Backup & Restore Dropbox - Version 1.1.1

Version Description

Download this release

Release Info

Developer backup-dropbox
Plugin Icon 128x128 Backup & Restore Dropbox
Version 1.1.1
Comparing to
See all releases

Version 1.1.1

Files changed (58) hide show
  1. class-wpadm-command.php +14 -0
  2. class-wpadm-core.php +263 -0
  3. class-wpadm-method-class.php +26 -0
  4. class-wpadm-result.php +117 -0
  5. commands/class-wpadm-command-archive.php +45 -0
  6. commands/class-wpadm-command-mysqldump.php +22 -0
  7. commands/class-wpadm-command-mysqloptimize.php +22 -0
  8. commands/class-wpadm-command-restore-backup.php +52 -0
  9. commands/class-wpadm-command-send-to-dropbox.php +45 -0
  10. commands/index.php +1 -0
  11. css/admin-style-wpadm.css +702 -0
  12. dropbox-backup.php +26 -0
  13. errorHandler.php +40 -0
  14. img/antivir.png +0 -0
  15. img/cloaud.png +0 -0
  16. img/content.png +0 -0
  17. img/icon.png +0 -0
  18. img/index.php +1 -0
  19. img/monitor.png +0 -0
  20. img/sheduler.png +0 -0
  21. img/spacer.gif +0 -0
  22. img/stats.png +0 -0
  23. img/wpadm.com_logo.2.png +0 -0
  24. index.php +1 -0
  25. methods/class-wpadm-method-backup-delete.php +28 -0
  26. methods/class-wpadm-method-backup-list.php +45 -0
  27. methods/class-wpadm-method-backup.php +451 -0
  28. methods/class-wpadm-method-full-backup-dropbox.php +512 -0
  29. methods/class-wpadm-method-local-backup.php +369 -0
  30. methods/class-wpadm-method-local-restore.php +142 -0
  31. methods/class-wpadm-method-ping.php +71 -0
  32. methods/class-wpadm-method-queue-controller.php +194 -0
  33. methods/class-wpadm-method-reconnect.php +15 -0
  34. methods/class-wpadm-method-send-to-dropbox.php +72 -0
  35. methods/class-wpadm-method-update.php +93 -0
  36. methods/index.php +1 -0
  37. modules/OAuthSimple.php +532 -0
  38. modules/class-wpadm-archive.php +42 -0
  39. modules/class-wpadm-command-context.php +28 -0
  40. modules/class-wpadm-command-factory.php +34 -0
  41. modules/class-wpadm-mysqldump.php +251 -0
  42. modules/class-wpadm-queue.php +151 -0
  43. modules/dropbox.class.php +512 -0
  44. modules/index.php +1 -0
  45. modules/pclzip.lib.php +3034 -0
  46. modules/phpseclib/Crypt/AES.php +540 -0
  47. modules/phpseclib/Crypt/Blowfish.php +1468 -0
  48. modules/phpseclib/Crypt/DES.php +2536 -0
  49. modules/phpseclib/Crypt/Hash.php +823 -0
  50. modules/phpseclib/Crypt/RC4.php +492 -0
  51. modules/phpseclib/Crypt/RSA.php +2693 -0
  52. modules/phpseclib/Crypt/Random.php +249 -0
  53. modules/phpseclib/Crypt/Rijndael.php +2062 -0
  54. modules/phpseclib/Crypt/TripleDES.php +842 -0
  55. modules/phpseclib/Crypt/Twofish.php +1664 -0
  56. modules/phpseclib/File/ANSI.php +560 -0
  57. modules/phpseclib/File/ASN1.php +1293 -0
  58. modules/phpseclib/File/X509.php +3136 -0
class-wpadm-command.php ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Class WPAdm_Сommand
4
+ */
5
+ if (!class_exists('WPAdm_Сommand')) {
6
+ abstract class WPAdm_Сommand {
7
+ /**
8
+ * @param WPAdm_Command_Context $context
9
+ * @return boolean
10
+ */
11
+ abstract function execute(WPAdm_Command_Context $context);
12
+
13
+ }
14
+ }
class-wpadm-core.php ADDED
@@ -0,0 +1,263 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once dirname(__FILE__) . '/class-wpadm-result.php';
3
+ require_once dirname(__FILE__) . '/class-wpadm-command.php';
4
+ require_once dirname(__FILE__) . '/modules/class-wpadm-command-context.php';
5
+ require_once dirname(__FILE__) . '/modules/class-wpadm-queue.php';
6
+ require_once dirname(__FILE__) . '/modules/class-wpadm-command-factory.php';
7
+
8
+
9
+ if (!class_exists('WPAdm_Core')) {
10
+ class WPAdm_Core {
11
+
12
+ /*
13
+ * "прилетевший" POST-запрос от админки($_POST)
14
+ * @var array
15
+ */
16
+ private $request = array();
17
+
18
+ /*
19
+ * публичный ключ для проверки подписи
20
+ * @var string
21
+ */
22
+ private $pub_key;
23
+
24
+ /*
25
+ * Результат выполнения запроса
26
+ * @var WPAdm_Result
27
+ */
28
+ private $result;
29
+
30
+ private $plugin;
31
+
32
+ public static $pl_dir;
33
+
34
+ public static $plugin_name;
35
+
36
+
37
+ public function __construct(array $request, $plugin = '', $plugin_dir = '') {
38
+ $this->result = new WPAdm_Result();
39
+ $this->result->setResult(WPAdm_Result::WPADM_RESULT_ERROR);
40
+ $this->request = $request;
41
+ $this->plugin = $plugin;
42
+ self::$pl_dir = $plugin_dir;
43
+ self::$plugin_name = $plugin;
44
+ // авторизация запроса
45
+ if (!$this->auth()) {
46
+ return;
47
+ };
48
+ if ('connect' == $request['method']) {
49
+ $this->connect();
50
+ } elseif ('local' == $request['method']){
51
+
52
+ } elseif($obj = $this->getObject($request['method'], $request['params'])) {
53
+ if (isset($obj->name)) {
54
+ $this->name = $obj->name;
55
+ }
56
+ if (isset($obj->time)) {
57
+ $this->time = $obj->time;
58
+ }
59
+ $this->result = $obj->getResult();
60
+ } else {
61
+ $this->result->setError('Unknown method "' . $request['method'] . '"');
62
+ }
63
+ }
64
+
65
+
66
+ /**
67
+ * Возвращает путь до папки временных файлов
68
+ * @return string
69
+ */
70
+ static public function getTmpDir() {
71
+ $tmp_dir = self::$pl_dir . '/tmp';
72
+ self::mkdir($tmp_dir);
73
+ if (!file_exists($tmp_dir . '/index.php')) {
74
+ file_put_contents($tmp_dir . '/index.php', '');
75
+ }
76
+ return $tmp_dir;
77
+ }
78
+
79
+ /**
80
+ * Возвращает путь до папки временных файлов
81
+ * @return string
82
+ */
83
+ static public function getPluginDir() {
84
+ return self::$pl_dir;
85
+ }
86
+
87
+ /**
88
+ * @param string $method
89
+ * @param mixed $params
90
+ * @return null|WPAdm_Method_Class
91
+ */
92
+ private function getObject($method, $params) {
93
+ if (!preg_match("|[a-zA-Z0-9_]|", $method)) {
94
+ return null;
95
+ }
96
+ $method = mb_strtolower($method);
97
+
98
+ $class_file = self::$pl_dir . "/methods/class-wpadm-method-" . str_replace('_', '-', $method) . ".php";
99
+
100
+ if (file_exists($class_file)) {
101
+ require_once $class_file;
102
+ $tmp = explode('_', str_replace('-', '_', $method));
103
+ foreach($tmp as $k=>$m) {
104
+ $tmp[$k] = ucfirst(strtolower($m));
105
+ }
106
+ $method = implode('_', $tmp);
107
+
108
+ $class_name = "WPAdm_Method_{$method}";
109
+ if (!class_exists($class_name)) {
110
+ $this->getResult()->setError("Class '$class_name' not found");
111
+ $this->getResult()->setResult(WPAdm_result::WPADM_RESULT_ERROR);
112
+ return null;
113
+ }
114
+ return new $class_name($params);
115
+ }
116
+ return null;
117
+
118
+ }
119
+
120
+ public static function getLog()
121
+ {
122
+ $file_log = self::getTmpDir() . '/log.log';
123
+ if (file_exists($file_log)) {
124
+ return @file_get_contents($file_log);
125
+ }
126
+ return "";
127
+ }
128
+
129
+ private function connect() {
130
+
131
+ add_option('wpadm_pub_key', $this->pub_key);
132
+ $this->result->setResult(WPAdm_Result::WPADM_RESULT_SUCCESS);
133
+
134
+ $sendData['system_data'] = get_system_data();
135
+ $data['actApi'] = 'setStats';
136
+ $data['site'] = get_option('siteurl');
137
+ $data['data'] = wpadm_pack($sendData);
138
+ if (!class_exists('WP_Http')) {
139
+ include_once ABSPATH.WPINC.'/class-http.php';
140
+ }
141
+
142
+ $remote = array();
143
+ $remote['body'] = $data;
144
+ $remote['timeout'] = 20;
145
+
146
+ $result = wp_remote_post(WPADM_URL_BASE, $remote);
147
+ }
148
+ public static function setPluginDIr($dir)
149
+ {
150
+ self::$pl_dir = $dir;
151
+ }
152
+
153
+ /*
154
+ * Авторизация запроса
155
+ */
156
+ private function auth() {
157
+ $this->pub_key = get_option('wpadm_pub_key');
158
+ if ('local_backup' == $this->request['method'] || 'local_restore' == $this->request['method'] || 'queue_controller' == $this->request['method'] || 'local' == $this->request['method']) {
159
+ return true;
160
+ }
161
+ if (empty($this->pub_key)) {
162
+ if ('connect' == $this->request['method']) {
163
+ $this->pub_key = $this->request['params']['pub_key'];
164
+ } else {
165
+ $this->getResult()->setError('Активируйте сайт на wpadm.com для работы плагинов.');
166
+ return false;
167
+ }
168
+ } elseif ('connect' == $this->request['method']) {
169
+ if( $this->pub_key != $this->request['params']['pub_key'] ){
170
+ $this->getResult()->setError('Ошибка. Воспользуйтесь переподключением плагина.');
171
+ return false;
172
+ }
173
+ } elseif('queue_controller' == $this->request['method']) {
174
+ //todo: проверить, что запустили сами себя
175
+ return true;
176
+
177
+ }
178
+
179
+ $sign = md5(serialize($this->request['params']));
180
+ //openssl_public_decrypt($this->request['sign'], $request_sign, $this->pub_key);
181
+ $ret = $this->verifySignature($this->request['sign'], $this->request['sign2'], $this->pub_key, $sign);
182
+
183
+
184
+ //$ret = ($sign == $request_sign);
185
+ if (!$ret) {
186
+ $this->getResult()->setError("Неверная подпись");
187
+ }
188
+ return $ret;
189
+ }
190
+
191
+
192
+ /**
193
+ * Создаем папку
194
+ * @param $dir
195
+ */
196
+ static public function mkdir($dir) {
197
+ if(!file_exists($dir)) {
198
+ mkdir($dir, 0755);
199
+ //todo: права доступа
200
+ file_put_contents($dir . '/index.php', '');
201
+ }
202
+ }
203
+
204
+ /**
205
+ * @return WPAdm_result result
206
+ */
207
+ public function getResult() {
208
+ return $this->result;
209
+ }
210
+
211
+
212
+ public function verifySignature($sign, $sign2, $pub_key, $text) {
213
+ if (function_exists('openssl_public_decrypt')) {
214
+ openssl_public_decrypt($sign, $request_sign, $pub_key);
215
+ $ret = ($text == $request_sign);
216
+ return $ret;
217
+ } else {
218
+ set_include_path(get_include_path() . PATH_SEPARATOR . self::getPluginDir() . '/modules/phpseclib');
219
+ require_once 'Crypt/RSA.php';
220
+ $rsa = new Crypt_RSA();
221
+ $rsa->loadKey($pub_key);
222
+ $ret = $rsa->verify($text, $sign2);
223
+ return $ret;
224
+ }
225
+ }
226
+
227
+ /**
228
+ * @param $sign
229
+ * @param $request_sign
230
+ * @param $pub_key
231
+ */
232
+ public function openssl_public_decrypt($sign, &$request_sign, $pub_key) {
233
+ //openssl_public_decrypt($sign, $request_sign, $pub_key);
234
+
235
+ }
236
+
237
+
238
+ static public function log($txt, $class='') {
239
+ $log_file = self::getTmpDir() . '/log.log';
240
+ file_put_contents($log_file, date("Y-m-d H:i:s") ."\t{$class}\t{$txt}\n", FILE_APPEND);
241
+ }
242
+
243
+ /**
244
+ * Удаляет директорию со всем содержимым
245
+ * @param $dir
246
+ */
247
+ static function rmdir($dir) {
248
+ if (is_dir($dir)) {
249
+ $files = glob($dir. '/*');
250
+ foreach($files as $f) {
251
+ if ($f == '..' or $f == '.') {
252
+ continue;
253
+ }
254
+ if (is_dir($f)) {
255
+ self::rmdir($f);
256
+ }
257
+ unlink($f);
258
+ }
259
+ rmdir($dir);
260
+ }
261
+ }
262
+ }
263
+ }
class-wpadm-method-class.php ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+
4
+ if (!class_exists('WPAdm_Method_Class')) {
5
+ abstract class WPAdm_Method_Class {
6
+ /**
7
+ * @var mixed
8
+ */
9
+ protected $params;
10
+
11
+ /**
12
+ * @var WPAdm_result
13
+ */
14
+ protected $result;
15
+
16
+ /**
17
+ * @param mixed $params
18
+ */
19
+ public function __construct($params) {
20
+ $this->params = $params;
21
+ $this->result = new WPAdm_Result();
22
+ }
23
+
24
+ abstract function getResult();
25
+ }
26
+ }
class-wpadm-result.php ADDED
@@ -0,0 +1,117 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if (!class_exists('WPAdm_Result')) {
3
+ class WPAdm_Result {
4
+ /*
5
+ * Status of the request.
6
+ * Can be either a "success" - the request is successful,
7
+ * or "error" - in an error was encountered
8
+ * @var string
9
+ */
10
+ private $result;
11
+
12
+ /*
13
+ * Text of the error that occurred during query execution
14
+ * @var string
15
+ */
16
+ private $error = '';
17
+
18
+ /*
19
+ * Data obtained during query execution
20
+ * @var mixed
21
+ */
22
+ private $data;
23
+
24
+ /*
25
+ * Total size of backup
26
+ */
27
+ private $size;
28
+
29
+ const WPADM_RESULT_SUCCESS = 'success';
30
+ const WPADM_RESULT_ERROR = 'error';
31
+
32
+ public function __construct() {
33
+ $this->result = WPAdm_Result::WPADM_RESULT_ERROR;
34
+ }
35
+
36
+ /**
37
+ * @param mixed $data
38
+ */
39
+ public function setData($data)
40
+ {
41
+ $this->data = $data;
42
+ }
43
+
44
+ /**
45
+ * @return mixed
46
+ */
47
+ public function getData()
48
+ {
49
+ return $this->data;
50
+ }
51
+
52
+ /**
53
+ * @param string $error
54
+ */
55
+ public function setError($error)
56
+ {
57
+ WPAdm_Core::log($error);
58
+ $this->error = $error;
59
+ }
60
+
61
+ /**
62
+ * @return string
63
+ */
64
+ public function getError()
65
+ {
66
+ return $this->error;
67
+ }
68
+
69
+ /**
70
+ * @param int $size
71
+ */
72
+ public function setSize($size)
73
+ {
74
+ $this->size = $size;
75
+ }
76
+
77
+ /**
78
+ * @return int
79
+ */
80
+ public function getSize()
81
+ {
82
+ return $this->size;
83
+ }
84
+
85
+ /**
86
+ * @param string $result
87
+ */
88
+ public function setResult($result)
89
+ {
90
+ $this->result = $result;
91
+ }
92
+
93
+ /**
94
+ * @return string
95
+ */
96
+ public function getResult()
97
+ {
98
+ return $this->result;
99
+ }
100
+
101
+ public function exchangeArray(array $a) {
102
+ $this->result = (isset($a['result'])) ? $a['result'] : '';
103
+ $this->data = (isset($a['data'])) ? $a['data'] : '';
104
+ $this->error = (isset($a['error'])) ? $a['error'] : '';
105
+ $this->size = (isset($a['size'])) ? $a['size'] : '';
106
+ }
107
+
108
+ public function toArray() {
109
+ return array(
110
+ 'result' => $this->getResult(),
111
+ 'error' => $this->getError(),
112
+ 'data' => $this->getData(),
113
+ 'size' => $this->getSize()
114
+ );
115
+ }
116
+ }
117
+ }
commands/class-wpadm-command-archive.php ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+
4
+ class WPadm_Command_Archive extends WPAdm_Сommand{
5
+ public function execute(WPAdm_Command_Context $context)
6
+ {
7
+ require_once WPAdm_Core::getPluginDir() . '/modules/class-wpadm-archive.php';
8
+ $af = $this->getArchiveName($context->get('to_file'));
9
+ $archive = new WPAdm_Archive($af, $context->get('to_file') . '.md5');
10
+ $archive->setRemovePath($context->get('remove_path'));
11
+ $files = $context->get('files');
12
+
13
+ // если привышен максимальный размер архива, создадим новый
14
+ if (file_exists($af) && filesize($af) > $context->get('max_file_size')) {
15
+ //WPAdm_Core::log(filesize($af) . ', max=' . $context->get('max_file_size'));
16
+ $af = $this->getNextArchiveName($context->get('to_file'));
17
+ unset($archive);
18
+ $archive = new WPAdm_Archive($af, $context->get('to_file') . '.md5');
19
+ $archive->setRemovePath($context->get('remove_path'));
20
+ }
21
+ //WPAdm_Core::log('Add to archive ' . $af);
22
+ $archive->add(implode(',', $files));
23
+ return true;
24
+ }
25
+
26
+ private function getArchiveName($name)
27
+ {
28
+ $archives = glob("{$name}-*.zip");
29
+ if (empty($archives)) {
30
+ return "{$name}-1.zip";
31
+ }
32
+ $n = count($archives);
33
+ $f = "{$name}-{$n}.zip";
34
+ //$f = array_pop($archives);
35
+ return $f;
36
+ }
37
+
38
+ private function getNextArchiveName($name)
39
+ {
40
+ $arhives = glob("{$name}-*.zip");
41
+ $n = 1 + count($arhives);
42
+ $a = "{$name}-{$n}.zip";
43
+ return $a;
44
+ }
45
+ }
commands/class-wpadm-command-mysqldump.php ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if (!class_exists('WPadm_Command_Mysqldump')) {
3
+ class WPadm_Command_Mysqldump extends WPAdm_Сommand{
4
+ public function execute(WPAdm_Command_Context $context)
5
+ {
6
+ //WPAdm_Core::log(print_r($context, true));
7
+ require_once WPAdm_Core::getPluginDir() . '/modules/class-wpadm-mysqldump.php';
8
+ $mysqldump = new WPAdm_Mysqldump();
9
+ $mysqldump->host = $context->get('host');
10
+ $mysqldump->user = $context->get('user');
11
+ $mysqldump->password = $context->get('password');
12
+
13
+ try {
14
+ $mysqldump->mysqldump($context->get('db'), $context->get('to_file'));
15
+ } catch (Exception $e) {
16
+ $context->setError($e->getMessage());
17
+ return false;
18
+ }
19
+ return true;
20
+ }
21
+ }
22
+ }
commands/class-wpadm-command-mysqloptimize.php ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if (!class_exists('WPadm_Command_Mysqloptimize')) {
3
+ class WPadm_Command_Mysqloptimize extends WPAdm_Сommand{
4
+ public function execute(WPAdm_Command_Context $context)
5
+ {
6
+ //WPAdm_Core::log(print_r($context, true));
7
+ require_once WPAdm_Core::getPluginDir() . '/modules/class-wpadm-mysqldump.php';
8
+ $mysqldump = new WPAdm_Mysqldump();
9
+ $mysqldump->host = $context->get('host');
10
+ $mysqldump->user = $context->get('user');
11
+ $mysqldump->password = $context->get('password');
12
+
13
+ try {
14
+ $mysqldump->optimize($context->get('db'));
15
+ } catch (Exception $e) {
16
+ $context->setError($e->getMessage());
17
+ return false;
18
+ }
19
+ return true;
20
+ }
21
+ }
22
+ }
commands/class-wpadm-command-restore-backup.php ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if (!class_exists('WPadm_Command_Restore_Backup')) {
3
+ class WPadm_Command_Restore_Backup extends WPAdm_Сommand {
4
+
5
+ public function execute(WPAdm_Command_Context $context)
6
+ {
7
+ if( file_exists($context->get('zip_file')) ) {
8
+ require_once WPAdm_Core::getPluginDir() . '/modules/pclzip.lib.php';
9
+ $this->archive = new PclZip($context->get('zip_file'));
10
+ $file = $context->get('file');
11
+ $is_dump = $file && strpos($file, "mysqldump.sql");
12
+
13
+ WPAdm_Core::log( "Decompression Archive " . basename($context->get('zip_file')) );
14
+ if ($is_dump !== false) {
15
+ $inzip = str_replace(ABSPATH, "", $file);
16
+ $file_in_zip = $this->archive->extract(PCLZIP_OPT_BY_NAME, $inzip);
17
+ } else {
18
+ $file_in_zip = $this->archive->extract(PCLZIP_OPT_REPLACE_NEWER);
19
+ }
20
+
21
+ if ($file_in_zip == 0) {
22
+ WPAdm_Core::log( "ERROR Archived: " . $this->archive->errorInfo(true) );
23
+ $context->setError( "ERROR Archived: " . $this->archive->errorInfo(true));
24
+ return false;
25
+ }
26
+ //WPAdm_Core::log(print_r($file_in_zip, 1));
27
+ if ($is_dump !== false) {
28
+ $db_host = $context->get('db_host');
29
+ if ($db_host !== false) {
30
+ require_once WPAdm_Core::getPluginDir() . '/modules/class-wpadm-mysqldump.php';
31
+ $mysqldump = new WPAdm_Mysqldump();
32
+ $mysqldump->host = $context->get('db_host');
33
+ $mysqldump->user = $context->get('db_user');
34
+ $mysqldump->password = $context->get('db_password');
35
+ try {
36
+ $mysqldump->restore($context->get('db_name'), $file);
37
+ } catch (Exception $e) {
38
+ $context->setError($e->getMessage());
39
+ return false;
40
+ }
41
+ }
42
+ }
43
+
44
+ } else {
45
+ $context->setError("File Archive Not Exist " . $context->get('zip_file'));
46
+ WPAdm_Core::log( "File Archive Not Exist " . $context->get('zip_file') );
47
+ return false;
48
+ }
49
+ return true;
50
+ }
51
+ }
52
+ }
commands/class-wpadm-command-send-to-dropbox.php ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if (!class_exists('WPadm_Command_Send_To_Dropbox')) {
3
+
4
+ class WPadm_Command_Send_To_Dropbox extends WPAdm_Сommand {
5
+
6
+ public function execute(WPAdm_Command_Context $context)
7
+ {
8
+ @session_start();
9
+ require_once WPAdm_Core::getPluginDir() . '/modules/dropbox.class.php';
10
+
11
+ WPAdm_Core::log('Send Files to Dropbox');
12
+ $dropbox = new dropbox($context->get('key'), $context->get('secret'), $context->get('token'));
13
+
14
+ if (!$dropbox->isAuth()) {
15
+ $context->setError("Error auth in Dropbox");
16
+ return false;
17
+ }
18
+ $files = $context->get('files');
19
+
20
+ $file = explode("/", $files);
21
+ $file_name = array_pop($file);
22
+ $folder_project_temp = $context->get('folder_project');
23
+ $folder_project = "";
24
+ if (!empty($folder_project_temp)) {
25
+ $folder_project = $folder_project_temp . "/";
26
+ $dropbox->createDir($folder_project_temp );
27
+ $dropbox->createDir($folder_project . $context->get('folder') );
28
+ } else {
29
+ $dropbox->createDir($context->get('folder') );
30
+ }
31
+
32
+ $fromFile = str_replace('//', '/', $files);
33
+ $toFile = str_replace('//', '/', $folder_project . $context->get('folder') . '/' . $file_name);
34
+ $res = $dropbox->uploadFile($fromFile, $toFile);
35
+ if (isset($res['error']) && isset($res['text']) && $res['error'] == 1) {
36
+ $context->setError("Dropbox error: " . $res['text']);
37
+ return false;
38
+ }
39
+ if (isset($res['size']) && isset($res['client_mtime'])) {
40
+ WPAdm_Core::log("file upload: " . $files . " size: " . $res['size']);
41
+ }
42
+ return true;
43
+ }
44
+ }
45
+ }
commands/index.php ADDED
@@ -0,0 +1 @@
 
1
+ <?php
css/admin-style-wpadm.css ADDED
@@ -0,0 +1,702 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ .wpadm-notice {
3
+ background: #fff;
4
+ border-left: 4px solid #dd3d36;
5
+ box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.1);
6
+ font-size: 16px;
7
+ overflow: hidden;
8
+ position: relative;
9
+ text-align: left;
10
+ clear: both;
11
+ height: 60px;
12
+ margin-top: 15px;
13
+ width: 95%;
14
+ }
15
+ .button-link {
16
+ background:none!important;
17
+ border:none;
18
+ padding:0!important;
19
+ font: inherit;
20
+ color:#0074a2;
21
+ border-bottom:1px solid #0074a2;
22
+ padding-bottom: 1px;
23
+ cursor: pointer;
24
+ line-height: 15px;
25
+ }
26
+ .button-link:hover {
27
+ color:#2ea2cc;
28
+ border-bottom:1px solid #2ea2cc;
29
+ }
30
+ .wpadm-notice div.registr {
31
+ margin-top : 20px;
32
+ font-size: 16px;
33
+ margin-left: 15px;
34
+ }
35
+
36
+ .form-counter {
37
+ background: #0096d6;
38
+ border: 1px solid #fff;
39
+ width: 95%;
40
+ margin-bottom: 20px;
41
+ margin-top: 20px;
42
+ color:#fff;
43
+ }
44
+
45
+ .form-counter table tr td{
46
+ padding: 10px;
47
+ }
48
+ .color-picker {
49
+ margin:10px;
50
+ }
51
+ .stat_title {
52
+ text-align: center;
53
+ font-size: 24px;
54
+ margin-top: 20px;
55
+ }
56
+ .cfTabsContainer {
57
+ background-color: #0096d6;
58
+ overflow: hidden;
59
+ width:95%;
60
+ padding: 15px;
61
+ margin-bottom: 40px;
62
+ margin-top: 30px;
63
+ -webkit-font-smoothing: antialiased;
64
+ }
65
+
66
+
67
+ .button-wpadm {
68
+ background: none repeat scroll 0 0 #00d2b8;
69
+ border-color: #cdcdcd;
70
+ box-shadow: 0 1px 0 #00d2b8 inset, 0 1px 0 rgba(0, 0, 0, 0.08);
71
+ color: #fff;
72
+ vertical-align: top;
73
+ border-radius: 3px;
74
+ border-style: solid;
75
+ border-width: 1px;
76
+ box-sizing: border-box;
77
+ cursor: pointer;
78
+ display: inline-block;
79
+ font-size: 13px;
80
+ height: 28px;
81
+ line-height: 26px;
82
+ margin: 0;
83
+ padding: 0 10px 1px;
84
+ text-decoration: none;
85
+ white-space: nowrap;
86
+ }
87
+ .wpadm-info {
88
+ font-size: 15px;
89
+ width: 30%;
90
+ margin-top:10px;
91
+ margin-left: 20px;
92
+ margin-bottom: 20px;
93
+ border-left: 1px solid #fff;
94
+ padding-left:20px;
95
+ padding-top: 20px;
96
+ height:200px;
97
+ }
98
+ .wpadm-info-title {
99
+ text-align:center;
100
+ padding:5px;
101
+ color:#fff;
102
+ font-size:20px;
103
+ }
104
+ .wpadm-registr-info {
105
+ width: 65%;
106
+ }
107
+ .wpadm-registr-info label {
108
+ color:#fff;
109
+ }
110
+ .wpadm-plugins-info {
111
+ width: 95%;
112
+ }
113
+ .services-info {
114
+ background: #fff; width: 95%; margin-top: 20px;
115
+ }
116
+ .title-services {
117
+ text-align: center; font-size: 20px; font-weight: 800; padding-bottom: 30px; padding-top: 20px;
118
+ }
119
+
120
+ .tmpl_line_body {
121
+ float: left;
122
+ margin: 0;
123
+ padding: 0;
124
+ position: relative;
125
+ width: 100%;
126
+ }
127
+ .wpadm-info-auth {
128
+ font-size: 11px;
129
+ padding-left:20px;
130
+ height:30px;
131
+ color:#fff;
132
+ margin-top: -5px;
133
+ }
134
+ #header_navigation_line {
135
+ background-color: #21759b;
136
+ background-image: linear-gradient(to bottom, #2a95c5, #21759b);
137
+ box-shadow: 0 2px 7px 2px rgba(50, 50, 50, 0.5);
138
+ height: 68px;
139
+ left: 0;
140
+ top: 0;
141
+ z-index: 1000;
142
+ }
143
+ #header_navigation_line #main_menu ul li {
144
+ display: inline-block;
145
+ float: none;
146
+ font-size: 14px;
147
+ font-weight: bold;
148
+ list-style: outside none none;
149
+ margin: 0;
150
+ padding: 0;
151
+ text-shadow: 0 1px 0 rgba(0, 0, 0, 0.1);
152
+ }
153
+ .inline {
154
+ float:left;
155
+ margin-top:10px;
156
+ margin-left:10px;
157
+ }
158
+ #header_navigation_line #main_menu ul li a {
159
+ background: -moz-linear-gradient(center top , #2e9ed2 5%, #21749b 100%) repeat scroll 0 0 #2e9ed2;
160
+ border: 1px solid #1b5f7f;
161
+ border-radius: 3px;
162
+ box-shadow: 1px 1px 0 0 #78c9e6 inset;
163
+ color: #dddddd;
164
+ display: inline-block;
165
+ float: left;
166
+ height: 43px;
167
+ line-height: 16px;
168
+ margin: 0 2px 0 0;
169
+ overflow: hidden;
170
+ padding: 5px 0;
171
+ text-decoration: none;
172
+ width: 90px;
173
+ }
174
+ #header_navigation_line #main_menu ul li:hover a {
175
+ background-image: linear-gradient(to bottom, #2fb1e5, #22759c);
176
+ color: #fff;
177
+ }
178
+ #header_navigation_line #main_menu {
179
+ float: left;
180
+ margin: 6px 0 0;
181
+ width: 100%;
182
+ }
183
+ #header_navigation_line #logo {
184
+ float: left;
185
+ left: 0;
186
+ position: absolute;
187
+ top: 9px;
188
+ width: auto;
189
+ }
190
+ #header_navigation_line #main_menu ul {
191
+ float: left;
192
+ list-style: outside none none;
193
+ margin: 0 0 0 20px;
194
+ padding: 0;
195
+ text-align: center;
196
+ width: 100%;
197
+ }
198
+ #header_navigation_line #main_menu ul li .nav_icon {
199
+ float: left;
200
+ height: 24px;
201
+ margin: 0;
202
+ padding: 0 0 3px;
203
+ width: 100%;
204
+ }
205
+ #header_navigation_line #main_menu ul li.active a, #header_navigation_line #main_menu ul li a:active {
206
+ background-image: linear-gradient(to bottom, #2cc4f5, #228bb4);
207
+ border: 1px solid #fff;
208
+ box-shadow: 0 1px 0 rgba(95, 157, 186, 0.6);
209
+ color: #fff;
210
+ }
211
+ .clear {
212
+ clear:both;
213
+ }
214
+ .plugins-info {
215
+ width:320px;
216
+ }
217
+ .plugin-box {
218
+ background: #0096d6;
219
+ border: 1px solid #e5e5e5;
220
+ box-shadow: 0 1px 1px rgba(0, 0, 0, 0.04);
221
+ min-width: 255px;
222
+ position: relative;
223
+ line-height: 1;
224
+ margin-bottom: 20px;
225
+ padding: 0;
226
+ }
227
+
228
+ .plugins-info-content {
229
+ display:none;
230
+ border-top: 1px solid #fff;
231
+ margin-top:8px;
232
+ padding-top: 7px;
233
+ }
234
+ h3.plugins-title {
235
+ font-size: 14px;
236
+ line-height: 1.4;
237
+ margin: 0;
238
+ }
239
+ .plugins-title a {
240
+ color:#fff;
241
+ text-decoration: none;
242
+
243
+ }
244
+ .wpadm-registr-info, .wpadm-info, .wpadm-info-auth {
245
+ float:left;
246
+ color:#fff;
247
+ }
248
+ .button-wpadm:hover {
249
+ border-color:#cdcdcd;
250
+ background-color: #009583;
251
+ }
252
+ .wpadm-red:hover {
253
+ border-color:#737373 ;
254
+ background-color: #ff706c;
255
+ }
256
+ .wpadm-red {
257
+ background: none repeat scroll 0 0 #f21111;
258
+ border-color: #c7c6ce;
259
+ box-shadow: 0 1px 0 #ff2c26 inset, 0 1px 0 rgba(0, 0, 0, 0.08);
260
+ }
261
+ .info-detail {
262
+ background:#bee7e7;
263
+ }
264
+ .table {
265
+ margin:0px;padding:0px;
266
+ width:100%;
267
+ border:0px;
268
+ border-collapse: collapse;
269
+ border-spacing: 0;
270
+ width:100%;
271
+ height:100%;
272
+ border: 1px solid #b7c6ff;
273
+ border-radius: 3px;
274
+ margin-top: 60px;
275
+
276
+ }
277
+ .table th {
278
+ padding: 7px;
279
+ background-color:#dde4ff;
280
+ font-size:16px;
281
+
282
+ }
283
+ .table td {
284
+ background: #fff;
285
+ font-size: 14px;
286
+ padding: 5px 0;
287
+ border-bottom:1px solid #b7c6ff;
288
+ text-align: center;
289
+ }
290
+ .info-path td {
291
+ font-size: 11px;
292
+ padding:0px;
293
+ }
294
+ .table tr:last td {
295
+
296
+ border-bottom: 0px;
297
+ }
298
+ .header-table {
299
+ font-size:20px;
300
+ }
301
+
302
+ .stat {
303
+ width: 200px;
304
+ }
305
+
306
+ .w1{
307
+ width:5%;
308
+ }
309
+ .w2{
310
+ width:13%;
311
+ }
312
+ .w3{
313
+ width:7%;
314
+ }
315
+ .table-stat-moovdiv {
316
+ background: none repeat scroll 0 0 #FFFFFF;
317
+ border-spacing: 0;
318
+ box-shadow: 0 4px 4px rgba(0, 0, 0, 0.3);
319
+ left: 0px;
320
+ margin-top: 0;
321
+ padding: 10px 15px;
322
+ top: 0px;
323
+ width: 400px;
324
+ }
325
+
326
+ .table-stat-moovdiv tr td{
327
+ border-right: 0px;
328
+ margin-bottom: 1px;
329
+ margin-top: 1px;
330
+ padding-bottom: 1px;
331
+ padding-top: 1px;
332
+ border-bottom:1px solid #D6D6D6;
333
+ padding: 5px;
334
+ }
335
+
336
+ #page_item {
337
+ margin-bottom:3px;
338
+ float:left;
339
+ }
340
+ .block-export {
341
+ float: right;
342
+ margin-right: 20px;
343
+ }
344
+ .info {
345
+ width: 70%;
346
+ border: 0;
347
+ }
348
+ .info tr {
349
+ border-style: hidden;
350
+ }
351
+ .info tr td{
352
+ border-style: hidden;
353
+ padding: 5px;
354
+ text-align:left;
355
+ }
356
+ .chart-box {
357
+ background: #fff;
358
+ border:1px solid #cccccc;
359
+ border-radius:3px;
360
+ margin-top:25px;
361
+ }
362
+ .chart-box-title {
363
+ color:#575757;
364
+ border-bottom: 1px solid #cccccc;
365
+ font-size: 18px;
366
+ padding:10px;
367
+ }
368
+ .charts {
369
+ padding:5px;
370
+ padding-top: 15px;
371
+ }
372
+ .form-account {
373
+ margin-top: 30px;
374
+ margin-bottom : 40px;
375
+ border:5px solid #fff;
376
+ background: #ffffa5;
377
+ padding: 10px;
378
+ height: auto;
379
+ overflow:hidden;
380
+ }
381
+ .form-account-title {
382
+ margin-bottom: 20px;
383
+ font-size: 22px;
384
+ }
385
+ .form-account-block {
386
+ margin-left: 20px;
387
+ float:left;
388
+ width: 40%;
389
+ }
390
+ .form-account-login {
391
+ margin-top: 10px;
392
+ margin-bottom : 40px;
393
+ border:5px solid #fff;
394
+ background: #ffffa5;
395
+ padding: 3px;
396
+ height: auto;
397
+ overflow:hidden;
398
+ }
399
+
400
+ .form-account-block-login {
401
+ margin-left: 10px;
402
+ width: 90%;
403
+
404
+ }
405
+ .form-account-info {
406
+ float:left;
407
+ width: 50%;
408
+ margin-left: 20px;
409
+ }
410
+ .b_2 {
411
+ background: url("button_ok.png") no-repeat scroll 0 0 rgba(0, 0, 0, 0);
412
+ color: #464646;
413
+ font-family: Arial,Helvetica,sans-serif;
414
+ font-size: 18px;
415
+ left: 12px;
416
+ padding-left: 30px;
417
+ top: 60px;
418
+ padding-top: 4px;
419
+ padding-bottom : 5px;
420
+ }
421
+ .b-3 {
422
+ font-size: 22px;
423
+ }
424
+ .form-account-button {
425
+ margin-top: 21px;
426
+ }
427
+ .label-form {
428
+ margin-left: 6px;
429
+ font-size: 16px;
430
+ }
431
+ .last {
432
+ line-height: 18px;
433
+ margin-top: 9px;
434
+ }
435
+ .progress {
436
+ height: 20px;
437
+ background: #ebebeb;
438
+ border-left: 1px solid transparent;
439
+ border-right: 1px solid transparent;
440
+ border-radius: 10px;
441
+ }
442
+ .progress > span {
443
+ position: relative;
444
+ float: left;
445
+ margin: 0 -1px;
446
+ min-width: 30px;
447
+ height: 18px;
448
+ line-height: 16px;
449
+ text-align: right;
450
+ background: #cccccc;
451
+ border: 1px solid;
452
+ border-color: #bfbfbf #b3b3b3 #9e9e9e;
453
+ border-radius: 10px;
454
+ background-image: -webkit-linear-gradient(top, #f0f0f0, #dbdbdb 70%, #cccccc);
455
+ background-image: -moz-linear-gradient(top, #f0f0f0, #dbdbdb 70%, #cccccc);
456
+ background-image: -o-linear-gradient(top, #f0f0f0, #dbdbdb 70%, #cccccc);
457
+ background-image: linear-gradient(to bottom, #f0f0f0, #dbdbdb 70%, #cccccc);
458
+ -webkit-box-shadow: inset 0 1px rgba(255, 255, 255, 0.3), 0 1px 2px rgba(0, 0, 0, 0.2);
459
+ box-shadow: inset 0 1px rgba(255, 255, 255, 0.3), 0 1px 2px rgba(0, 0, 0, 0.2);
460
+ }
461
+ .progress > span > span {
462
+ padding: 0 8px;
463
+ font-size: 11px;
464
+ font-weight: bold;
465
+ color: #404040;
466
+ color: rgba(0, 0, 0, 0.7);
467
+ text-shadow: 0 1px rgba(255, 255, 255, 0.4);
468
+ }
469
+ .progress > span:before {
470
+ content: '';
471
+ position: absolute;
472
+ top: 0;
473
+ bottom: 0;
474
+ left: 0;
475
+ right: 0;
476
+ z-index: 1;
477
+ height: 18px;
478
+ border-radius: 10px;
479
+ }
480
+
481
+
482
+
483
+ .stat-form-counter {
484
+ background: none repeat scroll 0 0 #0096d6;
485
+ color: #fff;
486
+ margin-bottom: 20px;
487
+ width: 46%;
488
+ margin-right: 0;
489
+ border: 0;
490
+ padding: 3px;
491
+ }
492
+ .stat-wpadm-registr-info {
493
+ color: #fff;
494
+ float: left;
495
+ width: 57%;
496
+ }
497
+ .stat-wpadm-registr-info label {
498
+ color:#fff;
499
+ }
500
+ .stat-wpadm-info-title {
501
+ color: #fff;
502
+ font-size: 20px;
503
+ padding :20px 0px;
504
+ margin-top:10px;
505
+ text-align: center;
506
+ }
507
+ .stat-table-registr {
508
+ margin-top: 20px;
509
+ }
510
+ .stat-table-registr th, .stat-table-registr td {
511
+ padding:5px;
512
+ }
513
+ .stat-wpadm-info {
514
+ width: 37%; margin-left: 9px; height:100%; padding-top: 0px; margin-top:20px;
515
+ color: #fff;
516
+ float: left;
517
+ border-left: 1px solid #fff;
518
+ font-size: 12px;
519
+ margin-bottom: 20px;
520
+ padding-left: 20px;
521
+ }
522
+ .block-button-show {
523
+ padding:11px 18px; cursor: pointer; text-align: center;
524
+ }
525
+ .block-button-show .block-click {
526
+ padding-top: 10px;
527
+ font-size: 16px;
528
+ border-top:1px solid #fff;
529
+ }
530
+ .stat-setting {
531
+ border-left:1px solid #fff;
532
+ margin-right: 0px;
533
+ }
534
+ #stat-title-setting{
535
+ font-size: 20px;
536
+ margin-top: 10px;
537
+ padding: 20px 0;
538
+ text-align: center;
539
+ }
540
+ #preview-image {
541
+ height: 105px; float: left; margin-right: 10px; margin-top:45px;
542
+ }
543
+ #preview-image .block-preview-image {
544
+ padding: 10px; border: 1px solid #fff; margin-left: 10px; margin-top:20px; width: 90px; text-align: center;
545
+ }
546
+ #preview-image .title-preveiw-image {
547
+ font-size: 16px; position: absolute;margin-top: -28px; margin-left: 7px;background: #0096d6; padding: 3px;
548
+ }
549
+ #preview-image .image-block {
550
+ display: table;
551
+ }
552
+ .image-block .image-block-in {
553
+ display: table-cell; vertical-align: middle;
554
+ }
555
+ .image-block-in img {
556
+ float: left;margin-top:7px;
557
+ margin-left: 2px;
558
+ }
559
+ .image-block-in .text-image-counter {
560
+ float: left;
561
+ padding-left:3px;
562
+ font-size: 8px;
563
+ font-weight: 600;
564
+ }
565
+ #setting-form .info-block {
566
+ float: left; margin: 5px 0px 0px; width:74%;
567
+ }
568
+ #setting-form .first-info-block {
569
+ margin: 20px 0px 0px;
570
+ }
571
+ .info-block-detail {
572
+ float:left;
573
+ }
574
+ .detail-title {
575
+ margin: 0 5px; width: 30%;
576
+ }
577
+ #setting-form .info-block .details-info {
578
+ width: auto;
579
+ font-size: 10px;
580
+ margin:0px;
581
+ }
582
+ #setting-form .info-block input[type="text"] {
583
+ font-size: 14px;
584
+ height: 28px;
585
+ }
586
+ .info-block .checkbox-info {
587
+ width:101px;
588
+ text-align:right;
589
+ }
590
+ .checkbox-info input[type="checkbox"] {
591
+ margin-right: 0px;
592
+ }
593
+ .stat-setting-save {
594
+ text-align: center; margin-top: 10px;
595
+ }
596
+
597
+ /*default style */
598
+ @media only screen and (max-width: 960px) {
599
+ /*
600
+ tablet computer
601
+ */
602
+ .stat-wpadm-info {
603
+ margin-left: 9px; height:100%; padding-top: 0px; margin-top:20px;
604
+ color: #fff;
605
+ float: none;
606
+ clear:both;
607
+ border-left: 0px;
608
+ border-top:1px solid #fff;
609
+ font-size: 10px;
610
+ margin-bottom: 10px;
611
+ padding-left: 0px;
612
+ width:88%;
613
+
614
+
615
+ }
616
+ .stat-table-registr th, .stat-table-registr td {
617
+ padding:2px;
618
+ font-size:10px;
619
+ }
620
+ .stat-table-registr {
621
+ margin-top: 10px;
622
+ float:none;
623
+ }
624
+ .form-table th {
625
+ line-height: 10px;
626
+ }
627
+ .stat-table-registr input {
628
+ font-size: 10px;
629
+ height: 20px;
630
+ line-height: 10px;
631
+ }
632
+ .stat-form-counter {
633
+ font-size:10px;
634
+ margin-right:5px;
635
+ }
636
+ #setting-form .info-block {
637
+ width:60%;
638
+ }
639
+ #preview-image {
640
+ height: 105px;
641
+ float: left;
642
+ margin-right: 10px;
643
+ }
644
+ .detail-title {
645
+ margin: 0 5px; width:auto;
646
+ }
647
+ #setting-form .info-block .details-info {
648
+ width: auto;
649
+ font-size: 8px;
650
+ float:none;
651
+ clear:both;
652
+ line-height: 8px;
653
+ margin-bottom:5px;
654
+
655
+ }
656
+ .info-block .checkbox-info {
657
+ width:28px;
658
+ }
659
+ #setting-form .info-block input[type="text"] {
660
+ font-size:12px;
661
+ height: 20px;
662
+ }
663
+ .minicolors-theme-default.minicolors-position-right .minicolors-input {
664
+ padding-right: 10px;
665
+ }
666
+
667
+ .minicolors-theme-default .minicolors-swatch {
668
+ height: 18px;
669
+ left: 5px;
670
+ top: 1px;
671
+ width: 18px;
672
+ }
673
+
674
+ }
675
+ @media only screen and (max-width: 1124px) {
676
+ .stat-form-counter {
677
+ font-size:10px;
678
+ margin-right:3.5%;
679
+ }
680
+ #setting-form .info-block {
681
+ width:55%;
682
+ }
683
+ #preview-image {
684
+ height: 105px;
685
+ float: left;
686
+ margin-right: 10px;
687
+ margin-top:40px;
688
+ }
689
+ .info-block input[type="text"] {
690
+ font-size:12px;
691
+ height: 20px;
692
+ }
693
+
694
+ }
695
+ @media only screen and (max-width: 758px) {
696
+ /*
697
+ vertical tablet computer
698
+ */
699
+ }
700
+ @media only screen and (max-width: 524px) {
701
+ /*phone*/
702
+ }
dropbox-backup.php ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Plugin Name: DropBox Backup
4
+ Description: DropBox Backup Plugin to create DropBox Full Backup (Files + Database) of your Web Page
5
+ Version: 1.1.1
6
+ */
7
+
8
+ require_once dirname(__FILE__) . DIRECTORY_SEPARATOR . 'wpadm.php';
9
+ if (file_exists(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'wpadm-class-wp.php')) {
10
+ require_once dirname(__FILE__) . DIRECTORY_SEPARATOR . 'wpadm-class-wp.php';
11
+ }
12
+
13
+ add_action('init', 'wpadm_full_backup_dropbox_run');
14
+
15
+ add_action('admin_print_scripts', 'wpadm_include_admins_script' );
16
+
17
+ add_action('admin_notices', 'wpadm_admin_notice');
18
+
19
+
20
+ if (!function_exists('wpadm_full_backup_dropbox_run')) {
21
+ function wpadm_full_backup_dropbox_run()
22
+ {
23
+ wpadm_run('dropbox-backup', dirname(__FILE__));
24
+ }
25
+ }
26
+
errorHandler.php ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if (!function_exists('myErrorHandler')) {
3
+ function myErrorHandler($errno, $errstr, $errfile, $errline)
4
+ {
5
+ if (!(error_reporting() & $errno)) {
6
+ return;
7
+ }
8
+
9
+ switch ($errno) {
10
+ case E_USER_ERROR:
11
+ myErrorHandlerEcho( " $errfile($errline)\t[$errno] $errstr", 'ERROR');
12
+ myErrorHandlerEcho( " Fatal error in line $errline file $errfile");
13
+ myErrorHandlerEcho( ", PHP " . PHP_VERSION . " (" . PHP_OS . ")");
14
+ exit(1);
15
+ break;
16
+
17
+ case E_USER_WARNING:
18
+ myErrorHandlerEcho( " $errfile($errline)\t[$errno] $errstr", 'WARNING');
19
+ break;
20
+
21
+ case E_USER_NOTICE:
22
+ myErrorHandlerEcho( " $errfile($errline)\t[$errno] $errstr", 'WARNING');
23
+ break;
24
+
25
+ default:
26
+ myErrorHandlerEcho( " $errfile($errline)\tUknown error: [$errno] $errstr");
27
+ break;
28
+ }
29
+
30
+ return true;
31
+ }
32
+ }
33
+
34
+ if (!function_exists('myErrorHandlerEcho')) {
35
+ function myErrorHandlerEcho($txt, $type = '') {
36
+ $dt = date("Y-m-d H:i:s");
37
+ file_put_contents(dirname(__FILE__) . '/error.log', $dt . "\t{$type}\n{$txt}\n\n", FILE_APPEND);
38
+ }
39
+ $old_error_handler = set_error_handler("myErrorHandler");
40
+ }
img/antivir.png ADDED
Binary file
img/cloaud.png ADDED
Binary file
img/content.png ADDED
Binary file
img/icon.png ADDED
Binary file
img/index.php ADDED
@@ -0,0 +1 @@
 
1
+ <?php
img/monitor.png ADDED
Binary file
img/sheduler.png ADDED
Binary file
img/spacer.gif ADDED
Binary file
img/stats.png ADDED
Binary file
img/wpadm.com_logo.2.png ADDED
Binary file
index.php ADDED
@@ -0,0 +1 @@
 
1
+ <?php
methods/class-wpadm-method-backup-delete.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Delete backup
4
+ * Class WPAdm_Method_Backup_Delete
5
+ */
6
+ if (!class_exists('WPAdm_Method_Backup_Delete')) {
7
+ class WPAdm_Method_Backup_Delete extends WPAdm_Method_Class {
8
+ public function getResult()
9
+ {
10
+ $backups_dir = realpath(ABSPATH . '/wpadm_backups/' . $this->params['name']);
11
+ if(strpos($backups_dir, DIRECTORY_SEPARATOR . 'wpadm_backups' . DIRECTORY_SEPARATOR) === false || !is_dir($backups_dir)) {
12
+ $this->result->setResult = WPAdm_result::WPADM_RESULT_ERROR;
13
+ $this->result->setError('Wrong name backup');
14
+ } else {
15
+ if (is_dir($backups_dir)) {
16
+ WPAdm_Core::rmdir($backups_dir);
17
+ if (!is_dir($backups_dir)) {
18
+ $this->result->setResult = WPAdm_result::WPADM_RESULT_SUCCESS;
19
+ } else {
20
+ $this->result->setResult = WPAdm_result::WPADM_RESULT_ERROR;
21
+ $this->result->setError('Failed to remove backup');
22
+ }
23
+ }
24
+ }
25
+ return $this->result;
26
+ }
27
+ }
28
+ }
methods/class-wpadm-method-backup-list.php ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Return a list of backups
4
+ * Class WPAdm_Method_Exec
5
+ */
6
+ if (!class_exists('WPAdm_Method_Backup_List')) {
7
+ class WPAdm_Method_Backup_List extends WPAdm_Method_Class {
8
+ public function getResult()
9
+ {
10
+ $backups_dir = ABSPATH . '/wpadm_backups/';
11
+ $dirs = glob($backups_dir . '*');
12
+
13
+ $backups = array();
14
+ foreach($dirs as $dir) {
15
+ if (preg_match("|(.*)\-(.*)\-(.*)|", $dir, $mm)) {
16
+ $tmp = explode('/', $dir);
17
+ $name = array_pop($tmp);
18
+ list($y,$m,$d, $h,$i) = explode('_', $mm[3]);
19
+ $dt = "$y-$m-$d $h:$i";
20
+ $backup = array(
21
+ 'name' => $name,
22
+ 'type' => $mm[2],
23
+ 'dt' => $dt,
24
+ );
25
+ $files = glob($dir . '/*.zip');
26
+ $size = 0;
27
+ foreach($files as $k=>$v) {
28
+ $size += (int)filesize($v);
29
+ $files[$k] = str_replace(ABSPATH, '', $v);
30
+ }
31
+ $backup['files'] = $files;
32
+ $backup['size'] = $size;
33
+ if ($size > 0) {
34
+ $backups[] = $backup;
35
+ }
36
+
37
+ }
38
+ }
39
+ $this->result->setData($backups);
40
+ $this->result->setResult(WPAdm_result::WPADM_RESULT_SUCCESS);
41
+ return $this->result;
42
+ }
43
+
44
+ }
45
+ }
methods/class-wpadm-method-backup.php ADDED
@@ -0,0 +1,451 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Бэкап сайта
4
+ * Class WPadm_Method_Backup
5
+ */
6
+ if (!class_exists('WPadm_Method_Backup')) {
7
+ class WPadm_Method_Backup extends WPAdm_Method_Class {
8
+ /**
9
+ * Уникальный идентификатор текущего объекта
10
+ * @var String
11
+ */
12
+ private $id;
13
+
14
+ /**
15
+ * Unixtimestamp, когда был запущен метод
16
+ * @var Int
17
+ */
18
+ private $stime;
19
+
20
+ /**
21
+ * @var WPAdm_Queue
22
+ */
23
+ private $queue;
24
+
25
+ /**
26
+ * @var string
27
+ */
28
+ private $dir;
29
+
30
+ /**
31
+ * @var string
32
+ */
33
+ private $tmp_dir;
34
+
35
+ /**
36
+ * Тип бэкапа
37
+ * @var string [full|db]
38
+ */
39
+ private $type = 'full';
40
+
41
+ private $name = '';
42
+
43
+ public function __construct($params) {
44
+ parent::__construct($params);
45
+ $this->init(
46
+ array(
47
+ 'id' => uniqid('wpadm_method_backup__'),
48
+ 'stime' => time(),
49
+ 'type' => $params['type'],
50
+ )
51
+ );
52
+
53
+
54
+ //папка для временных файлов
55
+ // $this->tmp_dir = WPAdm_Core::getTmpDir() . '/' . $this->id;
56
+ // WPAdm_Core::mkdir($this->tmp_dir);
57
+
58
+ $name = get_option('siteurl');
59
+
60
+ $name = str_replace("http://", '', $name);
61
+ $name = str_replace("https://", '', $name);
62
+ $name = preg_replace("|\W|", "_", $name);
63
+ $name .= '-' . $this->type . '-' . date("Y_m_d_H_i");
64
+ $this->name = $name;
65
+
66
+ // папка для бэкапа
67
+ $this->dir = ABSPATH . '/wpadm_backups/' . $this->name;
68
+ WPAdm_Core::mkdir(ABSPATH . '/wpadm_backups/');
69
+ WPAdm_Core::mkdir($this->dir);
70
+ }
71
+
72
+ public function getResult()
73
+ {
74
+ $errors = array();
75
+
76
+ $this->result->setResult(WPAdm_Result::WPADM_RESULT_SUCCESS);
77
+ $this->result->setError('');
78
+
79
+
80
+ #ОТЛАДКА, нужно удалить
81
+ //todo: удалить
82
+ unlink(dirname(__FILE__) . '/../tmp/log.log');
83
+ #конец отладки
84
+
85
+ WPAdm_Core::log('Начинаем бэкап');
86
+
87
+ # СОЗДАДИМ ДАМП БД
88
+ WPAdm_Core::log('Начинаем создание дампа БД');
89
+ // добавим в очередь создание бэкапа БД и выполним
90
+ WPAdm_Core::mkdir(ABSPATH . '/wpadm_backup');
91
+ $mysql_dump_file = ABSPATH . '/wpadm_backup/mysqldump.sql';
92
+ if (file_exists($mysql_dump_file)) {
93
+ unlink($mysql_dump_file);
94
+ }
95
+ $wp_mysql_params = $this->getWpMysqlParams();
96
+
97
+ if (isset($this->params['optimize']) && ($this->params['optimize']==1)) {
98
+ WPAdm_Core::log('Оптимизцация таблиц БД');
99
+ $commandContext = new WPAdm_Command_Context();
100
+ $commandContext ->addParam('command','mysqloptimize')
101
+ ->addParam('host', $wp_mysql_params['host'])
102
+ ->addParam('db', $wp_mysql_params['db'])
103
+ ->addParam('user', $wp_mysql_params['user'])
104
+ ->addParam('password', $wp_mysql_params['password']);
105
+ $this->queue->clear()
106
+ ->add($commandContext);
107
+ unset($commandContext);
108
+ }
109
+
110
+ $commandContext = new WPAdm_Command_Context();
111
+ $commandContext ->addParam('command','mysqldump')
112
+ ->addParam('host', $wp_mysql_params['host'])
113
+ ->addParam('db', $wp_mysql_params['db'])
114
+ ->addParam('user', $wp_mysql_params['user'])
115
+ ->addParam('password', $wp_mysql_params['password'])
116
+ ->addParam('tables', '')
117
+ ->addParam('to_file', $mysql_dump_file);
118
+ $res = $this->queue->add($commandContext)
119
+ ->save()
120
+ ->execute();
121
+
122
+ if (!$res) {
123
+ WPAdm_Core::log('Дамп БД не создан('.$this->queue->getError().')');
124
+ $errors[] = 'MySQL error: '.$this->queue->getError();
125
+ } elseif (0 == (int)filesize($mysql_dump_file)) {
126
+ $errors[] = 'MySQL error: empty dump-file';
127
+ WPAdm_Core::log('Дамп БД не создан(пустой файл)');
128
+ } else {
129
+ WPAdm_Core::log('Дамп БД создан('.filesize($mysql_dump_file).'b):' . $mysql_dump_file);
130
+ }
131
+ unset($commandContext);
132
+
133
+
134
+ #ЗАРХИВИРУЕМ ФАЙЛЫ
135
+ WPAdm_Core::log('Начинаем подготовку списка файлов');
136
+ // список файлов для архивации
137
+ if ($this->type == 'full') {
138
+ $files = $this->createListFilesForArchive();
139
+ } else {
140
+ $files = array();
141
+ }
142
+ if (file_exists($mysql_dump_file) && filesize($mysql_dump_file) > 0) {
143
+ $files[] = $mysql_dump_file;
144
+ }
145
+
146
+ if (empty($files)) {
147
+ $errors[] = 'Empty list files';
148
+ }
149
+
150
+ // разабьем список файлов на списки по 170кбайт,
151
+ // чтобы разбить одну большую задачу на маленькие
152
+ $files2 = array();
153
+ $files2[0] = array();
154
+ $i = 0;
155
+ $size = 0;
156
+ foreach($files as $f) {
157
+ if ($size > 170000) {//~170kbyte
158
+ $i ++;
159
+ $size = 0;
160
+ $files2[$i] = array();
161
+ }
162
+ $f_size =(int)filesize($f);
163
+ if ($f_size == 0 || $f_size > 1000000) {
164
+ WPAdm_Core::log('file '. $f .' size ' . $f_size);
165
+ }
166
+ $size += $f_size;
167
+ $files2[$i][] = $f;
168
+ }
169
+
170
+ WPAdm_Core::log('Список файлов подготовлен');
171
+ // подготовим очередь к выполнению
172
+ $this->queue->clear();
173
+
174
+ foreach($files2 as $files) {
175
+ $commandContext = new WPAdm_Command_Context();
176
+ $commandContext ->addParam('command','archive')
177
+ ->addParam('files', $files)
178
+ ->addParam('to_file', $this->dir . '/'.$this->name)
179
+ ->addParam('max_file_size', 900000)
180
+ ->addParam('remove_path', ABSPATH);
181
+
182
+ $this->queue->add($commandContext);
183
+ unset($commandContext);
184
+ }
185
+ WPAdm_Core::log('Начинаем архивацию файлов');
186
+ // сохраним и выполним
187
+ $this->queue->save()
188
+ ->execute();
189
+ WPAdm_Core::log('Закочили архивацию файлов');
190
+
191
+ $files = glob($this->dir . '/'.$this->name . '*');
192
+ $urls = array();
193
+ foreach($files as $file) {
194
+ $urls[] = str_replace(ABSPATH, '', $file);
195
+ }
196
+ $this->result->setData($urls);
197
+
198
+
199
+ # КОПИРОВАНИЕ ФАЙЛОВ НА FTP
200
+ if (isset($this->params['storage']) && $this->params['storage']['type'] == 'ftp') {
201
+ WPAdm_Core::log('Начинаем копирование файлов на FTP');
202
+ $this->queue->clear();
203
+ $files = glob($this->dir . '/'.$this->name . '*');
204
+ //$this->getResult()->setData($files);
205
+ $ad = $this->params['storage']['access_details'];
206
+ $dir = (isset($ad['dir'])) ? $ad['dir'] : '/';
207
+ $dir = trim($dir, '/') . '/' . $this->name;
208
+ foreach($files as $file) {
209
+ $commandContext = new WPAdm_Command_Context();
210
+ $commandContext ->addParam('command','send_to_ftp')
211
+ ->addParam('file', $file)
212
+ ->addParam('host', $ad['host'])
213
+ ->addParam('port', (isset($ad['port']))? $ad['port'] : 21)
214
+ ->addParam('user', $ad['user'])
215
+ ->addParam('password', $ad['password'])
216
+ ->addParam('dir', $dir)
217
+ ->addParam('http_host', isset($ad['http_host']) ? $ad['http_host'] : '');
218
+ $this->queue->add($commandContext);
219
+ unset($commandContext);
220
+ }
221
+ $res = $this->queue->save()
222
+ ->execute();
223
+ if (!$res) {
224
+ WPAdm_Core::log('FTP: ' . $this->queue->getError());
225
+ $errors[] = 'FTP: '.$this->queue->getError();
226
+ }
227
+ WPAdm_Core::log('Закончили копирование файлов на FTP');
228
+ if (isset($this->params['storage']['remove_from_server']) && $this->params['storage']['remove_from_server'] == 1 ) {
229
+ // удаляем файлы на сервере
230
+ WPAdm_Core::log('Удаляем бэкап на сервере');
231
+ WPAdm_Core::rmdir($this->dir);
232
+ }
233
+ }
234
+
235
+ #УДАЛЕНИЕ TMP-ФАЙЛОВ
236
+ //todo: УДАЛЕНИЕ TMP-ФАЙЛОВ
237
+ WPAdm_Core::rmdir(ABSPATH.'/wpadm_backup');
238
+
239
+ #УДАЛЕНИЕ СТАРЫХ АРХИВОВ(те что не влазят в лимит)
240
+ //todo: не правмльно удаляет, если есть ооба типа бэкапа
241
+ WPAdm_Core::log('Начинаем удалять старые архивы');
242
+ if ($this->params['limit'] != 0) {
243
+ $files = glob(ABSPATH . '/wpadm_backups/*');
244
+ if (count($files) > $this->params['limit']) {
245
+ $files2 = array();
246
+ foreach($files as $f) {
247
+ $fa = explode('-', $f);
248
+ if (count($fa) != 3) {
249
+ continue;
250
+ }
251
+ $files2[$fa[2]] = $f;
252
+
253
+ }
254
+ ksort($files2);
255
+ $d = count($files2) - $this->params['limit'];
256
+ $del = array_slice($files2, 0, $d);
257
+ foreach($del as $d) {
258
+ WPAdm_Core::rmdir($d);
259
+ }
260
+ }
261
+ }
262
+ WPAdm_Core::log('Закончили удалять старые архивы');
263
+
264
+ WPAdm_Core::log('Бэкап завершен');
265
+
266
+ if (!empty($errors)) {
267
+ $this->result->setError(implode("\n", $errors));
268
+ $this->result->setResult(WPAdm_Result::WPADM_RESULT_ERROR);
269
+ }
270
+
271
+ return $this->result;
272
+
273
+
274
+ }
275
+
276
+
277
+
278
+ public function createListFilesForArchive() {
279
+ $folders = array();
280
+ $files = array();
281
+
282
+ $files = array_merge(
283
+ $files,
284
+ array(
285
+ ABSPATH .'/.htaccess',
286
+ ABSPATH .'/index.php',
287
+ ABSPATH .'/license.txt',
288
+ ABSPATH .'/readme.html',
289
+ ABSPATH .'/wp-activate.php',
290
+ ABSPATH .'/wp-blog-header.php',
291
+ ABSPATH .'/wp-comments-post.php',
292
+ ABSPATH .'/wp-config.php',
293
+ ABSPATH .'/wp-config-sample.php',
294
+ ABSPATH .'/wp-cron.php',
295
+ ABSPATH .'/wp-links-opml.php',
296
+ ABSPATH .'/wp-load.php',
297
+ ABSPATH .'/wp-login.php',
298
+ ABSPATH .'/wp-mail.php',
299
+ ABSPATH .'/wp-settings.php',
300
+ ABSPATH .'/wp-signup.php',
301
+ ABSPATH .'/wp-trackback.php',
302
+ ABSPATH .'/xmlrpc.php',
303
+ )
304
+ );
305
+
306
+ if (!empty($this->params['minus-path'])) {
307
+ foreach($files as $k=>$v) {
308
+ $v = str_replace(ABSPATH .'/' , '', $v);
309
+ if (in_array($v, $this->params['minus-path'])) {
310
+ unset($files[$k]);
311
+ WPAdm_Core::log('Пропускаем файл ' . $v);
312
+ }
313
+ }
314
+ }
315
+
316
+ $folders = array_merge(
317
+ $folders,
318
+ array(
319
+ ABSPATH .'/wp-admin',
320
+ ABSPATH .'/wp-content',
321
+ ABSPATH .'/wp-includes',
322
+ )
323
+ );
324
+
325
+ foreach($this->params['plus-path'] as $p) {
326
+ if (empty($p)) {
327
+ continue;
328
+ }
329
+ $p = ABSPATH .'/' . $p;
330
+ if (file_exists($p)) {
331
+ if (is_dir($p)) {
332
+ $folders[] = $p;
333
+ } else{
334
+ $files[] = $p;
335
+ }
336
+ }
337
+ }
338
+
339
+ $folders = array_unique($folders);
340
+ $files = array_unique($files);
341
+
342
+ foreach($folders as $folder) {
343
+ if (!is_dir($folder)) {
344
+ continue;
345
+ }
346
+ $files = array_merge($files, $this->directoryToArray($folder, true));
347
+ }
348
+ return $files;
349
+ }
350
+
351
+
352
+ private function directoryToArray($directory, $recursive) {
353
+ $array_items = array();
354
+
355
+ $d = str_replace(ABSPATH . '/', '', $directory);
356
+ // пропускаем ненужные директории
357
+
358
+ if (
359
+ in_array($d, $this->params['minus-path'])
360
+ ) {
361
+ WPAdm_Core::log('Пропускаем папку ' . $directory);
362
+ return array();
363
+ }
364
+
365
+ $d = str_replace('\\', '/', $d);
366
+ $tmp = explode('/', $d);
367
+ $d1 = mb_strtolower($tmp[0]);
368
+ unset($tmp[0]);
369
+ $d2 = mb_strtolower(implode('/', $tmp));
370
+ // if (strpos($d1, 'cache') !== false || ($d1 == 'wp-includes' && strpos($d2, 'cache') !== false)) {
371
+ // if (($d1 == 'wp-includes' && strpos($d2, 'cache') !== false)
372
+ // || ($d1 == 'wp-content' || !in_array($tmp[0], array('plugins', 'themes')))
373
+ if (strpos($d2, 'cache') !== false
374
+ && !in_array($tmp[0], array('plugins', 'themes'))
375
+ ) {
376
+ WPAdm_Core::log('Пропускаем папку(cache) ' . $directory);
377
+ return array();
378
+ }
379
+
380
+ if ($handle = opendir($directory)) {
381
+ while (false !== ($file = readdir($handle))) {
382
+ if ($file != "." && $file != "..") {
383
+ if (is_dir($directory. "/" . $file)) {
384
+ if($recursive) {
385
+ $array_items = array_merge($array_items, $this->directoryToArray($directory. "/" . $file, $recursive));
386
+ }
387
+
388
+ $file = $directory . "/" . $file;
389
+ if (!is_dir($file)) {
390
+ $ff = preg_replace("/\/\//si", "/", $file);
391
+ $f = str_replace(ABSPATH . '/', '', $ff);
392
+ // пропускаем ненужные директории
393
+ if (!in_array($f, $this->params['minus-path'])) {
394
+ $array_items[] = $ff;
395
+ } else {
396
+ WPAdm_Core::log('Пропускаем файл ' . $ff);
397
+ }
398
+ }
399
+ } else {
400
+ $file = $directory . "/" . $file;
401
+ if (!is_dir($file)) {
402
+ $ff = preg_replace("/\/\//si", "/", $file);
403
+ $f = str_replace(ABSPATH . '/', '', $ff);
404
+ // пропускаем ненужные директории
405
+ if (!in_array($f, $this->params['minus-path'])) {
406
+ $array_items[] = $ff;
407
+ } else {
408
+ WPAdm_Core::log('Пропускаем файл ' . $ff);
409
+ }
410
+ }
411
+ }
412
+ }
413
+ }
414
+ closedir($handle);
415
+ }
416
+ return $array_items;
417
+ }
418
+
419
+
420
+ /*
421
+ * Берем реквизиты доступа к MySQL из параметров WP
422
+ * return Array()
423
+ */
424
+ private function getWpMysqlParams()
425
+ {
426
+ $db_params = array(
427
+ 'password' => 'DB_PASSWORD',
428
+ 'db' => 'DB_NAME',
429
+ 'user' => 'DB_USER',
430
+ 'host' => 'DB_HOST',
431
+ );
432
+
433
+ $r = "/define\('(.*)', '(.*)'\)/";
434
+ preg_match_all($r, file_get_contents(ABSPATH . "wp-config.php"), $m);
435
+ $params = array_combine($m[1], $m[2]);
436
+ foreach($db_params as $k=>$p) {
437
+ $db_params[$k] = $params[$p];
438
+ }
439
+ return $db_params;
440
+ }
441
+
442
+
443
+ private function init(array $conf) {
444
+ //todo: нормализация
445
+ $this->id = $conf['id'];
446
+ $this->stime = $conf['stime'];
447
+ $this->queue = new WPAdm_Queue($this->id);
448
+ $this->type = $conf['type'];
449
+ }
450
+ }
451
+ }
methods/class-wpadm-method-full-backup-dropbox.php ADDED
@@ -0,0 +1,512 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Creates a full backup of the site
4
+ * Class WPadm_Method_Backup_Dropbox
5
+ */
6
+ if (!class_exists('WPadm_Method_Full_Backup_Dropbox')) {
7
+ class WPadm_Method_Full_Backup_Dropbox extends WPAdm_Method_Class {
8
+ /**
9
+ * uniqueid
10
+ * @var String
11
+ */
12
+ private $id;
13
+
14
+ /**
15
+ * Unixtimestamp, start time method
16
+ * @var Int
17
+ */
18
+ private $stime;
19
+
20
+ /**
21
+ * @var WPAdm_Queue
22
+ */
23
+ private $queue;
24
+
25
+ /**
26
+ * @var string
27
+ */
28
+ private $dir;
29
+
30
+ /**
31
+ * @var string
32
+ */
33
+ private $tmp_dir;
34
+
35
+ /**
36
+ * type of backup
37
+ * @var string
38
+ */
39
+ private $type = 'full';
40
+
41
+ private $name = '';
42
+
43
+ public function __construct($params) {
44
+ parent::__construct($params);
45
+ $this->init(
46
+ array(
47
+ 'id' => uniqid('wpadm_method_backup__'),
48
+ 'stime' => time(),
49
+ )
50
+ );
51
+
52
+
53
+ $name = get_option('siteurl');
54
+
55
+ $name = str_replace("http://", '', $name);
56
+ $name = str_replace("https://", '', $name);
57
+ $name = preg_replace("|\W|", "_", $name);
58
+ $name .= '-' . $this->type . '-' . date("Y_m_d_H_i");
59
+ $this->name = $name;
60
+
61
+ // folder for backup
62
+ $this->dir = ABSPATH . 'wpadm_backups/' . $this->name;
63
+ WPAdm_Core::mkdir(ABSPATH . 'wpadm_backups/');
64
+ WPAdm_Core::mkdir($this->dir);
65
+ }
66
+
67
+ public function getResult()
68
+ {
69
+ $errors = array();
70
+
71
+ $this->result->setResult(WPAdm_Result::WPADM_RESULT_SUCCESS);
72
+ $this->result->setError('');
73
+
74
+ WPAdm_Core::log('Start backup');
75
+
76
+ # create db dump
77
+ WPAdm_Core::log('Start create db dump');
78
+ WPAdm_Core::mkdir(ABSPATH . 'wpadm_backup');
79
+ $mysql_dump_file = ABSPATH . 'wpadm_backup/mysqldump.sql';
80
+ if (file_exists($mysql_dump_file)) {
81
+ unlink($mysql_dump_file);
82
+ }
83
+ $wp_mysql_params = $this->getWpMysqlParams();
84
+
85
+ if (isset($this->params['optimize']) && ($this->params['optimize']==1)) {
86
+ WPAdm_Core::log('Table optimization');
87
+ $commandContext = new WPAdm_Command_Context();
88
+ $commandContext ->addParam('command','mysqloptimize')
89
+ ->addParam('host', $wp_mysql_params['host'])
90
+ ->addParam('db', $wp_mysql_params['db'])
91
+ ->addParam('user', $wp_mysql_params['user'])
92
+ ->addParam('password', $wp_mysql_params['password']);
93
+ $this->queue->clear()
94
+ ->add($commandContext);
95
+ unset($commandContext);
96
+ }
97
+
98
+ $commandContext = new WPAdm_Command_Context();
99
+ $commandContext ->addParam('command','mysqldump')
100
+ ->addParam('host', $wp_mysql_params['host'])
101
+ ->addParam('db', $wp_mysql_params['db'])
102
+ ->addParam('user', $wp_mysql_params['user'])
103
+ ->addParam('password', $wp_mysql_params['password'])
104
+ ->addParam('tables', '')
105
+ ->addParam('to_file', $mysql_dump_file);
106
+ $res = $this->queue->add($commandContext)
107
+ ->save()
108
+ ->execute();
109
+ if (!$res) {
110
+ WPAdm_Core::log('Database dump was not created('.$this->queue->getError().')');
111
+ $errors[] = 'MySQL error: '.$this->queue->getError();
112
+ } elseif (0 == (int)filesize($mysql_dump_file)) {
113
+ $errors[] = 'MySQL error: empty dump-file';
114
+ WPAdm_Core::log('Database dump was not created (empty file)');
115
+ } else {
116
+ WPAdm_Core::log('Database dump created('.filesize($mysql_dump_file).'b):' . $mysql_dump_file);
117
+ }
118
+ unset($commandContext);
119
+
120
+
121
+ #ЗАРХИВИРУЕМ ФАЙЛЫ
122
+ WPAdm_Core::log('Create a list of files');
123
+ $files = $this->createListFilesForArchive();
124
+ if (file_exists($mysql_dump_file) && filesize($mysql_dump_file) > 0) {
125
+ $files[] = $mysql_dump_file;
126
+ }
127
+
128
+ if (empty($files)) {
129
+ $errors[] = 'Empty list files';
130
+ }
131
+
132
+ // split the file list by 170kbayt lists, To break one big task into smaller
133
+ $files2 = array();
134
+ $files2[0] = array();
135
+ $i = 0;
136
+ $size = 0;
137
+ foreach($files as $f) {
138
+ if ($size > 170000) {//~170kbyte
139
+ $i ++;
140
+ $size = 0;
141
+ $files2[$i] = array();
142
+ }
143
+ $f_size =(int)@filesize($f);
144
+ if ($f_size == 0 || $f_size > 1000000) {
145
+ WPAdm_Core::log('file '. $f .' size ' . $f_size);
146
+ }
147
+ $size += $f_size;
148
+ $files2[$i][] = $f;
149
+ }
150
+
151
+ WPAdm_Core::log('List of files created');
152
+
153
+ $this->queue->clear();
154
+
155
+ foreach($files2 as $files) {
156
+ $commandContext = new WPAdm_Command_Context();
157
+ $commandContext ->addParam('command','archive')
158
+ ->addParam('files', $files)
159
+ ->addParam('to_file', $this->dir . '/'.$this->name)
160
+ ->addParam('max_file_size', 900000)
161
+ ->addParam('remove_path', ABSPATH);
162
+
163
+ $this->queue->add($commandContext);
164
+ unset($commandContext);
165
+ }
166
+ WPAdm_Core::log('Start backing up files');
167
+ $this->queue->save()
168
+ ->execute();
169
+ WPAdm_Core::log('End of backup files');
170
+
171
+ $files = glob($this->dir . '/'.$this->name . '*');
172
+ $urls = array();
173
+ $totalSize = 0;
174
+ foreach($files as $file) {
175
+ $urls[] = str_replace(ABSPATH, '', $file);
176
+ $totalSize += @intval( filesize($file) );
177
+ }
178
+ $this->result->setData($urls);
179
+ $this->result->setSize($totalSize);
180
+
181
+
182
+ $remove_from_server = 0;
183
+ if (isset($this->params['storage'])) {
184
+ foreach($this->params['storage'] as $storage) {
185
+ if ($storage['type'] == 'ftp') {
186
+ WPAdm_Core::log('Begin copying files to FTP');
187
+ $this->queue->clear();
188
+ $files = glob($this->dir . '/'.$this->name . '*');
189
+ //$this->getResult()->setData($files);
190
+ $ad = $storage['access_details'];
191
+ $dir = (isset($ad['dir'])) ? $ad['dir'] : '/';
192
+ $dir = trim($dir, '/') . '/' . $this->name;
193
+ foreach($files as $file) {
194
+ $commandContext = new WPAdm_Command_Context();
195
+ $commandContext ->addParam('command','send_to_ftp')
196
+ ->addParam('file', $file)
197
+ ->addParam('host', $ad['host'])
198
+ ->addParam('port', (isset($ad['port']))? $ad['port'] : 21)
199
+ ->addParam('user', $ad['user'])
200
+ ->addParam('password', $ad['password'])
201
+ ->addParam('dir', $dir)
202
+ ->addParam('http_host', isset($ad['http_host']) ? $ad['http_host'] : '');
203
+ $this->queue->add($commandContext);
204
+ unset($commandContext);
205
+ }
206
+ $res = $this->queue->save()
207
+ ->execute();
208
+ if (!$res) {
209
+ WPAdm_Core::log('FTP: ' . $this->queue->getError());
210
+ $errors[] = 'FTP: '.$this->queue->getError();
211
+ }
212
+ WPAdm_Core::log('Finished copying files to FTP');
213
+ if (isset($storage['remove_from_server']) && $storage['remove_from_server'] == 1 ) {
214
+ $remove_from_server = $storage['remove_from_server'];
215
+ }
216
+ } elseif ($storage['type'] == 's3') {
217
+ WPAdm_Core::log('Begin coping files to S3');
218
+ $this->queue->clear();
219
+ $files = glob($this->dir . '/'.$this->name . '*');
220
+ //$this->getResult()->setData($files);
221
+ $ad = $storage['access_details'];
222
+ $dir = (isset($ad['dir'])) ? $ad['dir'] : '/';
223
+ $dir = trim($dir, '/') . '/' . $this->name;
224
+ foreach($files as $file) {
225
+ $commandContext = new WPAdm_Command_Context();
226
+ $commandContext ->addParam('command','send_to_s3')
227
+ ->addParam('file', $file)
228
+ ->addParam('bucket', $ad['bucket'])
229
+ ->addParam('AccessKeyId', $ad['AccessKeyId'])
230
+ ->addParam('SecretAccessKey', $ad['SecretAccessKey'])
231
+ ->addParam('SessionToken', $ad['SessionToken']);
232
+ $this->queue->add($commandContext);
233
+ unset($commandContext);
234
+ }
235
+ $res = $this->queue->save()
236
+ ->execute();
237
+ if (!$res) {
238
+ WPAdm_Core::log('S3: ' . $this->queue->getError());
239
+ $errors[] = 'S3: '.$this->queue->getError();
240
+ }
241
+ WPAdm_Core::log('Finished copying files to S3');
242
+ if (isset($storage['remove_from_server']) && $storage['remove_from_server'] == 1 ) {
243
+ $remove_from_server = $storage['remove_from_server'];
244
+ }
245
+ }
246
+ }
247
+ if ($remove_from_server) {
248
+ // удаляем файлы на сервере
249
+ WPAdm_Core::log('Remove the backup server');
250
+ WPAdm_Core::rmdir($this->dir);
251
+ }
252
+
253
+ }
254
+ if (isset($this->params['gd']) && isset($this->params['gd']['key']) && isset($this->params['gd']['secret'])) {
255
+ $this->queue->clear();
256
+ $files = glob($this->dir . '/' . $this->name . '*');
257
+ $files = array_merge_recursive(array($mysql_dump_file), $files);
258
+ WPAdm_Core::log('files to google: ' . print_r($files, true));
259
+ $n = count($files);
260
+ for($i = 0; $i <$n; $i++) {
261
+ $commandContext = new WPAdm_Command_Context();
262
+ $commandContext->addParam('command', 'send_to_google_drive')
263
+ ->addParam('key', $this->params['gd']['key'])
264
+ ->addParam('secret', $this->params['gd']['secret'])
265
+ ->addParam('token', $this->params['gd']['token'])
266
+ ->addParam('folder_project', $this->params['gd']['folder'])
267
+ ->addParam('folder', $this->name )
268
+ ->addParam('files', $files[$i]);
269
+ $this->queue->add($commandContext);
270
+ unset($commandContext);
271
+ }
272
+ $res = $this->queue->save()
273
+ ->execute();
274
+ if (!$res) {
275
+ WPAdm_Core::log('Google drive: ' . $this->queue->getError());
276
+ }
277
+ //WPAdm_Core::log('google drive' . print_r($this->params, true));
278
+ }
279
+ if (isset($this->params['dropbox']) && isset($this->params['dropbox']['key']) && isset($this->params['dropbox']['secret'])) {
280
+ $this->queue->clear();
281
+ $files = glob($this->dir . '/' . $this->name . '*');
282
+ $files = array_merge_recursive(array($mysql_dump_file), $files);
283
+ WPAdm_Core::log('files to dropbox: ' . print_r($files, true));
284
+ $n = count($files);
285
+ for($i = 0; $i <$n; $i++) {
286
+ $commandContext = new WPAdm_Command_Context();
287
+ $commandContext->addParam('command', 'send_to_dropbox')
288
+ ->addParam('key', $this->params['dropbox']['key'])
289
+ ->addParam('secret', $this->params['dropbox']['secret'])
290
+ ->addParam('token', $this->params['dropbox']['token'])
291
+ ->addParam('folder_project', $this->params['dropbox']['folder'])
292
+ ->addParam('folder', $this->name)
293
+ ->addParam('files', $files[$i]);
294
+ $this->queue->add($commandContext);
295
+ unset($commandContext);
296
+ }
297
+ $this->queue->save()
298
+ ->execute();
299
+ if (!$res) {
300
+ WPAdm_Core::log('Dropbox: ' . $this->queue->getError());
301
+ }
302
+ }
303
+
304
+ #Removing TMP-files
305
+ WPAdm_Core::rmdir(ABSPATH.'wpadm_backup');
306
+
307
+ #Removind old backups(if limit the number of stored backups)
308
+ WPAdm_Core::log('Start removing old backups');
309
+ if ($this->params['limit'] != 0) {
310
+ $files = glob(ABSPATH . 'wpadm_backups/*');
311
+ if (count($files) > $this->params['limit']) {
312
+ $files2 = array();
313
+ foreach($files as $f) {
314
+ $fa = explode('-', $f);
315
+ if (count($fa) != 3) {
316
+ continue;
317
+ }
318
+ $files2[$fa[2]] = $f;
319
+
320
+ }
321
+ ksort($files2);
322
+ $d = count($files2) - $this->params['limit'];
323
+ $del = array_slice($files2, 0, $d);
324
+ foreach($del as $d) {
325
+ WPAdm_Core::rmdir($d);
326
+ }
327
+ }
328
+ }
329
+ WPAdm_Core::log('Finished removing old backups');
330
+
331
+ WPAdm_Core::log('Creating a backup is completed');
332
+
333
+ if (!empty($errors)) {
334
+ $this->result->setError(implode("\n", $errors));
335
+ $this->result->setResult(WPAdm_Result::WPADM_RESULT_ERROR);
336
+ }
337
+
338
+ return $this->result;
339
+
340
+
341
+ }
342
+
343
+
344
+
345
+ public function createListFilesForArchive() {
346
+ $folders = array();
347
+ $files = array();
348
+
349
+ $files = array_merge(
350
+ $files,
351
+ array(
352
+ ABSPATH . '.htaccess',
353
+ ABSPATH . 'index.php',
354
+ ABSPATH . 'license.txt',
355
+ ABSPATH . 'readme.html',
356
+ ABSPATH . 'wp-activate.php',
357
+ ABSPATH . 'wp-blog-header.php',
358
+ ABSPATH . 'wp-comments-post.php',
359
+ ABSPATH . 'wp-config.php',
360
+ ABSPATH . 'wp-config-sample.php',
361
+ ABSPATH . 'wp-cron.php',
362
+ ABSPATH . 'wp-links-opml.php',
363
+ ABSPATH . 'wp-load.php',
364
+ ABSPATH . 'wp-login.php',
365
+ ABSPATH . 'wp-mail.php',
366
+ ABSPATH . 'wp-settings.php',
367
+ ABSPATH . 'wp-signup.php',
368
+ ABSPATH . 'wp-trackback.php',
369
+ ABSPATH . 'xmlrpc.php',
370
+ )
371
+ );
372
+
373
+ if (!empty($this->params['minus-path'])) {
374
+ $minus_path = explode(",", $this->params['minus-path']);
375
+ foreach($files as $k => $v) {
376
+ $v = str_replace(ABSPATH , '', $v);
377
+ if (in_array($v, $minus_path)) {
378
+ unset($files[$k]);
379
+ WPAdm_Core::log('Skip file ' . $v);
380
+ }
381
+ }
382
+ }
383
+
384
+ $folders = array_merge(
385
+ $folders,
386
+ array(
387
+ ABSPATH . 'wp-admin',
388
+ ABSPATH . 'wp-content',
389
+ ABSPATH . 'wp-includes',
390
+ )
391
+ );
392
+ if (!empty($this->params['plus-path'])) {
393
+ $plus_path = explode(",", $this->params['plus-path']);
394
+ foreach($plus_path as $p) {
395
+ if (empty($p)) {
396
+ continue;
397
+ }
398
+ $p = ABSPATH . $p;
399
+ if (file_exists($p)) {
400
+ if (is_dir($p)) {
401
+ $folders[] = $p;
402
+ } else{
403
+ $files[] = $p;
404
+ }
405
+ }
406
+ }
407
+ }
408
+
409
+ $folders = array_unique($folders);
410
+ $files = array_unique($files);
411
+
412
+ foreach($folders as $folder) {
413
+ if (!is_dir($folder)) {
414
+ continue;
415
+ }
416
+ $files = array_merge($files, $this->directoryToArray($folder, true));
417
+ }
418
+ return $files;
419
+ }
420
+
421
+
422
+ private function directoryToArray($directory, $recursive) {
423
+ $array_items = array();
424
+
425
+ $d = str_replace(ABSPATH, '', $directory);
426
+ // Skip dirs
427
+ $minus_path = explode(",", $this->params['minus-path']);
428
+ if (in_array($d, $minus_path) ) {
429
+ WPAdm_Core::log('Skip dir ' . $directory);
430
+ return array();
431
+ }
432
+
433
+ $d = str_replace('\\', '/', $d);
434
+ $tmp = explode('/', $d);
435
+ $d1 = mb_strtolower($tmp[0]);
436
+ unset($tmp[0]);
437
+ $d2 = mb_strtolower(implode('/', $tmp));
438
+ if (strpos($d2, 'cache') !== false && isset($tmp[0]) && !in_array($tmp[0], array('plugins', 'themes')) ) {
439
+ WPAdm_Core::log('Skip dir(cache) ' . $directory);
440
+ return array();
441
+ }
442
+
443
+ if ($handle = opendir($directory)) {
444
+ while (false !== ($file = readdir($handle))) {
445
+ if ($file != "." && $file != "..") {
446
+ if (is_dir($directory. "/" . $file)) {
447
+ if($recursive) {
448
+ $array_items = array_merge($array_items, $this->directoryToArray($directory. "/" . $file, $recursive));
449
+ }
450
+
451
+ $file = $directory . "/" . $file;
452
+ if (!is_dir($file)) {
453
+ $ff = preg_replace("/\/\//si", "/", $file);
454
+ $f = str_replace(ABSPATH, '', $ff);
455
+ // skip "minus" dirs
456
+ if (!in_array($f, $minus_path)) {
457
+ $array_items[] = $ff;
458
+ } else {
459
+ WPAdm_Core::log('Skip file ' . $ff);
460
+ }
461
+ }
462
+ } else {
463
+ $file = $directory . "/" . $file;
464
+ if (!is_dir($file)) {
465
+ $ff = preg_replace("/\/\//si", "/", $file);
466
+ $f = str_replace(ABSPATH, '', $ff);
467
+ // skip "minus" dirs
468
+ if (!in_array($f, $minus_path)) {
469
+ $array_items[] = $ff;
470
+ } else {
471
+ WPAdm_Core::log('Skip dir ' . $ff);
472
+ }
473
+ }
474
+ }
475
+ }
476
+ }
477
+ closedir($handle);
478
+ }
479
+ return $array_items;
480
+ }
481
+
482
+
483
+ /*
484
+ * returns the elements of access to MySQL from WP options
485
+ * return Array()
486
+ */
487
+ private function getWpMysqlParams()
488
+ {
489
+ $db_params = array(
490
+ 'password' => 'DB_PASSWORD',
491
+ 'db' => 'DB_NAME',
492
+ 'user' => 'DB_USER',
493
+ 'host' => 'DB_HOST',
494
+ );
495
+
496
+ $r = "/define\('(.*)', '(.*)'\)/";
497
+ preg_match_all($r, file_get_contents(ABSPATH . "wp-config.php"), $m);
498
+ $params = array_combine($m[1], $m[2]);
499
+ foreach($db_params as $k=>$p) {
500
+ $db_params[$k] = $params[$p];
501
+ }
502
+ return $db_params;
503
+ }
504
+
505
+
506
+ private function init(array $conf) {
507
+ $this->id = $conf['id'];
508
+ $this->stime = $conf['stime'];
509
+ $this->queue = new WPAdm_Queue($this->id);
510
+ }
511
+ }
512
+ }
methods/class-wpadm-method-local-backup.php ADDED
@@ -0,0 +1,369 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if (!class_exists('WPAdm_Method_Local_Backup')) {
4
+ class WPAdm_Method_Local_Backup extends WPAdm_Method_Class {
5
+
6
+ public function __construct($params)
7
+ {
8
+ parent::__construct($params);
9
+ $this->init(
10
+ array(
11
+ 'id' => uniqid('wpadm_method_backup__'),
12
+ 'stime' => time(),
13
+ )
14
+ );
15
+ $file_log = WPAdm_Core::getTmpDir() . "/log.log";
16
+ if (file_exists($file_log)) {
17
+ unlink($file_log);
18
+ }
19
+ WPAdm_Core::log('Create Unique Id '. $this->id);
20
+
21
+
22
+ $name = get_option('siteurl');
23
+
24
+ $name = str_replace("http://", '', $name);
25
+ $name = str_replace("https://", '', $name);
26
+ $name = preg_replace("|\W|", "_", $name);
27
+ $this->time = date("d.m.Y H:i"); //23.04.2015 13:45
28
+ $name .= '-' . wpadm_class::$type . '-' . date("Y_m_d_H_i");
29
+ $this->name = $name;
30
+
31
+
32
+ // folder for backup
33
+ $this->dir = ABSPATH . 'wpadm_backups/' . $this->name;
34
+ WPAdm_Core::mkdir(ABSPATH . 'wpadm_backups/');
35
+ WPAdm_Core::mkdir($this->dir);
36
+ }
37
+ public function getResult()
38
+ {
39
+
40
+ $errors = array();
41
+
42
+ $this->result->setResult(WPAdm_Result::WPADM_RESULT_SUCCESS);
43
+ $this->result->setError('');
44
+
45
+ WPAdm_Core::log('Start Backup process...');
46
+
47
+ # create db dump
48
+ if (in_array('db', $this->params['types']) ) {
49
+ WPAdm_Core::log('Creating Database Dump');
50
+ WPAdm_Core::mkdir(ABSPATH . 'wpadm_backup');
51
+ $mysql_dump_file = ABSPATH . 'wpadm_backup/mysqldump.sql';
52
+ if (file_exists($mysql_dump_file)) {
53
+ unlink($mysql_dump_file);
54
+ }
55
+ $wp_mysql_params = $this->getWpMysqlParams();
56
+
57
+ // Table Optimization
58
+ if (isset($this->params['optimize']) && ($this->params['optimize']==1)) {
59
+ WPAdm_Core::log('Optimize Database Tables');
60
+ $commandContext = new WPAdm_Command_Context();
61
+ $commandContext ->addParam('command','mysqloptimize')
62
+ ->addParam('host', $wp_mysql_params['host'])
63
+ ->addParam('db', $wp_mysql_params['db'])
64
+ ->addParam('user', $wp_mysql_params['user'])
65
+ ->addParam('password', $wp_mysql_params['password']);
66
+ $this->queue->clear()
67
+ ->add($commandContext);
68
+ unset($commandContext);
69
+ }
70
+ // Creating of Database Backup
71
+ $commandContext = new WPAdm_Command_Context();
72
+ $commandContext ->addParam('command','mysqldump')
73
+ ->addParam('host', $wp_mysql_params['host'])
74
+ ->addParam('db', $wp_mysql_params['db'])
75
+ ->addParam('user', $wp_mysql_params['user'])
76
+ ->addParam('password', $wp_mysql_params['password'])
77
+ ->addParam('tables', '')
78
+ ->addParam('to_file', $mysql_dump_file);
79
+ $res = $this->queue->add($commandContext)
80
+ ->save()
81
+ ->execute();
82
+ if (!$res) {
83
+ WPAdm_Core::log('Error: Dump of Database wasn\'t created('.$this->queue->getError().')');
84
+ $errors[] = 'MySQL Error: '.$this->queue->getError();
85
+ } elseif (0 == (int)filesize($mysql_dump_file)) {
86
+ $errors[] = 'MySQL Error: Database-Dump File is empty';
87
+ WPAdm_Core::log('Dump of Database wasn\'t created (File of Database-Dump is empty!)');
88
+ } else {
89
+ WPAdm_Core::log('Database Dump was successfully created('.filesize($mysql_dump_file).'b):' . $mysql_dump_file);
90
+ }
91
+ unset($commandContext);
92
+ }
93
+
94
+
95
+ if (in_array('files', $this->params['types']) ) {
96
+ WPAdm_Core::log('Create a list of files for Backup');
97
+ $files = $this->createListFilesForArchive();
98
+ }
99
+ if (isset($mysql_dump_file) && file_exists($mysql_dump_file) && filesize($mysql_dump_file) > 0) {
100
+ $files[] = $mysql_dump_file;
101
+ }
102
+
103
+ if (empty($files)) {
104
+ $errors[] = 'Error: the list of Backup files is empty';
105
+ }
106
+
107
+ // split the file list by 170kbayt lists, To break one big task into smaller
108
+ $files2 = array();
109
+ $files2[0] = array();
110
+ $i = 0;
111
+ $size = 0;
112
+ foreach($files as $f) {
113
+ if ($size > 170000) {//~170kbyte
114
+ $i ++;
115
+ $size = 0;
116
+ $files2[$i] = array();
117
+ }
118
+ $f_size =(int)filesize($f);
119
+ if ($f_size == 0 || $f_size > 1000000) {
120
+ WPAdm_Core::log('File '. $f .' Size ' . $f_size);
121
+ }
122
+ $size += $f_size;
123
+ $files2[$i][] = $f;
124
+ }
125
+
126
+ WPAdm_Core::log('List of Backup-Files was successfully created');
127
+
128
+ $this->queue->clear();
129
+ // Adding Wordpress Files and MySQL Dump to Archive
130
+ foreach($files2 as $files) {
131
+ $commandContext = new WPAdm_Command_Context();
132
+ $commandContext ->addParam('command', 'archive')
133
+ ->addParam('files', $files)
134
+ ->addParam('to_file', $this->dir . '/'.$this->name)
135
+ ->addParam('max_file_size', 900000)
136
+ ->addParam('remove_path', ABSPATH);
137
+
138
+ $this->queue->add($commandContext);
139
+ unset($commandContext);
140
+ }
141
+ WPAdm_Core::log('Backup of Files was started');
142
+ $this->queue->save()
143
+ ->execute();
144
+ WPAdm_Core::log('End of File Backup');
145
+
146
+ $files = glob($this->dir . '/'.$this->name . '*');
147
+ $urls = array();
148
+ $totalSize = 0;
149
+ foreach($files as $file) {
150
+ $urls[] = str_replace(ABSPATH, '', $file);
151
+ $totalSize += @intval( filesize($file) );
152
+ }
153
+ $this->result->setData($urls);
154
+ $this->result->setSize($totalSize);
155
+ $size = $totalSize / 1024 / 1024; /// MByte
156
+ $size = round($size, 2);
157
+ WPAdm_Core::log('Backup Size ' . $size . " Mb");
158
+
159
+ $remove_from_server = 0;
160
+ #Removing TMP-files
161
+ WPAdm_Core::rmdir(ABSPATH . 'wpadm_backup');
162
+
163
+ #Removind old backups(if limit the number of stored backups)
164
+ if ($this->params['limit'] != 0) {
165
+ WPAdm_Core::log('Limits of Backups ' . $this->params['limit']);
166
+ WPAdm_Core::log('Removing of old Backups was started');
167
+ $files = glob(ABSPATH . 'wpadm_backups/*');
168
+ if (count($files) > $this->params['limit']) {
169
+ $files2 = array();
170
+ foreach($files as $f) {
171
+ $fa = explode('-', $f);
172
+ if (count($fa) != 3) {
173
+ continue;
174
+ }
175
+ $files2[$fa[2]] = $f;
176
+
177
+ }
178
+ ksort($files2);
179
+ $d = count($files2) - $this->params['limit'];
180
+ $del = array_slice($files2, 0, $d);
181
+ foreach($del as $d) {
182
+ WPAdm_Core::rmdir($d);
183
+ }
184
+ }
185
+ WPAdm_Core::log('Removing of old Backups was Finished');
186
+ }
187
+ if (!empty($errors)) {
188
+ $this->result->setError(implode("\n", $errors));
189
+ $this->result->setResult(WPAdm_Result::WPADM_RESULT_ERROR);
190
+ } else {
191
+ WPAdm_Core::log('Backup creating is completed successfully!');
192
+ }
193
+
194
+ return $this->result;
195
+
196
+ }
197
+
198
+ public function createListFilesForArchive() {
199
+ $folders = array();
200
+ $files = array();
201
+
202
+ $files = array_merge(
203
+ $files,
204
+ array(
205
+ ABSPATH . '.htaccess',
206
+ ABSPATH . 'index.php',
207
+ ABSPATH . 'license.txt',
208
+ ABSPATH . 'readme.html',
209
+ ABSPATH . 'wp-activate.php',
210
+ ABSPATH . 'wp-blog-header.php',
211
+ ABSPATH . 'wp-comments-post.php',
212
+ ABSPATH . 'wp-config.php',
213
+ ABSPATH . 'wp-config-sample.php',
214
+ ABSPATH . 'wp-cron.php',
215
+ ABSPATH . 'wp-links-opml.php',
216
+ ABSPATH . 'wp-load.php',
217
+ ABSPATH . 'wp-login.php',
218
+ ABSPATH . 'wp-mail.php',
219
+ ABSPATH . 'wp-settings.php',
220
+ ABSPATH . 'wp-signup.php',
221
+ ABSPATH . 'wp-trackback.php',
222
+ ABSPATH . 'xmlrpc.php',
223
+ )
224
+ );
225
+
226
+ if (!empty($this->params['minus-path'])) {
227
+ $minus_path = explode(",", $this->params['minus-path']);
228
+ foreach($files as $k => $v) {
229
+ $v = str_replace(ABSPATH , '', $v);
230
+ if (in_array($v, $minus_path)) {
231
+ unset($files[$k]);
232
+ WPAdm_Core::log('Skip of File ' . $v);
233
+ }
234
+ }
235
+ }
236
+
237
+ $folders = array_merge(
238
+ $folders,
239
+ array(
240
+ ABSPATH . 'wp-admin',
241
+ ABSPATH . 'wp-content',
242
+ ABSPATH . 'wp-includes',
243
+ )
244
+ );
245
+ if (!empty($this->params['plus-path'])) {
246
+ $plus_path = explode(",", $this->params['plus-path']);
247
+ foreach($plus_path as $p) {
248
+ if (empty($p)) {
249
+ continue;
250
+ }
251
+ $p = ABSPATH . $p;
252
+ if (file_exists($p)) {
253
+ if (is_dir($p)) {
254
+ $folders[] = $p;
255
+ } else{
256
+ $files[] = $p;
257
+ }
258
+ }
259
+ }
260
+ }
261
+
262
+ $folders = array_unique($folders);
263
+ $files = array_unique($files);
264
+
265
+ foreach($folders as $folder) {
266
+ if (!is_dir($folder)) {
267
+ continue;
268
+ }
269
+ $files = array_merge($files, $this->directoryToArray($folder, true));
270
+ }
271
+ return $files;
272
+ }
273
+
274
+
275
+ private function directoryToArray($directory, $recursive) {
276
+ $array_items = array();
277
+
278
+ $d = str_replace(ABSPATH, '', $directory);
279
+ // Skip dirs
280
+ if (isset($this->params['minus-path'])) {
281
+ $minus_path = explode(",", $this->params['minus-path']);
282
+ if (in_array($d, $minus_path) ) {
283
+ WPAdm_Core::log('Skip of Folder ' . $directory);
284
+ return array();
285
+ }
286
+ } else {
287
+ $minus_path = array();
288
+ }
289
+
290
+ $d = str_replace('\\', '/', $d);
291
+ $tmp = explode('/', $d);
292
+ $d1 = mb_strtolower($tmp[0]);
293
+ unset($tmp[0]);
294
+ $d2 = mb_strtolower(implode('/', $tmp));
295
+ if (strpos($d2, 'cache') !== false && isset($tmp[0])&& !in_array($tmp[0], array('plugins', 'themes')) ) {
296
+ WPAdm_Core::log('Skip of Cache-Folder ' . $directory);
297
+ return array();
298
+ }
299
+
300
+ if ($handle = opendir($directory)) {
301
+ while (false !== ($file = readdir($handle))) {
302
+ if ($file != "." && $file != "..") {
303
+ if (is_dir($directory. "/" . $file)) {
304
+ if($recursive) {
305
+ $array_items = array_merge($array_items, $this->directoryToArray($directory. "/" . $file, $recursive));
306
+ }
307
+
308
+ $file = $directory . "/" . $file;
309
+ if (!is_dir($file)) {
310
+ $ff = preg_replace("/\/\//si", "/", $file);
311
+ $f = str_replace(ABSPATH, '', $ff);
312
+ // skip "minus" dirs
313
+ if (!in_array($f, $minus_path)) {
314
+ $array_items[] = $ff;
315
+ } else {
316
+ WPAdm_Core::log('Skip of File ' . $ff);
317
+ }
318
+ }
319
+ } else {
320
+ $file = $directory . "/" . $file;
321
+ if (!is_dir($file)) {
322
+ $ff = preg_replace("/\/\//si", "/", $file);
323
+ $f = str_replace(ABSPATH, '', $ff);
324
+ // skip "minus" dirs
325
+ if (!in_array($f, $minus_path)) {
326
+ $array_items[] = $ff;
327
+ } else {
328
+ WPAdm_Core::log('Skip of Folder ' . $ff);
329
+ }
330
+ }
331
+ }
332
+ }
333
+ }
334
+ closedir($handle);
335
+ }
336
+ return $array_items;
337
+ }
338
+
339
+
340
+ /*
341
+ * returns the elements of access to MySQL from WP options
342
+ * return Array()
343
+ */
344
+ private function getWpMysqlParams()
345
+ {
346
+ $db_params = array(
347
+ 'password' => 'DB_PASSWORD',
348
+ 'db' => 'DB_NAME',
349
+ 'user' => 'DB_USER',
350
+ 'host' => 'DB_HOST',
351
+ );
352
+
353
+ $r = "/define\('(.*)', '(.*)'\)/";
354
+ preg_match_all($r, file_get_contents(ABSPATH . "wp-config.php"), $m);
355
+ $params = array_combine($m[1], $m[2]);
356
+ foreach($db_params as $k=>$p) {
357
+ $db_params[$k] = $params[$p];
358
+ }
359
+ return $db_params;
360
+ }
361
+
362
+
363
+ private function init(array $conf) {
364
+ $this->id = $conf['id'];
365
+ $this->stime = $conf['stime'];
366
+ $this->queue = new WPAdm_Queue($this->id);
367
+ }
368
+ }
369
+ }
methods/class-wpadm-method-local-restore.php ADDED
@@ -0,0 +1,142 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Class WPAdm_Method_Exec
4
+ */
5
+ if (!class_exists('WPAdm_Method_Local_Restore')) {
6
+ class WPAdm_Method_Local_Restore extends WPAdm_Method_Class {
7
+
8
+ private $restore = false;
9
+
10
+ private $files_resotre = array();
11
+
12
+ private $md5_info = "";
13
+
14
+ function __construct($params)
15
+ {
16
+ parent::__construct($params);
17
+ $this->init(
18
+ array(
19
+ 'id' => uniqid('wpadm_method_restore__'),
20
+ 'stime' => time(),
21
+ )
22
+ );
23
+ $this->getFiles();
24
+ $file_log = WPAdm_Core::getTmpDir() . "/log.log";
25
+ if (file_exists($file_log)) {
26
+ unlink($file_log);
27
+ }
28
+ WPAdm_Core::log('Create Unique Id '. $this->id);
29
+ if (count($this->files_resotre) > 0) {
30
+ $this->restore = true;
31
+ }
32
+
33
+ }
34
+ private function getFiles()
35
+ {
36
+ if (isset($this->params['name_backup']) && !empty($this->params['name_backup'])) {
37
+ $dir_backup = ABSPATH . 'wpadm_backups/' . $this->params['name_backup'];
38
+ if (is_dir($dir_backup)) {
39
+ WPAdm_Core::log('Read of Backup Files for Restore (' . $this->params['name_backup'] . ')');
40
+ $dir_open = opendir($dir_backup);
41
+ while($d = readdir($dir_open)) {
42
+ if ($d != "." && $d != '..') {
43
+ if(strpos($d, ".md5") !== false) {
44
+ $this->md5_info = explode ("\n", file_get_contents( $dir_backup . "/$d" ) );
45
+ } elseif(strpos($d, ".zip") !== false) {
46
+ $this->files_resotre[$d] = $dir_backup . "/$d";
47
+ }
48
+ }
49
+ }
50
+ return true;
51
+ }
52
+ }
53
+ WPAdm_Core::log('Error: folder is not exist (' . $this->params['name_backup'] . ')');
54
+ $this->setError('Error: folder is not exist (' . $this->params['name_backup'] . ')');
55
+ return false;
56
+
57
+ }
58
+ private function setError($errors)
59
+ {
60
+ $this->result->setError($errors);
61
+ $this->result->setResult(WPAdm_Result::WPADM_RESULT_ERROR);
62
+ }
63
+ private function init(array $conf)
64
+ {
65
+ $this->id = $conf['id'];
66
+ $this->stime = $conf['stime'];
67
+ $this->queue = new WPAdm_Queue($this->id);
68
+ }
69
+ public function getResult()
70
+ {
71
+ if ($this->restore) {
72
+ $this->result->setResult(WPAdm_Result::WPADM_RESULT_SUCCESS);
73
+ $this->result->setError('');
74
+
75
+ WPAdm_Core::log('Start Restore process');
76
+ $n = count($this->md5_info);
77
+ if (in_array('db', $this->params['types'])) {
78
+
79
+ }
80
+ if (in_array('files', $this->params['types']) ) {
81
+ foreach($this->files_resotre as $key => $file) {
82
+ if (file_exists($file)) {
83
+ $commandContext = new WPAdm_Command_Context();
84
+ $commandContext ->addParam('command', 'restore_backup')
85
+ ->addParam('zip_file', $file );
86
+ $this->queue->clear()
87
+ ->add($commandContext)->save()
88
+ ->execute();
89
+ unset($commandContext);
90
+ }
91
+ }
92
+ }
93
+ if (in_array('db', $this->params['types'])) {
94
+ $this->getWpMysqlParams();
95
+ for($i = 0; $i < $n; $i++) {
96
+ if (strpos($this->md5_info[$i], "mysqldump.sql") !== false ) {
97
+ $data = explode("\t", $this->md5_info[$i]);
98
+ if (isset($this->files_resotre[$data[2]]) && file_exists($this->files_resotre[$data[2]])) {
99
+ $commandContext = new WPAdm_Command_Context();
100
+ $commandContext ->addParam('command', 'restore_backup')
101
+ ->addParam('file', $data[0])
102
+ ->addParam('zip_file', $this->files_resotre[$data[2]] );
103
+ $commandContext->addParam('db_password', $this->db_data['password'])->
104
+ addParam('db_name', $this->db_data['db'])->
105
+ addParam('db_user', $this->db_data['user'])->
106
+ addParam('db_host', $this->db_data['host']);
107
+ $this->queue->clear()
108
+ ->add($commandContext)->save()
109
+ ->execute();
110
+ unset($commandContext);
111
+ } else {
112
+ $this->setError('File(' . $data[2] . ') not Exist');
113
+ WPAdm_Core::log('File(' . $data[2] . ') not Exist');
114
+ break;
115
+ }
116
+ }
117
+ }
118
+ }
119
+ } else {
120
+ WPAdm_Core::log('Files to restore is empty');
121
+ }
122
+ return $this->result;
123
+ }
124
+ private function getWpMysqlParams()
125
+ {
126
+ $db_params = array(
127
+ 'password' => 'DB_PASSWORD',
128
+ 'db' => 'DB_NAME',
129
+ 'user' => 'DB_USER',
130
+ 'host' => 'DB_HOST',
131
+ );
132
+
133
+ $r = "/define\('(.*)', '(.*)'\)/";
134
+ preg_match_all($r, file_get_contents(ABSPATH . "wp-config.php"), $m);
135
+ $params = array_combine($m[1], $m[2]);
136
+ foreach($db_params as $k=>$p) {
137
+ $db_params[$k] = $params[$p];
138
+ }
139
+ $this->db_data = $db_params;
140
+ }
141
+ }
142
+ }
methods/class-wpadm-method-ping.php ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if (!class_exists('WPAdm_Method_Ping')) {
4
+ class WPAdm_Method_Ping extends WPAdm_Method_Class {
5
+ public function getResult()
6
+ {
7
+ global $wp_version;
8
+ $this->result->setResult(WPAdm_result::WPADM_RESULT_SUCCESS);
9
+ if ( ! function_exists( 'get_plugins' ) ) {
10
+ require_once ABSPATH . 'wp-admin/includes/plugin.php';
11
+ }
12
+ $plugin_name = array_pop( explode("/", WPAdm_Core::getPluginDir()) );
13
+ $plugin_name2 = str_replace("-", "_", $plugin_name);
14
+ $plugin = get_plugins("/$plugin_name");
15
+ $pl_version = "";
16
+ if (isset($plugin["$plugin_name.php"])) {
17
+ $pl_version = $plugin["$plugin_name.php"]['Version'];
18
+ }
19
+ if (isset($plugin["$plugin_name2.php"])) {
20
+ $pl_version = $plugin["$plugin_name2.php"]['Version'];
21
+ }
22
+
23
+
24
+ $data_return = array(
25
+ 'reply' => 'pong',
26
+ 'date' => array('time_zone' => date('O'), 'time' => time()),
27
+ 'system_version' => $wp_version,
28
+ 'plugin_version' => $pl_version,
29
+ 'system' => 'wordpress'
30
+ );
31
+
32
+
33
+ //get info for minimal requirements
34
+ $data_return['php_version'] = @phpversion();
35
+ $data_return['php_max_execution_time'] = @intval(ini_get('max_execution_time'));
36
+ $data_return['php_memory_limit'] = @ini_get('memory_limit');
37
+ $data_return['php_extensions'] = @implode(',',get_loaded_extensions());
38
+ $data_return['php_disabled_functions'] = @ini_get('disable_functions');
39
+ $data_return['php_max_execution_time_up'] = 0;
40
+ $data_return['php_memory_limit_up'] = 0;
41
+ $data_return['mysql_version'] = '';
42
+ $data_return['suhosin_functions_blacklist'] = '';
43
+ //try set new max time
44
+ $newMaxExecutionTime = 3000;
45
+ @set_time_limit( $newMaxExecutionTime );
46
+ if( @intval(ini_get('max_execution_time')) == $newMaxExecutionTime ){
47
+ $data_return['php_max_execution_time_up'] = 1;
48
+ }
49
+ //try set new memory limit
50
+ $newMemoryLimit = 256;
51
+ @ini_set('memory_limit', $newMemoryLimit.'M');
52
+ if( @intval(ini_get('memory_limit')) == $newMemoryLimit ){
53
+ $data_return['php_memory_limit_up'] = 1;
54
+ }
55
+ //try get mysql version
56
+ $mysqli = new mysqli(DB_HOST, DB_USER, DB_PASSWORD);
57
+ if (!mysqli_connect_errno()) {
58
+ $data_return['mysql_version'] = $mysqli->server_info;
59
+ }
60
+ //check suhosin
61
+ if (extension_loaded('suhosin') ) {
62
+ $data_return['suhosin_functions_blacklist'] = @ini_get('suhosin.executor.func.blacklist');
63
+ }
64
+
65
+ $this->result->setData(
66
+ $data_return
67
+ );
68
+ return $this->result;
69
+ }
70
+ }
71
+ }
methods/class-wpadm-method-queue-controller.php ADDED
@@ -0,0 +1,194 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Выполнение очереди
4
+ * Class WPAdm_Method_Exec
5
+ */
6
+ if (!class_exists('WPAdm_Method_Queue_Controller')) {
7
+ class WPAdm_Method_Queue_Controller extends WPAdm_Method_Class {
8
+
9
+ /**
10
+ * За сколько секунд до окончания выделенного времени завершать работу
11
+ */
12
+ const TIME_DEAD_LINE = 3; //сек
13
+
14
+ /**
15
+ * максимальное число рестартов
16
+ */
17
+ const MAX_COUNT_STEPS = 500;
18
+
19
+
20
+ /**
21
+ * Файл для хранения парметров, между "перезапусками"
22
+ * @var string
23
+ */
24
+ private $queue_file = "";
25
+
26
+ /**
27
+ * Время "запуска" этого метода
28
+ * @var int
29
+ */
30
+ private $stime = '';
31
+
32
+ /**
33
+ * Максимальное допустимая длительность(сек.) выполнения скрипта
34
+ * @var int
35
+ */
36
+ private $max_execution_time = 10;
37
+
38
+ /**
39
+ * Список задач для выполнения
40
+ * @var array of WPAdm_Command_Context
41
+ */
42
+ private $contexts = array();
43
+
44
+ private $step = 1;
45
+
46
+ private $id = '';
47
+
48
+ public function __construct($params) {
49
+ //WPAdm_Core::log("Запуск очереди. Параметры: " . print_r($params, true));
50
+ $this->stime = time();
51
+ parent::__construct($params);
52
+ $this->queue_file = WPAdm_Core::getTmpDir() . '/' . $this->params['id'] . '.queue';
53
+ if (!file_exists($this->queue_file)) {
54
+ $this->log("queue-file not exists: {$this->queue_file}");
55
+ exit;
56
+ }
57
+ //WPAdm_Core::log('Открываем файл очереди ' . $this->queue_file);
58
+ $queue = unserialize(file_get_contents($this->queue_file));
59
+ //WPAdm_Core::log(print_r($queue, true));
60
+ $this->id = $queue['id'];
61
+ $this->step = (isset($queue['step']) && (int)$queue['step'] > 1) ? (int)$queue['step']+1 : 1;
62
+ $this->contexts = $queue['contexts'];
63
+ $this->max_execution_time = ini_get('max_execution_time');
64
+ }
65
+
66
+ public function getResult()
67
+ {
68
+ // пока время не закончилось и есть задачи - выполняем
69
+ while(!$this->timeIsOver() && $context = $this->getNextContext()) {
70
+ $com = $context->get('command');
71
+ $cmd = WPAdm_Command_Factory::getCommand($com);
72
+ if ($cmd === null) {
73
+ $this->result->setError('Command error:' . $com . ': '. 'Command not found: ' . $com);
74
+ $this->result->setResult(WPAdm_Result::WPADM_RESULT_ERROR);
75
+ array_unshift($this->contexts, $context);
76
+ $this->done();
77
+ return $this->result;
78
+ } elseif (!$cmd->execute($context)) {
79
+ $this->result->setError('Command error:' . $com . ': '. $context->getError());
80
+ $this->result->setResult(WPAdm_Result::WPADM_RESULT_ERROR);
81
+ array_unshift($this->contexts, $context);
82
+ $this->done();
83
+ return $this->result;
84
+ } else {
85
+ //
86
+ //WPAdm_Core::log("Команда выполнена: {$com}");
87
+ }
88
+ //продолжаем работу
89
+ }
90
+
91
+ if ($this->step >= self::MAX_COUNT_STEPS) {
92
+ $this->log('max_step: ' . $this->id);
93
+ exit;
94
+ }
95
+ //если еще есть невыполненые задачи - рестаратуем
96
+ if (!empty($this->contexts)) {
97
+ $this->restart();
98
+ }
99
+
100
+ // если все задачи выполнили, то пометим файл
101
+
102
+ $this->result->setResult(WPAdm_Result::WPADM_RESULT_SUCCESS);
103
+ $this->done();
104
+ return $this->result;
105
+ }
106
+
107
+
108
+ private function done() {
109
+ $this->save();
110
+ rename($this->queue_file, $this->queue_file.'.done');
111
+ }
112
+
113
+ /**
114
+ * @return WPAdm_Command_Context|null
115
+ */
116
+ private function getNextContext() {
117
+ if(empty($this->contexts)) {
118
+ return null;
119
+ } else {
120
+ $context = array_shift($this->contexts);
121
+ $this->save();
122
+ }
123
+ return $context;
124
+ }
125
+
126
+ private function restart() {
127
+ $this->log('restart(' . $this->step .'): ' . $this->id);
128
+ $this->step ++;
129
+ $url = get_option('siteurl');
130
+ $pu = parse_url($url);
131
+ $host = $pu['host'];
132
+
133
+ $data = array(
134
+ 'method' => 'queue_controller',
135
+ 'params' => array(
136
+ 'id' => $this->id,
137
+ 'step' => $this->step,
138
+ ),
139
+ 'sign' => '',
140
+
141
+ );
142
+ /**
143
+ *
144
+ * request to itself to predict multitasking
145
+ *
146
+ */
147
+ $socket = fsockopen($host, 80, $errno, $errstr, 30);
148
+
149
+ $dp = explode(DIRECTORY_SEPARATOR,dirname(dirname(__FILE__)));
150
+ $pl = array_pop($dp) . '_';
151
+ // $data = 'wpadm_'.$pl.'request='.base64_encode(serialize($data));
152
+ $data = $pl.'request='.base64_encode(serialize($data));
153
+ fwrite($socket, "POST / HTTP/1.1\r\n");
154
+ fwrite($socket, "Host: {$host}\r\n");
155
+
156
+ fwrite($socket,"Content-type: application/x-www-form-urlencoded\r\n");
157
+ fwrite($socket,"Content-length:".strlen($data)."\r\n");
158
+ fwrite($socket,"Accept:*/*\r\n");
159
+ fwrite($socket,"User-agent:Opera 10.00\r\n");
160
+ fwrite($socket,"Connection:Close\r\n");
161
+ fwrite($socket,"\r\n");
162
+ fwrite($socket,"$data\r\n");
163
+ fwrite($socket,"\r\n");
164
+ sleep(1);
165
+ fclose($socket);
166
+ exit;
167
+ }
168
+
169
+ private function timeIsOver() {
170
+ if ($this->max_execution_time == 0) {
171
+ return false;
172
+ }
173
+ return (time() - $this->stime + self::TIME_DEAD_LINE > $this->max_execution_time);
174
+ }
175
+
176
+ private function save() {
177
+ $file = WPAdm_Core::getTmpDir() . '/' . $this->id. '.queue';
178
+ $txt = serialize(
179
+ array(
180
+ 'id' => $this->id,
181
+ 'step' => $this->step,
182
+ 'contexts' => $this->contexts,
183
+
184
+ )
185
+ );
186
+ file_put_contents($file, $txt);
187
+ return $this;
188
+ }
189
+
190
+ private function log($txt) {
191
+ //WPAdm_Core::log($txt, 'WPAdm_Method_Queue_Controller');
192
+ }
193
+ }
194
+ }
methods/class-wpadm-method-reconnect.php ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if (!class_exists('WPAdm_Method_Reconnect')) {
4
+ class WPAdm_Method_Reconnect extends WPAdm_Method_Class {
5
+ public function getResult()
6
+ {
7
+ // обновить публичный ключ
8
+ update_option('wpadm_pub_key', $this->params['pub_key']);
9
+
10
+ $this->result->setResult(WPAdm_result::WPADM_RESULT_SUCCESS);
11
+ $this->result->setData('');
12
+ return $this->result;
13
+ }
14
+ }
15
+ }
methods/class-wpadm-method-send-to-dropbox.php ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Бэкап сайта
4
+ * Class WPadm_Method_Send_To_Dropbox
5
+ */
6
+ if (!class_exists('WPadm_Method_Send_To_Dropbox')) {
7
+ class WPadm_Method_Send_To_Dropbox extends WPAdm_Method_Class {
8
+ /**
9
+ * @var WPAdm_Queue
10
+ */
11
+ private $queue;
12
+
13
+ private $id;
14
+
15
+ //private $name = '';
16
+
17
+ public function getResult()
18
+ {
19
+ $errors = array();
20
+ $this->id = uniqid('wpadm_method_send_to_dropbox_');
21
+
22
+ $this->result->setResult(WPAdm_Result::WPADM_RESULT_SUCCESS);
23
+ $this->result->setError('');
24
+
25
+ $this->queue = new WPAdm_Queue($this->id);
26
+
27
+ $ad = $this->params['access_details'];
28
+ WPAdm_Core::log('Copying of Files to Dropbox');
29
+ $this->queue->clear();
30
+ $files = $this->params['files'];
31
+ //$this->getResult()->setData($files);
32
+
33
+ $dir = (isset($ad['dir'])) ? $ad['dir'] : '/';
34
+ // Task creating to copy files to Dropbox
35
+ foreach($files as $file) {
36
+ $commandContext = new WPAdm_Command_Context();
37
+ $commandContext->addParam('command', 'send_to_dropbox')
38
+ ->addParam('key', $ad['key'])
39
+ ->addParam('secret', $ad['secret'])
40
+ ->addParam('token', $ad['token'])
41
+ ->addParam('folder_project',$ad['folder'])
42
+ ->addParam('folder', $dir)
43
+ ->addParam('files', ABSPATH . $file);
44
+ $this->queue->add($commandContext);
45
+ unset($commandContext);
46
+ }
47
+ $res = $this->queue->save()
48
+ ->execute();
49
+ if (!$res) {
50
+ WPAdm_Core::log('Dropbox: ' . $this->queue->getError());
51
+ $errors[] = 'Dropbox: '.$this->queue->getError();
52
+ }
53
+ WPAdm_Core::log('End of copying files to Dropbox');
54
+ if (count($errors) > 0) {
55
+ $this->result->setError(implode("\n", $errors));
56
+ $this->result->setResult(WPAdm_Result::WPADM_RESULT_ERROR);
57
+ }
58
+
59
+ return $this->result;
60
+
61
+
62
+ }
63
+
64
+ private function init(array $conf) {
65
+ //todo: нормализация
66
+ $this->id = $conf['id'];
67
+ $this->stime = $conf['stime'];
68
+ $this->queue = new WPAdm_Queue($this->id);
69
+ $this->type = $conf['type'];
70
+ }
71
+ }
72
+ }
methods/class-wpadm-method-update.php ADDED
@@ -0,0 +1,93 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if (!class_exists('WPAdm_Method_Update')) {
4
+ class WPAdm_Method_Update extends WPAdm_Method_Class {
5
+
6
+ private $archive = null;
7
+
8
+ public function getResult()
9
+ {
10
+ $error = array();
11
+ if (isset($this->params['files'])) {
12
+ if (is_array($this->params['files'])) {
13
+ $n = count($this->params['files']);
14
+ for($i = 0; $i < $n; $i++) {
15
+ if ( ( $f = $this->dl($this->params['files'][$i]) ) === false ) {
16
+ $error[] = 'Error to copy file ' . $this->params['files'][$i]['file'];
17
+ } else {
18
+ if ( is_string($f) && $this->unpack($f, $this->params['files'][$i]['to']) === false ) {
19
+ $error[] = 'Error to extract file ' . $f;
20
+ }
21
+ if (file_exists($f)) {
22
+ unlink($f);
23
+ }
24
+ }
25
+ }
26
+ }
27
+ } else {
28
+ $error[] = 'Files is not exist';
29
+ }
30
+ if (count($error) == 0) {
31
+ $this->result->setResult(WPAdm_result::WPADM_RESULT_SUCCESS);
32
+ $this->result->setData('');
33
+ } else {
34
+ $this->result->setError(implode("\n", $error));
35
+ $this->result->setResult(WPAdm_Result::WPADM_RESULT_ERROR);
36
+ }
37
+
38
+ return $this->result;
39
+ }
40
+
41
+ private function dl($file)
42
+ {
43
+
44
+ if (isset($file['unpack']) && $file['unpack'] == 1) {
45
+ $d_ = WPAdm_Core::getTmpDir() . "/update";
46
+ if (! is_dir($d_)) {
47
+ mkdir($d_, 0755);
48
+ }
49
+ $b = uniqid('update_') . '.zip';
50
+
51
+ } elseif (isset($file['unpack']) && $file['unpack'] == 0) {
52
+ $d_ = ABSPATH;
53
+ $b = $file['to'];
54
+ } else {
55
+ $d_ = '';
56
+ $b = $file['to'];
57
+ }
58
+ if (!empty($d_)) {
59
+ $headers = array( 'Authorization' => 'Basic ' . base64_encode( "admin24:admin24" ) );
60
+ $f = wp_remote_get($file['file'], array('headers' => $headers));
61
+ if (isset($f['body']) && !empty($f['body'])) {
62
+ file_put_contents($d_ . "/" . $b, $f['body']);
63
+ if (file_exists($d_ . "/" . $b)) {
64
+ if (isset($file['unpack']) && $file['unpack'] == 1) {
65
+ return $d_ . "/" . $b;
66
+ } else {
67
+ return true;
68
+ }
69
+ }
70
+ }
71
+ }
72
+ return false;
73
+
74
+ }
75
+ private function unpack($f, $to)
76
+ {
77
+ if (strpos($to, ABSPATH) === false) {
78
+ $to = ABSPATH . $to;
79
+ }
80
+ require_once WPAdm_Core::getPluginDir() . '/modules/pclzip.lib.php';
81
+ $this->archive = new PclZip($f);
82
+ $res = $this->archive->extract(PCLZIP_OPT_PATH, WPAdm_Core::getPluginDir(),
83
+ PCLZIP_OPT_REPLACE_NEWER,
84
+ PCLZIP_OPT_REMOVE_PATH, WPAdm_Core::$plugin_name
85
+ );
86
+ if ( $res ) {
87
+ return true;
88
+ }
89
+ WPAdm_Core::log($this->archive->errorInfo(true));
90
+ return false;
91
+ }
92
+ }
93
+ }
methods/index.php ADDED
@@ -0,0 +1 @@
 
1
+ <?php
modules/OAuthSimple.php ADDED
@@ -0,0 +1,532 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * OAuthSimple - A simpler version of OAuth
4
+ *
5
+ * https://github.com/jrconlin/oauthsimple
6
+ *
7
+ * @author jr conlin <src@jrconlin.com>
8
+ * @copyright unitedHeroes.net 2011
9
+ * @version 1.3
10
+ * @license See OAuthSimple_license.txt
11
+ *
12
+ */
13
+
14
+ class OAuthSimple {
15
+ private $_secrets;
16
+ private $_default_signature_method;
17
+ private $_action;
18
+ private $_nonce_chars;
19
+
20
+ /**
21
+ * Constructor
22
+ *
23
+ * @access public
24
+ * @param api_key (String) The API Key (sometimes referred to as the consumer key) This value is usually supplied by the site you wish to use.
25
+ * @param shared_secret (String) The shared secret. This value is also usually provided by the site you wish to use.
26
+ * @return OAuthSimple (Object)
27
+ */
28
+ function __construct ($APIKey = "", $sharedSecret=""){
29
+
30
+ if (!empty($APIKey))
31
+ {
32
+ $this->_secrets['consumer_key'] = $APIKey;
33
+ }
34
+
35
+ if (!empty($sharedSecret))
36
+ {
37
+ $this->_secrets['shared_secret'] = $sharedSecret;
38
+ }
39
+
40
+ $this->_default_signature_method = "HMAC-SHA1";
41
+ $this->_action = "GET";
42
+ $this->_nonce_chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
43
+
44
+ return $this;
45
+ }
46
+
47
+ /**
48
+ * Reset the parameters and URL
49
+ *
50
+ * @access public
51
+ * @return OAuthSimple (Object)
52
+ */
53
+ public function reset() {
54
+ $this->_parameters = Array();
55
+ $this->path = NULL;
56
+ $this->sbs = NULL;
57
+
58
+ return $this;
59
+ }
60
+
61
+ /**
62
+ * Set the parameters either from a hash or a string
63
+ *
64
+ * @access public
65
+ * @param(string, object) List of parameters for the call, this can either be a URI string (e.g. "foo=bar&gorp=banana" or an object/hash)
66
+ * @return OAuthSimple (Object)
67
+ */
68
+ public function setParameters ($parameters=Array()) {
69
+
70
+ if (is_string($parameters))
71
+ {
72
+ $parameters = $this->_parseParameterString($parameters);
73
+ }
74
+ if (empty($this->_parameters))
75
+ {
76
+ $this->_parameters = $parameters;
77
+ }
78
+ else if (!empty($parameters))
79
+ {
80
+ $this->_parameters = array_merge($this->_parameters,$parameters);
81
+ }
82
+ if (empty($this->_parameters['oauth_nonce']))
83
+ {
84
+ $this->_getNonce();
85
+ }
86
+ if (empty($this->_parameters['oauth_timestamp']))
87
+ {
88
+ $this->_getTimeStamp();
89
+ }
90
+ if (empty($this->_parameters['oauth_consumer_key']))
91
+ {
92
+ $this->_getApiKey();
93
+ }
94
+ if (empty($this->_parameters['oauth_token']))
95
+ {
96
+ $this->_getAccessToken();
97
+ }
98
+ if (empty($this->_parameters['oauth_signature_method']))
99
+ {
100
+ $this->setSignatureMethod();
101
+ }
102
+ if (empty($this->_parameters['oauth_version']))
103
+ {
104
+ $this->_parameters['oauth_version']="1.0";
105
+ }
106
+
107
+ return $this;
108
+ }
109
+
110
+ /**
111
+ * Convenience method for setParameters
112
+ *
113
+ * @access public
114
+ * @see setParameters
115
+ */
116
+ public function setQueryString ($parameters)
117
+ {
118
+ return $this->setParameters($parameters);
119
+ }
120
+
121
+ /**
122
+ * Set the target URL (does not include the parameters)
123
+ *
124
+ * @param path (String) the fully qualified URI (excluding query arguments) (e.g "http://example.org/foo")
125
+ * @return OAuthSimple (Object)
126
+ */
127
+ public function setURL ($path)
128
+ {
129
+ if (empty($path))
130
+ {
131
+ throw new OAuthSimpleException('No path specified for OAuthSimple.setURL');
132
+ }
133
+ $this->_path=$path;
134
+
135
+ return $this;
136
+ }
137
+
138
+ /**
139
+ * Convenience method for setURL
140
+ *
141
+ * @param path (String)
142
+ * @see setURL
143
+ */
144
+ public function setPath ($path)
145
+ {
146
+ return $this->_path=$path;
147
+ }
148
+
149
+ /**
150
+ * Set the "action" for the url, (e.g. GET,POST, DELETE, etc.)
151
+ *
152
+ * @param action (String) HTTP Action word.
153
+ * @return OAuthSimple (Object)
154
+ */
155
+ public function setAction ($action)
156
+ {
157
+ if (empty($action))
158
+ {
159
+ $action = 'GET';
160
+ }
161
+ $action = strtoupper($action);
162
+ if (preg_match('/[^A-Z]/',$action))
163
+ {
164
+ throw new OAuthSimpleException('Invalid action specified for OAuthSimple.setAction');
165
+ }
166
+ $this->_action = $action;
167
+
168
+ return $this;
169
+ }
170
+
171
+ /**
172
+ * Set the signatures (as well as validate the ones you have)
173
+ *
174
+ * @param signatures (object) object/hash of the token/signature pairs {api_key:, shared_secret:, oauth_token: oauth_secret:}
175
+ * @return OAuthSimple (Object)
176
+ */
177
+ public function signatures ($signatures)
178
+ {
179
+ if (!empty($signatures) && !is_array($signatures))
180
+ {
181
+ throw new OAuthSimpleException('Must pass dictionary array to OAuthSimple.signatures');
182
+ }
183
+ if (!empty($signatures))
184
+ {
185
+ if (empty($this->_secrets))
186
+ {
187
+ $this->_secrets=Array();
188
+ }
189
+ $this->_secrets=array_merge($this->_secrets,$signatures);
190
+ }
191
+ if (isset($this->_secrets['api_key']))
192
+ {
193
+ $this->_secrets['consumer_key'] = $this->_secrets['api_key'];
194
+ }
195
+ if (isset($this->_secrets['access_token']))
196
+ {
197
+ $this->_secrets['oauth_token'] = $this->_secrets['access_token'];
198
+ }
199
+ if (isset($this->_secrets['access_secret']))
200
+ {
201
+ $this->_secrets['oauth_secret'] = $this->_secrets['access_secret'];
202
+ }
203
+ if (isset($this->_secrets['access_token_secret']))
204
+ {
205
+ $this->_secrets['oauth_secret'] = $this->_secrets['access_token_secret'];
206
+ }
207
+ if (empty($this->_secrets['consumer_key']))
208
+ {
209
+ throw new OAuthSimpleException('Missing required consumer_key in OAuthSimple.signatures');
210
+ }
211
+ if (empty($this->_secrets['shared_secret']))
212
+ {
213
+ throw new OAuthSimpleException('Missing requires shared_secret in OAuthSimple.signatures');
214
+ }
215
+ if (!empty($this->_secrets['oauth_token']) && empty($this->_secrets['oauth_secret']))
216
+ {
217
+ throw new OAuthSimpleException('Missing oauth_secret for supplied oauth_token in OAuthSimple.signatures');
218
+ }
219
+
220
+ return $this;
221
+ }
222
+
223
+ public function setTokensAndSecrets($signatures)
224
+ {
225
+ return $this->signatures($signatures);
226
+ }
227
+
228
+ /**
229
+ * Set the signature method (currently only Plaintext or SHA-MAC1)
230
+ *
231
+ * @param method (String) Method of signing the transaction (only PLAINTEXT and SHA-MAC1 allowed for now)
232
+ * @return OAuthSimple (Object)
233
+ */
234
+ public function setSignatureMethod ($method="")
235
+ {
236
+ if (empty($method))
237
+ {
238
+ $method = $this->_default_signature_method;
239
+ }
240
+ $method = strtoupper($method);
241
+ switch($method)
242
+ {
243
+ case 'PLAINTEXT':
244
+ case 'HMAC-SHA1':
245
+ $this->_parameters['oauth_signature_method']=$method;
246
+ break;
247
+ default:
248
+ throw new OAuthSimpleException ("Unknown signing method $method specified for OAuthSimple.setSignatureMethod");
249
+ break;
250
+ }
251
+
252
+ return $this;
253
+ }
254
+
255
+ /** sign the request
256
+ *
257
+ * note: all arguments are optional, provided you've set them using the
258
+ * other helper functions.
259
+ *
260
+ * @param args (Array) hash of arguments for the call {action, path, parameters (array), method, signatures (array)} all arguments are optional.
261
+ * @return (Array) signed values
262
+ */
263
+ public function sign($args=array())
264
+ {
265
+ if (!empty($args['action']))
266
+ {
267
+ $this->setAction($args['action']);
268
+ }
269
+ if (!empty($args['path']))
270
+ {
271
+ $this->setPath($args['path']);
272
+ }
273
+ if (!empty($args['method']))
274
+ {
275
+ $this->setSignatureMethod($args['method']);
276
+ }
277
+ if (!empty($args['signatures']))
278
+ {
279
+ $this->signatures($args['signatures']);
280
+ }
281
+ if (empty($args['parameters']))
282
+ {
283
+ $args['parameters']=array();
284
+ }
285
+ $this->setParameters($args['parameters']);
286
+ $normParams = $this->_normalizedParameters();
287
+ $this->_parameters['oauth_signature'] = $this->_generateSignature($normParams);
288
+
289
+ return Array (
290
+ 'parameters' => $this->_parameters,
291
+ 'signature' => self::_oauthEscape($this->_parameters['oauth_signature']),
292
+ 'signed_url' => $this->_path . '?' . $this->_normalizedParameters(),
293
+ 'header' => $this->getHeaderString(),
294
+ 'sbs'=> $this->sbs
295
+ );
296
+ }
297
+
298
+ /**
299
+ * Return a formatted "header" string
300
+ *
301
+ * NOTE: This doesn't set the "Authorization: " prefix, which is required.
302
+ * It's not set because various set header functions prefer different
303
+ * ways to do that.
304
+ *
305
+ * @param args (Array)
306
+ * @return $result (String)
307
+ */
308
+ public function getHeaderString ($args=array())
309
+ {
310
+ if (empty($this->_parameters['oauth_signature']))
311
+ {
312
+ $this->sign($args);
313
+ }
314
+ $result = 'OAuth ';
315
+
316
+ foreach ($this->_parameters as $pName => $pValue)
317
+ {
318
+ if (strpos($pName,'oauth_') !== 0 || $pName == 'oauth_token_secret2')
319
+ {
320
+ continue;
321
+ }
322
+ if (is_array($pValue))
323
+ {
324
+ foreach ($pValue as $val)
325
+ {
326
+ $result .= $pName .'="' . self::_oauthEscape($val) . '", ';
327
+ }
328
+ }
329
+ else
330
+ {
331
+ $result .= $pName . '="' . self::_oauthEscape($pValue) . '", ';
332
+ }
333
+ }
334
+
335
+ return preg_replace('/, $/','',$result);
336
+ }
337
+
338
+ private function _parseParameterString ($paramString)
339
+ {
340
+ $elements = explode('&',$paramString);
341
+ $result = array();
342
+ foreach ($elements as $element)
343
+ {
344
+ list ($key,$token) = explode('=',$element);
345
+ if ($token)
346
+ {
347
+ $token = urldecode($token);
348
+ }
349
+ if (!empty($result[$key]))
350
+ {
351
+ if (!is_array($result[$key]))
352
+ {
353
+ $result[$key] = array($result[$key],$token);
354
+ }
355
+ else
356
+ {
357
+ array_push($result[$key],$token);
358
+ }
359
+ }
360
+ else
361
+ $result[$key]=$token;
362
+ }
363
+ return $result;
364
+ }
365
+
366
+
367
+ private static function _oauthEscape($string)
368
+ {
369
+ if ($string === 0) { return 0; }
370
+ if ($string == '0') { return '0'; }
371
+ if (strlen($string) == 0) { return ''; }
372
+ if (is_array($string)) {
373
+ throw new OAuthSimpleException('Array passed to _oauthEscape');
374
+ }
375
+ $string = rawurlencode($string);
376
+
377
+ $string = str_replace('+','%20',$string);
378
+ $string = str_replace('!','%21',$string);
379
+ $string = str_replace('*','%2A',$string);
380
+ $string = str_replace('\'','%27',$string);
381
+ $string = str_replace('(','%28',$string);
382
+ $string = str_replace(')','%29',$string);
383
+
384
+ return $string;
385
+ }
386
+
387
+ private function _getNonce($length=5)
388
+ {
389
+ $result = '';
390
+ $cLength = strlen($this->_nonce_chars);
391
+ for ($i=0; $i < $length; $i++)
392
+ {
393
+ $rnum = rand(0,$cLength);
394
+ $result .= substr($this->_nonce_chars,$rnum,1);
395
+ }
396
+ $result = md5($result);
397
+ $this->_parameters['oauth_nonce'] = $result;
398
+
399
+ return $result;
400
+ }
401
+
402
+ private function _getApiKey()
403
+ {
404
+ if (empty($this->_secrets['consumer_key']))
405
+ {
406
+ throw new OAuthSimpleException('No consumer_key set for OAuthSimple');
407
+ }
408
+ $this->_parameters['oauth_consumer_key']=$this->_secrets['consumer_key'];
409
+
410
+ return $this->_parameters['oauth_consumer_key'];
411
+ }
412
+
413
+ private function _getAccessToken()
414
+ {
415
+ if (!isset($this->_secrets['oauth_secret']))
416
+ {
417
+ return '';
418
+ }
419
+ if (!isset($this->_secrets['oauth_token']))
420
+ {
421
+ throw new OAuthSimpleException('No access token (oauth_token) set for OAuthSimple.');
422
+ }
423
+ $this->_parameters['oauth_token'] = $this->_secrets['oauth_token'];
424
+
425
+ return $this->_parameters['oauth_token'];
426
+ }
427
+
428
+ private function _getTimeStamp()
429
+ {
430
+ return $this->_parameters['oauth_timestamp'] = time();
431
+ }
432
+
433
+ private function _normalizedParameters()
434
+ {
435
+ $normalized_keys = array();
436
+ $return_array = array();
437
+
438
+ foreach ( $this->_parameters as $paramName=>$paramValue) {
439
+ if (!preg_match('/\w+_secret/',$paramName) OR (strpos($paramValue, '@') !== 0 && !file_exists(substr($paramValue, 1))) )
440
+ {
441
+ if (is_array($paramValue))
442
+ {
443
+ $normalized_keys[self::_oauthEscape($paramName)] = array();
444
+ foreach($paramValue as $item)
445
+ {
446
+ array_push($normalized_keys[self::_oauthEscape($paramName)], self::_oauthEscape($item));
447
+ }
448
+ }
449
+ else
450
+ {
451
+ $normalized_keys[self::_oauthEscape($paramName)] = self::_oauthEscape($paramValue);
452
+ }
453
+ }
454
+ }
455
+
456
+ ksort($normalized_keys);
457
+
458
+ foreach($normalized_keys as $key=>$val)
459
+ {
460
+ if (is_array($val))
461
+ {
462
+ sort($val);
463
+ foreach($val as $element)
464
+ {
465
+ array_push($return_array, $key . "=" . $element);
466
+ }
467
+ }
468
+ else
469
+ {
470
+ array_push($return_array, $key .'='. $val);
471
+ }
472
+
473
+ }
474
+
475
+ return join("&", $return_array);
476
+ }
477
+
478
+
479
+ private function _generateSignature ()
480
+ {
481
+ $secretKey = '';
482
+ if(isset($this->_secrets['shared_secret']))
483
+ {
484
+ $secretKey = self::_oauthEscape($this->_secrets['shared_secret']);
485
+ }
486
+
487
+ $secretKey .= '&';
488
+ if(isset($this->_secrets['oauth_secret']))
489
+ {
490
+ $secretKey .= self::_oauthEscape($this->_secrets['oauth_secret']);
491
+ }
492
+
493
+ switch($this->_parameters['oauth_signature_method'])
494
+ {
495
+ case 'PLAINTEXT':
496
+ return urlencode($secretKey);;
497
+ case 'HMAC-SHA1':
498
+ $this->sbs = self::_oauthEscape($this->_action).'&'.self::_oauthEscape($this->_path).'&'.self::_oauthEscape($this->_normalizedParameters());
499
+
500
+ return base64_encode(hash_hmac('sha1',$this->sbs,$secretKey,TRUE));
501
+ default:
502
+ throw new OAuthSimpleException('Unknown signature method for OAuthSimple');
503
+ break;
504
+ }
505
+ }
506
+ }
507
+
508
+ class OAuthSimpleException extends Exception {
509
+
510
+ public function __construct($err, $isDebug = FALSE)
511
+ {
512
+ self::log_error($err);
513
+ if ($isDebug)
514
+ {
515
+ self::display_error($err, TRUE);
516
+ }
517
+ }
518
+
519
+ public static function log_error($err)
520
+ {
521
+ error_log($err, 0);
522
+ }
523
+
524
+ public static function display_error($err, $kill = FALSE)
525
+ {
526
+ print_r($err);
527
+ if ($kill === FALSE)
528
+ {
529
+ die();
530
+ }
531
+ }
532
+ }
modules/class-wpadm-archive.php ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once dirname(__FILE__) . '/pclzip.lib.php';
3
+ if (!class_exists('WPAdm_Archive')) {
4
+ class WPAdm_Archive {
5
+ private $remove_path = '';
6
+ private $files = array();
7
+ /**
8
+ * @var PclZip
9
+ */
10
+ private $archive;
11
+ private $md5_file = '';
12
+
13
+ public function __construct($file, $md5_file = '') {
14
+ $this->archive = new PclZip($file);
15
+ $this->files[] = $file;
16
+ $this->md5_file = $md5_file;
17
+ }
18
+
19
+ public function add($file) {
20
+ if (empty($this->remove_path)) {
21
+ $this->archive->add($file);
22
+ } else {
23
+ $this->archive->add($file, PCLZIP_OPT_REMOVE_PATH, $this->remove_path);
24
+ }
25
+ $this->saveMd5($file);
26
+ }
27
+
28
+ protected function saveMd5($file) {
29
+ if ($this->md5_file) {
30
+ $files = explode(',', $file); {
31
+ foreach($files as $f) {
32
+ file_put_contents($this->md5_file, $f . "\t" . md5_file($f) . "\t" . basename($this->archive->zipname) . "\n", FILE_APPEND);
33
+ }
34
+ }
35
+ }
36
+ }
37
+
38
+ public function setRemovePath($remove_path) {
39
+ $this->remove_path = $remove_path;
40
+ }
41
+ }
42
+ }
modules/class-wpadm-command-context.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if (!class_exists('WPAdm_Command_Context')) {
3
+ class WPAdm_Command_Context {
4
+ private $params = array();
5
+ private $error = '';
6
+
7
+ public function addParam($key, $val)
8
+ {
9
+ $this->params[$key] = $val;
10
+ return $this;
11
+ }
12
+
13
+ public function get($key)
14
+ {
15
+ return $this->params[$key];
16
+ }
17
+
18
+ public function setError($error)
19
+ {
20
+ $this->error = $error;
21
+ return $this;
22
+ }
23
+
24
+ public function getError() {
25
+ return $this->error;
26
+ }
27
+ }
28
+ }
modules/class-wpadm-command-factory.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Class WPAdm_Command_Factory
4
+ */
5
+ if (!class_exists('WPAdm_Command_Factory')) {
6
+ class WPAdm_Command_Factory {
7
+ /**
8
+ * @param string $com
9
+ * @return command
10
+ */
11
+ static function getCommand($com = '') {
12
+ if (!preg_match("|[a-zA-Z0-9_]|", $com)) {
13
+ return null;
14
+ }
15
+
16
+ $com = mb_strtolower($com);
17
+ $tmp = explode('_', $com);
18
+ $class_file = WPAdm_Core::getPluginDir() . "/commands/class-wpadm-command-" . str_replace('_', '-', $com) . ".php";
19
+
20
+ if (file_exists($class_file)) {
21
+ require_once $class_file;
22
+ foreach($tmp as $k=>$v) {
23
+ $tmp[$k] = ucfirst($v);
24
+ }
25
+ $com = implode('_', $tmp);
26
+
27
+ $class_name = "WPAdm_Command_{$com}";
28
+ return new $class_name();
29
+ }
30
+
31
+ return null;
32
+ }
33
+ }
34
+ }
modules/class-wpadm-mysqldump.php ADDED
@@ -0,0 +1,251 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if (!class_exists('WPAdm_Mysqldump')) {
3
+ class WPAdm_Mysqldump {
4
+
5
+ public $charset;
6
+ public $collate;
7
+
8
+ public $host = '';
9
+ public $user = '';
10
+ public $password = '';
11
+ public $dbh ;
12
+
13
+ private function connect($db = '') {
14
+ WPAdm_Core::log("----------------------------------------------------");
15
+ WPAdm_Core::log("Connecting to MySQL...");
16
+ if ($db) {
17
+ $link = mysqli_connect($this->host, $this->user, $this->password, $db);
18
+ } else {
19
+ $link = mysqli_connect($this->host, $this->user, $this->password);
20
+ }
21
+ if (mysqli_connect_errno()) {
22
+ $this->setError('MySQL Connect failed: ' . mysqli_connect_error());
23
+ }
24
+ $this->dbh = $link;
25
+ $this->init_charset($link);
26
+ $this->set_charset($link);
27
+ return $link;
28
+
29
+ }
30
+
31
+ public function set_charset( $link, $charset = null, $collate = null ) {
32
+ if ( ! isset( $charset ) )
33
+ $charset = $this->charset;
34
+ if ( ! isset( $collate ) )
35
+ $collate = $this->collate;
36
+ WPAdm_Core::log("MySQL set Charset $charset");
37
+ if (! empty( $charset ) ) {
38
+ if ( function_exists( 'mysqli_set_charset' )) {
39
+ mysqli_set_charset( $link, $charset );
40
+ } else {
41
+ $query = $this->prepare( 'SET NAMES %s', $charset );
42
+ if ( ! empty( $collate ) )
43
+ $query .= $this->prepare( ' COLLATE %s', $collate );
44
+ mysqli_query( $link, $query );
45
+ }
46
+
47
+ }
48
+ }
49
+ public function init_charset($link)
50
+ {
51
+ if ( function_exists('is_multisite') && is_multisite() ) {
52
+ $this->charset = 'utf8';
53
+ if ( defined( 'DB_COLLATE' ) && DB_COLLATE ) {
54
+ $this->collate = DB_COLLATE;
55
+ } else {
56
+ $this->collate = 'utf8_general_ci';
57
+ }
58
+ } elseif ( defined( 'DB_COLLATE' ) ) {
59
+ $this->collate = DB_COLLATE;
60
+ }
61
+
62
+ if ( defined( 'DB_CHARSET' ) ) {
63
+ $this->charset = DB_CHARSET;
64
+ }
65
+
66
+ if ( ( ! ( $link instanceof mysqli ) )
67
+ || ( empty( $link ) || ! ( $link instanceof mysqli ) ) ) {
68
+ return;
69
+ }
70
+
71
+ if ( 'utf8' === $this->charset && $this->has_cap( 'utf8mb4' ) ) {
72
+ $this->charset = 'utf8mb4';
73
+ }
74
+
75
+ if ( 'utf8mb4' === $this->charset && ( ! $this->collate || stripos( $this->collate, 'utf8_' ) === 0 ) ) {
76
+ $this->collate = 'utf8mb4_unicode_ci';
77
+ }
78
+ }
79
+ public function has_cap( $db_cap ) {
80
+ $version = $this->db_version();
81
+
82
+ switch ( strtolower( $db_cap ) ) {
83
+ case 'collation' : // @since 2.5.0
84
+ case 'group_concat' : // @since 2.7.0
85
+ case 'subqueries' : // @since 2.7.0
86
+ return version_compare( $version, '4.1', '>=' );
87
+ case 'set_charset' :
88
+ return version_compare( $version, '5.0.7', '>=' );
89
+ case 'utf8mb4' : // @since 4.1.0
90
+ if ( version_compare( $version, '5.5.3', '<' ) ) {
91
+ return false;
92
+ }
93
+ $client_version = mysqli_get_client_info();
94
+ if ( false !== strpos( $client_version, 'mysqlnd' ) ) {
95
+ $client_version = preg_replace( '/^\D+([\d.]+).*/', '$1', $client_version );
96
+ return version_compare( $client_version, '5.0.9', '>=' );
97
+ } else {
98
+ return version_compare( $client_version, '5.5.3', '>=' );
99
+ }
100
+ }
101
+
102
+ return false;
103
+ }
104
+ public function db_version() {
105
+
106
+ $server_info = mysqli_get_server_info( $this->dbh );
107
+
108
+ return preg_replace( '/[^0-9.].*/', '', $server_info );
109
+ }
110
+ public function prepare( $query, $args ) {
111
+ if ( is_null( $query ) )
112
+ return;
113
+
114
+ // This is not meant to be foolproof -- but it will catch obviously incorrect usage.
115
+ if ( strpos( $query, '%' ) === false ) {
116
+ _doing_it_wrong( 'wpdb::prepare', sprintf( __( 'The query argument of %s must have a placeholder.' ), 'wpdb::prepare()' ), '3.9' );
117
+ }
118
+
119
+ $args = func_get_args();
120
+ array_shift( $args );
121
+ // If args were passed as an array (as in vsprintf), move them up
122
+ if ( isset( $args[0] ) && is_array($args[0]) )
123
+ $args = $args[0];
124
+ $query = str_replace( "'%s'", '%s', $query ); // in case someone mistakenly already singlequoted it
125
+ $query = str_replace( '"%s"', '%s', $query ); // doublequote unquoting
126
+ $query = preg_replace( '|(?<!%)%f|' , '%F', $query ); // Force floats to be locale unaware
127
+ $query = preg_replace( '|(?<!%)%s|', "'%s'", $query ); // quote the strings, avoiding escaped strings like %%s
128
+ array_walk( $args, array( $this, 'escape_by_ref' ) );
129
+ return @vsprintf( $query, $args );
130
+ }
131
+
132
+ public function optimize($db) {
133
+ $link = $this->connect($db);
134
+ WPAdm_Core::log("Optimize Database Tables was started");
135
+ if (!$result = mysqli_query($link, 'SHOW TABLES')) {
136
+ $this->setError(mysqli_error($link));
137
+ };
138
+ while($row = mysqli_fetch_row($result))
139
+ {
140
+ if (!mysqli_query($link, 'OPTIMIZE TABLE '.$row[0])) {
141
+ $this->setError(mysqli_error($link));
142
+ };
143
+ }
144
+ WPAdm_Core::log("Optimize Database Tables was Finished");
145
+
146
+ }
147
+
148
+ public function mysqldump($db, $filename) {
149
+ $link = $this->connect($db);
150
+ WPAdm_Core::log("MySQL of Dump was started");
151
+ $tables = array();
152
+ if (!$result = mysqli_query($link, 'SHOW TABLES')) {
153
+ $this->setError(mysqli_error($link));
154
+ };
155
+ while($row = mysqli_fetch_row($result))
156
+ {
157
+ $tables[] = $row[0];
158
+ }
159
+
160
+ //cycle through
161
+
162
+ $return = '';
163
+ $charset = mysqli_get_charset($link);
164
+ if (isset($charset->charset)) {
165
+ $return .= "SET NAMES '{$charset->charset}';\n\n";
166
+ WPAdm_Core::log("SET NAMES Database {$charset->charset};");
167
+ }
168
+ foreach($tables as $table)
169
+ {
170
+ WPAdm_Core::log("Add a table {$table} in the database dump");
171
+ mysqli_close($link);
172
+ $link = $this->connect($db);
173
+ if (!$result = mysqli_query($link, 'SELECT * FROM ' . $table)) {
174
+ $this->setError(mysqli_error($link));
175
+ };
176
+ $num_fields = mysqli_num_fields($result);
177
+
178
+ $return.= 'DROP TABLE '.$table.';';
179
+ if (!$ress = mysqli_query($link, 'SHOW CREATE TABLE ' . $table)) {
180
+ $this->setError(mysqli_error($link));
181
+ };
182
+
183
+ $row2 = mysqli_fetch_row($ress);
184
+ $return.= "\n\n".$row2[1].";\n\n";
185
+
186
+ for ($i = 0; $i < $num_fields; $i++)
187
+ {
188
+ while($row = mysqli_fetch_row($result))
189
+ {
190
+ $return.= 'INSERT INTO '.$table.' VALUES(';
191
+ for($j=0; $j<$num_fields; $j++)
192
+ {
193
+ //$row[$j] = mb_convert_encoding($row[$j], 'UTF-8', 'auto');
194
+ $row[$j] = addslashes($row[$j]);
195
+ $row[$j] = str_replace("\n","\\n",$row[$j]);
196
+ if (isset($row[$j])) { $return.= '"'.$row[$j].'"' ; } else { $return.= '""'; }
197
+ if ($j<($num_fields-1)) { $return.= ','; }
198
+ }
199
+ $return.= ");\n";
200
+ }
201
+ }
202
+ $return.="\n\n\n";
203
+ }
204
+
205
+ mysqli_close($link);
206
+ $handle = fopen($filename,'w+');
207
+ fwrite($handle,$return);
208
+ fclose($handle);
209
+ WPAdm_Core::log("MySQL of Dump was finished");
210
+ return true;
211
+ }
212
+
213
+ private function setError($txt)
214
+ {
215
+ //WPAdm_Core::log($txt);
216
+ throw new Exception($txt);
217
+ }
218
+
219
+ public function restore($db, $file)
220
+ {
221
+ $link = $this->connect($db);
222
+ WPAdm_Core::log("Restore Database was started");
223
+ $fo = fopen($file, "r");
224
+ if (!$fo) {
225
+ WPAdm_Core::log("Error in open file dump");
226
+ $this->setError("Error in open file dump");
227
+ return false;
228
+ }
229
+ $sql = "";
230
+ while(false !== ($char = fgetc($fo))) {
231
+ $sql .= $char;
232
+ if ($char == ";") {
233
+ $char_new = fgetc($fo);
234
+ if ($char_new !== false && $char_new != "\n") {
235
+ $sql .= $char_new;
236
+ } else {
237
+ $ress = mysqli_query($link, $sql);
238
+ if (!$ress) {
239
+ $this->setError(mysqli_error($link));
240
+ WPAdm_Core::log("MySQL Error: " . mysqli_error($link));
241
+ break;
242
+ };
243
+ $sql = "";
244
+ }
245
+ }
246
+ }
247
+ WPAdm_Core::log("Restore Database was finished");
248
+ }
249
+ }
250
+ }
251
+
modules/class-wpadm-queue.php ADDED
@@ -0,0 +1,151 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ *
4
+ * Class WPAdm_Queue
5
+ */
6
+ if (!class_exists('WPAdm_Queue')) {
7
+ class WPAdm_Queue {
8
+
9
+ /**
10
+ * sleep, while waiting
11
+ */
12
+ const SLEEP_TIME = 2; //sec
13
+
14
+ /**
15
+ * the maximum number of falling asleep while waiting
16
+ */
17
+ const MAX_COUNT_SLEEPS = 1000;
18
+
19
+
20
+ /**
21
+ * @var array
22
+ */
23
+ private $contexts = array();
24
+
25
+ /**
26
+ * @var WPAdm_queue_status
27
+ */
28
+ private $status;
29
+
30
+ /**
31
+ * @var
32
+ */
33
+ private $id;
34
+
35
+ private $error;
36
+
37
+ public function __construct($id) {
38
+ $this->id = $id;
39
+ }
40
+
41
+ public function add(WPAdm_Command_Context $context) {
42
+ $this->contexts[] = $context;
43
+ return $this;
44
+ }
45
+
46
+ public function clear()
47
+ {
48
+
49
+ $file = WPAdm_Core::getTmpDir() . '/' . $this->id. '.queue';
50
+ if (file_exists($file)) {
51
+ unlink($file);
52
+ }
53
+
54
+ $s = uniqid();
55
+ $this->id = preg_replace("|(.*__).*|", '${1}'.$s, $this->id);
56
+
57
+ $this->contexts = array();
58
+ return $this;
59
+ }
60
+
61
+ public function execute() {
62
+ $url = get_option('siteurl');
63
+ $pu = parse_url($url);
64
+ $host = $pu['host'];
65
+ $path = isset($pu['path']) ? $pu['path'] . "/" : "/" ;
66
+
67
+ //WPAdm_Core::log('execute on host ' . $host);
68
+ $data = array(
69
+ 'method' => 'queue_controller',
70
+ 'params' => array(
71
+ 'id' => $this->id,
72
+ ),
73
+ 'sign' => '',
74
+
75
+ );
76
+
77
+ if (function_exists('fsockopen')) {
78
+ $socket = @fsockopen($host, 80, $errno, $errstr, 30);
79
+ $dp = explode(DIRECTORY_SEPARATOR, WPAdm_Core::$pl_dir );
80
+ $pl = array_pop($dp) . '_';
81
+ $data = $pl . 'request='.base64_encode(serialize($data));
82
+ if (!$socket) {
83
+ //WPAdm_Core::log( "$errstr ($errno) " , "socket");
84
+ $curl = curl_init($url . "/");
85
+ curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
86
+ curl_setopt($curl, CURLOPT_POST, true);
87
+ curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
88
+ curl_setopt($curl, CURLOPT_TIMEOUT, 10);
89
+ $res = curl_exec($curl);
90
+ curl_close($curl);
91
+ return $this->wait_result();
92
+ }
93
+
94
+ fwrite($socket, "POST {$path} HTTP/1.1\r\n");
95
+ fwrite($socket, "Host: {$host}\r\n");
96
+
97
+ fwrite($socket,"Content-type: application/x-www-form-urlencoded\r\n");
98
+ fwrite($socket,"Content-length:".strlen($data)."\r\n");
99
+ fwrite($socket,"Accept:*/*\r\n");
100
+ fwrite($socket,"User-agent:Opera 10.00\r\n");
101
+ fwrite($socket,"Connection:Close\r\n");
102
+ fwrite($socket,"\r\n");
103
+ fwrite($socket,"$data\r\n");
104
+ fwrite($socket,"\r\n");
105
+
106
+ @sleep(1);
107
+ fclose($socket);
108
+ }
109
+ return $this->wait_result();
110
+ }
111
+
112
+ private function wait_result() {
113
+ $step = 0;
114
+ $done_file = WPAdm_Core::getTmpDir() . '/' . $this->id. '.queue.done';
115
+ while (!file_exists($done_file) && $step <= self::MAX_COUNT_SLEEPS) {
116
+ $step ++;
117
+ @sleep(self::SLEEP_TIME);
118
+ }
119
+ if (!file_exists($done_file)) {
120
+ $this->error = 'No result of the command';
121
+ return false;
122
+ } else {
123
+ $queue = unserialize(file_get_contents($done_file));
124
+ if (isset($queue['contexts'][0])) {
125
+ $this->error = $queue['contexts'][0]->getError();
126
+ return false;
127
+ }
128
+ }
129
+ if (file_exists($done_file)) {
130
+ unlink($done_file);
131
+ }
132
+ return true;
133
+ }
134
+
135
+ public function save() {
136
+ $file = WPAdm_Core::getTmpDir() . '/' . $this->id. '.queue';
137
+ $txt = serialize(
138
+ array(
139
+ 'id' => $this->id,
140
+ 'contexts' => $this->contexts,
141
+ )
142
+ );
143
+ file_put_contents($file, $txt);
144
+ return $this;
145
+ }
146
+
147
+ public function getError() {
148
+ return $this->error;
149
+ }
150
+ }
151
+ }
modules/dropbox.class.php ADDED
@@ -0,0 +1,512 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ error_reporting(E_ALL ^E_NOTICE ^E_WARNING);
3
+
4
+ require dirname(__FILE__)."/OAuthSimple.php";
5
+
6
+ class dropbox
7
+ {
8
+ private $app_key;
9
+ private $app_secret;
10
+ private $token;
11
+
12
+ private $max_filesize_mb = 150;
13
+ private $chunk_size_mb = 50;
14
+ private $request_token;
15
+
16
+ private $api_url = "https://api.dropbox.com/1/";
17
+ private $api_url_content = "https://api-content.dropbox.com/1/";
18
+
19
+
20
+ /**
21
+ * @param $app_key
22
+ * @param $app_secret
23
+ * @param string $token - постоянный токен
24
+ */
25
+ public function __construct ($app_key, $app_secret, $token = "")
26
+ {
27
+ $this->app_key = $app_key;
28
+ $this->app_secret = $app_secret;
29
+ $this->token = $token;
30
+ }
31
+
32
+ /**
33
+ * Проверка на то, был ли получен постоянный токен
34
+ *
35
+ * @return bool
36
+ */
37
+ public function isAuth()
38
+ {
39
+ return !empty($this->token);
40
+ }
41
+
42
+ /**
43
+ * Получение временного токена, необходимого для авторизации и получения токена постоянного
44
+ *
45
+ * @return mixed
46
+ */
47
+ public function getRequestToken()
48
+ {
49
+ if (!$this->request_token) {
50
+ $q = $this->doCurl($this->api_url."oauth/request_token");
51
+ parse_str($q, $data_url);
52
+ $this->request_token = $data_url;
53
+ }
54
+
55
+ return $this->request_token;
56
+ }
57
+
58
+ /**
59
+ * Авторизация, шаг1: Генерация ссылки для авторизации приложения
60
+ *
61
+ * @param $callback - URL для возвращения токена после авторизации
62
+ * @return string
63
+ */
64
+ public function generateAuthUrl($callback)
65
+ {
66
+ $request_token = $this->getRequestToken();
67
+
68
+ return "https://www.dropbox.com/1/oauth/authorize?oauth_token=".$request_token['oauth_token']."&oauth_callback=".urlencode($callback);
69
+ }
70
+
71
+
72
+ /**
73
+ * Получение токена, необходимого для запросов к API
74
+ *
75
+ * @param $request_token - временный токен, полученный функцией getRequestToken
76
+ * @return string токен
77
+ */
78
+ public function getAccessToken($request_token)
79
+ {
80
+ if (!empty($this->token)) {
81
+ return $this->token;
82
+ }
83
+
84
+ $this->request_token = $request_token;
85
+
86
+ parse_str($this->doCurl($this->api_url."oauth/access_token"), $parsed_str);
87
+
88
+ return $parsed_str;
89
+ }
90
+
91
+ /**
92
+ * Удаление файла
93
+ *
94
+ * @param $file
95
+ * @return mixed
96
+ */
97
+ public function deleteFile($file)
98
+ {
99
+ return $this->doApi("fileops/delete", "POST", array(
100
+ "path" => $file,
101
+ "root" => "auto"
102
+ ));
103
+ }
104
+
105
+ /**
106
+ * Удаление нескольких файлов
107
+ *
108
+ * @param array $files
109
+ * @return array
110
+ */
111
+ public function deleteFiles($files = array())
112
+ {
113
+ $result = array();
114
+
115
+ foreach ($files as $file) {
116
+ $do = $this->deleteFile($file);
117
+ $result[] = array (
118
+ "name" => $file,
119
+ "result" => $do['error'] ? 0 : 1
120
+ );
121
+ }
122
+
123
+ return $result;
124
+ }
125
+
126
+ /**
127
+ * Перемещение файлов
128
+ *
129
+ * @param $from - откуда
130
+ * @param $to - куда
131
+ * @return mixed
132
+ */
133
+ public function moveFile ($from, $to)
134
+ {
135
+ return $this->doApi("fileops/move", "POST", array(
136
+ "root" => "auto",
137
+ "from_path" => $from,
138
+ "to_path" => $to
139
+ ));
140
+ }
141
+
142
+ public function listing($path)
143
+ {
144
+ $dir = $this->doApi("metadata/auto/".ltrim($path, "/"), "GET", array(
145
+ "list" => TRUE
146
+ ));
147
+
148
+ if ($dir['error']) {
149
+ return $dir;
150
+ }
151
+ //Это не папка
152
+ elseif (!$dir['is_dir']) {
153
+ return array (
154
+ "size" => $dir['size'],
155
+ "date" => $dir['modified'],
156
+ "name" => $dir['path']
157
+ );
158
+ }
159
+
160
+ $all_size = 0;
161
+ $items = array();
162
+
163
+ foreach ($dir['contents'] as $item) {
164
+ if (!$item['is_dir']) {
165
+ switch (substr($item['size'], -2)) {
166
+ default:
167
+ $size = $item['size'];
168
+ break;
169
+
170
+ case "KB":
171
+ $size = substr($item['size'], 0, -2)*1024;
172
+ break;
173
+
174
+ case "MB":
175
+ $size = substr($item['size'], 0, -2)*1024*1024;
176
+ break;
177
+
178
+ case "GB":
179
+ $size = substr($item['size'], 0, -2)*1024*1024*1024;
180
+ break;
181
+ }
182
+ $all_size += $size;
183
+ }
184
+
185
+ $items[] = array (
186
+ "type" => $item['is_dir'] ? "dir" : "file",
187
+ "date" => $item['modified'],
188
+ "name" => basename($item['path']),
189
+ "size" => $item['size']
190
+ );
191
+ }
192
+
193
+ $dir_result = array (
194
+ "size" => $this->bite2other($all_size),
195
+ "date" => $dir['modified'],
196
+ "name" => $dir['path'],
197
+ "items" => $items
198
+ );
199
+
200
+ return $dir_result;
201
+ }
202
+
203
+ private function bite2other($size)
204
+ {
205
+ $kb = 1024;
206
+ $mb = 1024 * $kb;
207
+ $gb = 1024 * $mb;
208
+ $tb = 1024 * $gb;
209
+
210
+ if ($size < $kb) {
211
+ return $size.' B';
212
+ } else if ($size < $mb) {
213
+ return round($size / $kb, 2).' KB';
214
+ } else if ($size < $gb) {
215
+ return round($size / $mb, 2).' MB';
216
+ } else if ($size < $tb) {
217
+ return round($size / $gb, 2).' GB';
218
+ } else {
219
+ return round($size / $tb, 2).' TB';
220
+ }
221
+ }
222
+
223
+ /**
224
+ * Скачивание файла
225
+ *
226
+ * @param $file
227
+ * @param $server_path - путь, куда скачать на сервер. Если задан -- вернет путь к файлу в случае успешной загрузки.
228
+ * @return array
229
+ */
230
+ public function downloadFile($file, $server_path = "")
231
+ {
232
+ $isset = $this->listing($file);
233
+
234
+ if (!$isset['error'])
235
+ {
236
+ //Отдаем в браузер
237
+ if (empty($server_path)) {
238
+ header("Pragma: public");
239
+ header("Expires: 0");
240
+ header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
241
+ header("Cache-Control: private", false);
242
+ header("Content-Type: application/force-download");
243
+ header('Content-Disposition: attachment; filename="'.$file.'"');
244
+ header("Content-Transfer-Encoding: binary");
245
+
246
+ $this->doApi("files/auto/".ltrim($file, "/"), "GET", array(), array(
247
+ CURLOPT_BINARYTRANSFER => 1,
248
+ CURLOPT_RETURNTRANSFER => 0,
249
+ ), TRUE);
250
+ exit;
251
+ }
252
+ //Скачиваем на сервер
253
+ else {
254
+ //Файл недоступен для записи
255
+ if (!$fd = fopen($server_path, "wb")) {
256
+ return array (
257
+ "error" => 1,
258
+ "text" => "File '".$server_path."' not writable"
259
+ );
260
+ }
261
+
262
+ $this->doApi("files/auto/".ltrim($file, "/"), "GET", array(), array(
263
+ CURLOPT_BINARYTRANSFER => 1,
264
+ CURLOPT_RETURNTRANSFER => 1,
265
+ CURLOPT_FILE => $fd
266
+ ), TRUE);
267
+
268
+ fclose($fd);
269
+
270
+ return $server_path;
271
+ }
272
+
273
+ }
274
+ else {
275
+ return $isset;
276
+ }
277
+ }
278
+
279
+ /**
280
+ * Поделиться файлом
281
+ *
282
+ * @param $file
283
+ * @param bool $short_url - короткая ссылка
284
+ * @return mixed
285
+ */
286
+ public function shareFile($file, $short_url = TRUE)
287
+ {
288
+ $result = $this->doApi("shares/auto/".ltrim($file, "/"), "POST", compact("short_url"));
289
+ return $result['error'] ? $result : $result['url'];
290
+ }
291
+
292
+ /**
293
+ * Загрузка нескольких файлов
294
+ *
295
+ * @param $files - массив формата файл_на_сервере => файл_в_дропбоксе
296
+ *
297
+ * @return array - информация о списке файлов
298
+ */
299
+ public function uploadFiles($files = array())
300
+ {
301
+ $result = array();
302
+
303
+ foreach ($files as $file => $dbx) {
304
+ $do = $this->uploadFile($file, $dbx);
305
+ $result[] = array (
306
+ "name" => $file,
307
+ "result" => $do['error'] ? 0 : 1
308
+ );
309
+ }
310
+
311
+ return $result;
312
+ }
313
+
314
+ /**
315
+ * Загрузка файла
316
+ *
317
+ * @param $file_path - путь к файлу на сервере
318
+ * @param $dropbox_path - куда загружать, если не задан, будет загружен в корень дропбокса с таким же именем
319
+ * @param bool $overwrite - заменять ли файлы со схожими именами
320
+ * @return mixed
321
+ */
322
+ public function uploadFile($file_path, $dropbox_path = "", $overwrite = FALSE)
323
+ {
324
+ if (empty($dropbox_path)) {
325
+ $dropbox_path = basename($file_path);
326
+ }
327
+
328
+ if (!is_file($file_path)) {
329
+ return array(
330
+ "error" => 1,
331
+ "text" => "File '".$file_path."' not found."
332
+ );
333
+ }
334
+
335
+ $fsize = filesize($file_path);
336
+ $file = fopen($file_path, "rb");
337
+
338
+ if ($fsize/1024/1024 < $this->max_filesize_mb)
339
+ {
340
+ $result = $this->doApi("files_put/auto/".ltrim($dropbox_path, "/"),
341
+ "PUT",
342
+ compact ("overwrite"),
343
+ array(
344
+ CURLOPT_INFILE => $file,
345
+ CURLOPT_INFILESIZE => filesize($file_path),
346
+ CURLOPT_BINARYTRANSFER => 1,
347
+ CURLOPT_PUT => 1
348
+ ),
349
+ TRUE);
350
+
351
+ }
352
+ //Файл слишком велик
353
+ else {
354
+ $upload_id = "";
355
+ $offset = 0;
356
+
357
+ while(!feof($file)) {
358
+
359
+ $chunk = min($fsize-$offset, $this->chunk_size_mb);
360
+ $offset += $chunk;
361
+
362
+ $result = $this->doApi("chunked_upload",
363
+ "PUT",
364
+ compact("upload_id", "offset"),
365
+ array(
366
+ CURLOPT_INFILE => $file,
367
+ CURLOPT_INFILESIZE => $chunk,
368
+ CURLOPT_BINARYTRANSFER => 1,
369
+ CURLOPT_PUT => 1
370
+ ),
371
+ TRUE);
372
+
373
+ fseek($file, $offset);
374
+ if($offset >= $fsize) {
375
+ break;
376
+ }
377
+
378
+ if (empty($upload_id)) {
379
+ $upload_id = $result['upload_id'];
380
+ }
381
+ }
382
+
383
+ $result = $this->doApi("commit_chunked_upload/auto/".ltrim($dropbox_path, "/"),
384
+ "POST",
385
+ compact("upload_id", "overwrite"),
386
+ array(),
387
+ TRUE);
388
+ }
389
+
390
+ @fclose($file);
391
+
392
+ return $result;
393
+ }
394
+
395
+ /**
396
+ * Создание директории
397
+ *
398
+ * @param $path
399
+ * @return mixed
400
+ */
401
+ public function createDir($path)
402
+ {
403
+ return $this->doApi("fileops/create_folder", "POST", array(
404
+ "root" => "auto",
405
+ "path" => $path
406
+ ));
407
+ }
408
+
409
+ /**
410
+ * Информация об аккаунте
411
+ *
412
+ * @return mixed
413
+ */
414
+ public function accInfo()
415
+ {
416
+ return $this->doApi("account/info", "GET");
417
+ }
418
+
419
+ /** Запрос к API
420
+ *
421
+ * @param $op - операция (url)
422
+ * @param $method - post/get
423
+ * @param array $data - доп. данные, url запрос
424
+ * @param array $opts - доп. параметры для curl
425
+ * @param $api_content - использовать url для загрузки файлов
426
+ * @return mixed
427
+ */
428
+ private function doApi ($op, $method, $data = array(), $opts = array(), $api_content = FALSE)
429
+ {
430
+ if (($method == "GET" || $method == "PUT") && count($data)) {
431
+ $op .= "?".http_build_query($data);
432
+ }
433
+ $result = $this->doCurl((!$api_content ? $this->api_url : $this->api_url_content).$op, $method, $data, $opts);
434
+ $return = json_decode($result, TRUE);
435
+ return self::checkError($return);
436
+ }
437
+
438
+ /**
439
+ * Обертка для отправки подписанного запроса через curl
440
+ *
441
+ * @param $url
442
+ * @param string $method
443
+ * @param array $data - POST данные
444
+ * @param $opts - доп. параметры для curl
445
+ * @return mixed
446
+ */
447
+ public function doCurl($url, $method = "POST", $data = array(), $opts = array())
448
+ {
449
+ $ch = curl_init($url);
450
+ $opts += array(
451
+ CURLOPT_RETURNTRANSFER => 1,
452
+ CURLOPT_HEADER => 0,
453
+ CURLOPT_SSL_VERIFYPEER => 0,
454
+ CURLOPT_SSL_VERIFYHOST => 0,
455
+ );
456
+
457
+
458
+ if ($method == "POST") {
459
+ $opts[CURLOPT_POST] = TRUE;
460
+ $opts[CURLOPT_POSTFIELDS] = http_build_query($data);
461
+ }
462
+
463
+ $oauth = new OAuthSimple($this->app_key, $this->app_secret);
464
+
465
+ if (!$this->request_token && $this->token) {
466
+ $this->request_token = $this->token;
467
+ }
468
+
469
+ if ($this->request_token) {
470
+ $oauth->setParameters(array('oauth_token' => $this->request_token['oauth_token']));
471
+ $oauth->signatures(array('oauth_secret'=> $this->request_token['oauth_token_secret']));
472
+ }
473
+
474
+ if ($method == "POST" && count($data)) {
475
+ $oauth->setParameters(http_build_query($data));
476
+ }
477
+
478
+ $path = $url;
479
+ $query = strrchr($url,'?');
480
+ if(!empty($query)) {
481
+ $oauth->setParameters(substr($query,1));
482
+ $path = substr($url, 0, -strlen($query));
483
+ }
484
+
485
+ $signed = $oauth->sign(array(
486
+ 'action' => $method,
487
+ 'path' => $path
488
+ )
489
+ );
490
+ $opts[CURLOPT_HTTPHEADER][] = "Authorization: ".$signed['header'];
491
+
492
+ if ($method == "PUT")
493
+ {
494
+ $opts[CURLOPT_CUSTOMREQUEST] = "PUT";
495
+ }
496
+ curl_setopt_array($ch, $opts);
497
+ $result = curl_exec($ch);
498
+
499
+
500
+ return $result;
501
+ }
502
+
503
+
504
+ private static function checkError($return)
505
+ {
506
+ if(!empty($return['error']))
507
+ return array ("error" => 1, "text" => $return['error']);
508
+ return $return;
509
+ }
510
+
511
+
512
+ }
modules/index.php ADDED
@@ -0,0 +1 @@
 
1
+ <?php
modules/pclzip.lib.php ADDED
@@ -0,0 +1,3034 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if (!defined('PCLZIP_READ_BLOCK_SIZE')) {
3
+ define( 'PCLZIP_READ_BLOCK_SIZE', 2048 );
4
+ }
5
+ if (!defined('PCLZIP_SEPARATOR')) {
6
+ define( 'PCLZIP_SEPARATOR', ',' );
7
+ }
8
+ if (!defined('PCLZIP_ERROR_EXTERNAL')) {
9
+ define( 'PCLZIP_ERROR_EXTERNAL', 0 );
10
+ }
11
+ if (!defined('PCLZIP_TEMPORARY_DIR')) {
12
+ define( 'PCLZIP_TEMPORARY_DIR', '' );
13
+ }
14
+ if (!defined('PCLZIP_TEMPORARY_FILE_RATIO')) {
15
+ define( 'PCLZIP_TEMPORARY_FILE_RATIO', 0.47 );
16
+ }
17
+ // --------------------------------------------------------------------------------
18
+ // ***** UNDER THIS LINE NOTHING NEEDS TO BE MODIFIED *****
19
+ // --------------------------------------------------------------------------------
20
+ $g_pclzip_version = "2.8.2";
21
+ define( 'PCLZIP_ERR_USER_ABORTED', 2 );
22
+ define( 'PCLZIP_ERR_NO_ERROR', 0 );
23
+ define( 'PCLZIP_ERR_WRITE_OPEN_FAIL', -1 );
24
+ define( 'PCLZIP_ERR_READ_OPEN_FAIL', -2 );
25
+ define( 'PCLZIP_ERR_INVALID_PARAMETER', -3 );
26
+ define( 'PCLZIP_ERR_MISSING_FILE', -4 );
27
+ define( 'PCLZIP_ERR_FILENAME_TOO_LONG', -5 );
28
+ define( 'PCLZIP_ERR_INVALID_ZIP', -6 );
29
+ define( 'PCLZIP_ERR_BAD_EXTRACTED_FILE', -7 );
30
+ define( 'PCLZIP_ERR_DIR_CREATE_FAIL', -8 );
31
+ define( 'PCLZIP_ERR_BAD_EXTENSION', -9 );
32
+ define( 'PCLZIP_ERR_BAD_FORMAT', -10 );
33
+ define( 'PCLZIP_ERR_DELETE_FILE_FAIL', -11 );
34
+ define( 'PCLZIP_ERR_RENAME_FILE_FAIL', -12 );
35
+ define( 'PCLZIP_ERR_BAD_CHECKSUM', -13 );
36
+ define( 'PCLZIP_ERR_INVALID_ARCHIVE_ZIP', -14 );
37
+ define( 'PCLZIP_ERR_MISSING_OPTION_VALUE', -15 );
38
+ define( 'PCLZIP_ERR_INVALID_OPTION_VALUE', -16 );
39
+ define( 'PCLZIP_ERR_ALREADY_A_DIRECTORY', -17 );
40
+ define( 'PCLZIP_ERR_UNSUPPORTED_COMPRESSION', -18 );
41
+ define( 'PCLZIP_ERR_UNSUPPORTED_ENCRYPTION', -19 );
42
+ define( 'PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE', -20 );
43
+ define( 'PCLZIP_ERR_DIRECTORY_RESTRICTION', -21 );
44
+ define( 'PCLZIP_OPT_PATH', 77001 );
45
+ define( 'PCLZIP_OPT_ADD_PATH', 77002 );
46
+ define( 'PCLZIP_OPT_REMOVE_PATH', 77003 );
47
+ define( 'PCLZIP_OPT_REMOVE_ALL_PATH', 77004 );
48
+ define( 'PCLZIP_OPT_SET_CHMOD', 77005 );
49
+ define( 'PCLZIP_OPT_EXTRACT_AS_STRING', 77006 );
50
+ define( 'PCLZIP_OPT_NO_COMPRESSION', 77007 );
51
+ define( 'PCLZIP_OPT_BY_NAME', 77008 );
52
+ define( 'PCLZIP_OPT_BY_INDEX', 77009 );
53
+ define( 'PCLZIP_OPT_BY_EREG', 77010 );
54
+ define( 'PCLZIP_OPT_BY_PREG', 77011 );
55
+ define( 'PCLZIP_OPT_COMMENT', 77012 );
56
+ define( 'PCLZIP_OPT_ADD_COMMENT', 77013 );
57
+ define( 'PCLZIP_OPT_PREPEND_COMMENT', 77014 );
58
+ define( 'PCLZIP_OPT_EXTRACT_IN_OUTPUT', 77015 );
59
+ define( 'PCLZIP_OPT_REPLACE_NEWER', 77016 );
60
+ define( 'PCLZIP_OPT_STOP_ON_ERROR', 77017 );
61
+ define( 'PCLZIP_OPT_EXTRACT_DIR_RESTRICTION', 77019 );
62
+ define( 'PCLZIP_OPT_TEMP_FILE_THRESHOLD', 77020 );
63
+ define( 'PCLZIP_OPT_ADD_TEMP_FILE_THRESHOLD', 77020 ); // alias
64
+ define( 'PCLZIP_OPT_TEMP_FILE_ON', 77021 );
65
+ define( 'PCLZIP_OPT_ADD_TEMP_FILE_ON', 77021 ); // alias
66
+ define( 'PCLZIP_OPT_TEMP_FILE_OFF', 77022 );
67
+ define( 'PCLZIP_OPT_ADD_TEMP_FILE_OFF', 77022 ); // alias
68
+ define( 'PCLZIP_ATT_FILE_NAME', 79001 );
69
+ define( 'PCLZIP_ATT_FILE_NEW_SHORT_NAME', 79002 );
70
+ define( 'PCLZIP_ATT_FILE_NEW_FULL_NAME', 79003 );
71
+ define( 'PCLZIP_ATT_FILE_MTIME', 79004 );
72
+ define( 'PCLZIP_ATT_FILE_CONTENT', 79005 );
73
+ define( 'PCLZIP_ATT_FILE_COMMENT', 79006 );
74
+ define( 'PCLZIP_CB_PRE_EXTRACT', 78001 );
75
+ define( 'PCLZIP_CB_POST_EXTRACT', 78002 );
76
+ define( 'PCLZIP_CB_PRE_ADD', 78003 );
77
+ define( 'PCLZIP_CB_POST_ADD', 78004 );
78
+ /* For futur use
79
+ define( 'PCLZIP_CB_PRE_LIST', 78005 );
80
+ define( 'PCLZIP_CB_POST_LIST', 78006 );
81
+ define( 'PCLZIP_CB_PRE_DELETE', 78007 );
82
+ define( 'PCLZIP_CB_POST_DELETE', 78008 );
83
+ */
84
+ class PclZip
85
+ {
86
+ var $zipname = '';
87
+ var $zip_fd = 0;
88
+ var $error_code = 1;
89
+ var $error_string = '';
90
+ var $magic_quotes_status;
91
+ function PclZip($p_zipname)
92
+ {
93
+ if (!function_exists('gzopen'))
94
+ {
95
+ die('Abort '.basename(__FILE__).' : Missing zlib extensions');
96
+ }
97
+ $this->zipname = $p_zipname;
98
+ $this->zip_fd = 0;
99
+ $this->magic_quotes_status = -1;
100
+ return;
101
+ }
102
+ function create($p_filelist)
103
+ {
104
+ $v_result=1;
105
+ $this->privErrorReset();
106
+ $v_options = array();
107
+ $v_options[PCLZIP_OPT_NO_COMPRESSION] = FALSE;
108
+ $v_size = func_num_args();
109
+ if ($v_size > 1) {
110
+ $v_arg_list = func_get_args();
111
+ array_shift($v_arg_list);
112
+ $v_size--;
113
+ if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) {
114
+ $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options,
115
+ array (PCLZIP_OPT_REMOVE_PATH => 'optional',
116
+ PCLZIP_OPT_REMOVE_ALL_PATH => 'optional',
117
+ PCLZIP_OPT_ADD_PATH => 'optional',
118
+ PCLZIP_CB_PRE_ADD => 'optional',
119
+ PCLZIP_CB_POST_ADD => 'optional',
120
+ PCLZIP_OPT_NO_COMPRESSION => 'optional',
121
+ PCLZIP_OPT_COMMENT => 'optional',
122
+ PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional',
123
+ PCLZIP_OPT_TEMP_FILE_ON => 'optional',
124
+ PCLZIP_OPT_TEMP_FILE_OFF => 'optional'
125
+ ));
126
+ if ($v_result != 1) {
127
+ return 0;
128
+ }
129
+ }
130
+ else {
131
+ $v_options[PCLZIP_OPT_ADD_PATH] = $v_arg_list[0];
132
+ if ($v_size == 2) {
133
+ $v_options[PCLZIP_OPT_REMOVE_PATH] = $v_arg_list[1];
134
+ }
135
+ else if ($v_size > 2) {
136
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER,
137
+ "Invalid number / type of arguments");
138
+ return 0;
139
+ }
140
+ }
141
+ }
142
+ $this->privOptionDefaultThreshold($v_options);
143
+ $v_string_list = array();
144
+ $v_att_list = array();
145
+ $v_filedescr_list = array();
146
+ $p_result_list = array();
147
+ if (is_array($p_filelist)) {
148
+ if (isset($p_filelist[0]) && is_array($p_filelist[0])) {
149
+ $v_att_list = $p_filelist;
150
+ }
151
+ else {
152
+ $v_string_list = $p_filelist;
153
+ }
154
+ }
155
+ else if (is_string($p_filelist)) {
156
+ $v_string_list = explode(PCLZIP_SEPARATOR, $p_filelist);
157
+ }
158
+ else {
159
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_filelist");
160
+ return 0;
161
+ }
162
+ if (sizeof($v_string_list) != 0) {
163
+ foreach ($v_string_list as $v_string) {
164
+ if ($v_string != '') {
165
+ $v_att_list[][PCLZIP_ATT_FILE_NAME] = $v_string;
166
+ }
167
+ else {
168
+ }
169
+ }
170
+ }
171
+ $v_supported_attributes
172
+ = array ( PCLZIP_ATT_FILE_NAME => 'mandatory'
173
+ ,PCLZIP_ATT_FILE_NEW_SHORT_NAME => 'optional'
174
+ ,PCLZIP_ATT_FILE_NEW_FULL_NAME => 'optional'
175
+ ,PCLZIP_ATT_FILE_MTIME => 'optional'
176
+ ,PCLZIP_ATT_FILE_CONTENT => 'optional'
177
+ ,PCLZIP_ATT_FILE_COMMENT => 'optional'
178
+ );
179
+ foreach ($v_att_list as $v_entry) {
180
+ $v_result = $this->privFileDescrParseAtt($v_entry,
181
+ $v_filedescr_list[],
182
+ $v_options,
183
+ $v_supported_attributes);
184
+ if ($v_result != 1) {
185
+ return 0;
186
+ }
187
+ }
188
+ $v_result = $this->privFileDescrExpand($v_filedescr_list, $v_options);
189
+ if ($v_result != 1) {
190
+ return 0;
191
+ }
192
+ $v_result = $this->privCreate($v_filedescr_list, $p_result_list, $v_options);
193
+ if ($v_result != 1) {
194
+ return 0;
195
+ }
196
+ return $p_result_list;
197
+ }
198
+ function add($p_filelist)
199
+ {
200
+ $v_result=1;
201
+ $this->privErrorReset();
202
+ $v_options = array();
203
+ $v_options[PCLZIP_OPT_NO_COMPRESSION] = FALSE;
204
+ $v_size = func_num_args();
205
+ if ($v_size > 1) {
206
+ $v_arg_list = func_get_args();
207
+ array_shift($v_arg_list);
208
+ $v_size--;
209
+ if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) {
210
+ $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options,
211
+ array (PCLZIP_OPT_REMOVE_PATH => 'optional',
212
+ PCLZIP_OPT_REMOVE_ALL_PATH => 'optional',
213
+ PCLZIP_OPT_ADD_PATH => 'optional',
214
+ PCLZIP_CB_PRE_ADD => 'optional',
215
+ PCLZIP_CB_POST_ADD => 'optional',
216
+ PCLZIP_OPT_NO_COMPRESSION => 'optional',
217
+ PCLZIP_OPT_COMMENT => 'optional',
218
+ PCLZIP_OPT_ADD_COMMENT => 'optional',
219
+ PCLZIP_OPT_PREPEND_COMMENT => 'optional',
220
+ PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional',
221
+ PCLZIP_OPT_TEMP_FILE_ON => 'optional',
222
+ PCLZIP_OPT_TEMP_FILE_OFF => 'optional'
223
+ ));
224
+ if ($v_result != 1) {
225
+ return 0;
226
+ }
227
+ }
228
+ else {
229
+ $v_options[PCLZIP_OPT_ADD_PATH] = $v_add_path = $v_arg_list[0];
230
+ if ($v_size == 2) {
231
+ $v_options[PCLZIP_OPT_REMOVE_PATH] = $v_arg_list[1];
232
+ }
233
+ else if ($v_size > 2) {
234
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments");
235
+ return 0;
236
+ }
237
+ }
238
+ }
239
+ $this->privOptionDefaultThreshold($v_options);
240
+ $v_string_list = array();
241
+ $v_att_list = array();
242
+ $v_filedescr_list = array();
243
+ $p_result_list = array();
244
+ if (is_array($p_filelist)) {
245
+ if (isset($p_filelist[0]) && is_array($p_filelist[0])) {
246
+ $v_att_list = $p_filelist;
247
+ }
248
+ else {
249
+ $v_string_list = $p_filelist;
250
+ }
251
+ }
252
+ else if (is_string($p_filelist)) {
253
+ $v_string_list = explode(PCLZIP_SEPARATOR, $p_filelist);
254
+ }
255
+ else {
256
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type '".gettype($p_filelist)."' for p_filelist");
257
+ return 0;
258
+ }
259
+ if (sizeof($v_string_list) != 0) {
260
+ foreach ($v_string_list as $v_string) {
261
+ $v_att_list[][PCLZIP_ATT_FILE_NAME] = $v_string;
262
+ }
263
+ }
264
+ $v_supported_attributes
265
+ = array ( PCLZIP_ATT_FILE_NAME => 'mandatory'
266
+ ,PCLZIP_ATT_FILE_NEW_SHORT_NAME => 'optional'
267
+ ,PCLZIP_ATT_FILE_NEW_FULL_NAME => 'optional'
268
+ ,PCLZIP_ATT_FILE_MTIME => 'optional'
269
+ ,PCLZIP_ATT_FILE_CONTENT => 'optional'
270
+ ,PCLZIP_ATT_FILE_COMMENT => 'optional'
271
+ );
272
+ foreach ($v_att_list as $v_entry) {
273
+ $v_result = $this->privFileDescrParseAtt($v_entry,
274
+ $v_filedescr_list[],
275
+ $v_options,
276
+ $v_supported_attributes);
277
+ if ($v_result != 1) {
278
+ return 0;
279
+ }
280
+ }
281
+ $v_result = $this->privFileDescrExpand($v_filedescr_list, $v_options);
282
+ if ($v_result != 1) {
283
+ return 0;
284
+ }
285
+ $v_result = $this->privAdd($v_filedescr_list, $p_result_list, $v_options);
286
+ if ($v_result != 1) {
287
+ return 0;
288
+ }
289
+ return $p_result_list;
290
+ }
291
+ function listContent()
292
+ {
293
+ $v_result=1;
294
+ $this->privErrorReset();
295
+ if (!$this->privCheckFormat()) {
296
+ return(0);
297
+ }
298
+ $p_list = array();
299
+ if (($v_result = $this->privList($p_list)) != 1)
300
+ {
301
+ unset($p_list);
302
+ return(0);
303
+ }
304
+ return $p_list;
305
+ }
306
+ function extract()
307
+ {
308
+ $v_result=1;
309
+ $this->privErrorReset();
310
+ if (!$this->privCheckFormat()) {
311
+ return(0);
312
+ }
313
+ $v_options = array();
314
+ // $v_path = "./";
315
+ $v_path = '';
316
+ $v_remove_path = "";
317
+ $v_remove_all_path = false;
318
+ $v_size = func_num_args();
319
+ $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = FALSE;
320
+ if ($v_size > 0) {
321
+ $v_arg_list = func_get_args();
322
+ if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) {
323
+ $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options,
324
+ array (PCLZIP_OPT_PATH => 'optional',
325
+ PCLZIP_OPT_REMOVE_PATH => 'optional',
326
+ PCLZIP_OPT_REMOVE_ALL_PATH => 'optional',
327
+ PCLZIP_OPT_ADD_PATH => 'optional',
328
+ PCLZIP_CB_PRE_EXTRACT => 'optional',
329
+ PCLZIP_CB_POST_EXTRACT => 'optional',
330
+ PCLZIP_OPT_SET_CHMOD => 'optional',
331
+ PCLZIP_OPT_BY_NAME => 'optional',
332
+ PCLZIP_OPT_BY_EREG => 'optional',
333
+ PCLZIP_OPT_BY_PREG => 'optional',
334
+ PCLZIP_OPT_BY_INDEX => 'optional',
335
+ PCLZIP_OPT_EXTRACT_AS_STRING => 'optional',
336
+ PCLZIP_OPT_EXTRACT_IN_OUTPUT => 'optional',
337
+ PCLZIP_OPT_REPLACE_NEWER => 'optional'
338
+ ,PCLZIP_OPT_STOP_ON_ERROR => 'optional'
339
+ ,PCLZIP_OPT_EXTRACT_DIR_RESTRICTION => 'optional',
340
+ PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional',
341
+ PCLZIP_OPT_TEMP_FILE_ON => 'optional',
342
+ PCLZIP_OPT_TEMP_FILE_OFF => 'optional'
343
+ ));
344
+ if ($v_result != 1) {
345
+ return 0;
346
+ }
347
+ if (isset($v_options[PCLZIP_OPT_PATH])) {
348
+ $v_path = $v_options[PCLZIP_OPT_PATH];
349
+ }
350
+ if (isset($v_options[PCLZIP_OPT_REMOVE_PATH])) {
351
+ $v_remove_path = $v_options[PCLZIP_OPT_REMOVE_PATH];
352
+ }
353
+ if (isset($v_options[PCLZIP_OPT_REMOVE_ALL_PATH])) {
354
+ $v_remove_all_path = $v_options[PCLZIP_OPT_REMOVE_ALL_PATH];
355
+ }
356
+ if (isset($v_options[PCLZIP_OPT_ADD_PATH])) {
357
+ if ((strlen($v_path) > 0) && (substr($v_path, -1) != '/')) {
358
+ $v_path .= '/';
359
+ }
360
+ $v_path .= $v_options[PCLZIP_OPT_ADD_PATH];
361
+ }
362
+ }
363
+ else {
364
+ $v_path = $v_arg_list[0];
365
+ if ($v_size == 2) {
366
+ $v_remove_path = $v_arg_list[1];
367
+ }
368
+ else if ($v_size > 2) {
369
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments");
370
+ return 0;
371
+ }
372
+ }
373
+ }
374
+ $this->privOptionDefaultThreshold($v_options);
375
+ $p_list = array();
376
+ $v_result = $this->privExtractByRule($p_list, $v_path, $v_remove_path,
377
+ $v_remove_all_path, $v_options);
378
+ if ($v_result < 1) {
379
+ unset($p_list);
380
+ return(0);
381
+ }
382
+ return $p_list;
383
+ }
384
+ function extractByIndex($p_index)
385
+ {
386
+ $v_result=1;
387
+ $this->privErrorReset();
388
+ if (!$this->privCheckFormat()) {
389
+ return(0);
390
+ }
391
+ $v_options = array();
392
+ // $v_path = "./";
393
+ $v_path = '';
394
+ $v_remove_path = "";
395
+ $v_remove_all_path = false;
396
+ $v_size = func_num_args();
397
+ $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = FALSE;
398
+ if ($v_size > 1) {
399
+ $v_arg_list = func_get_args();
400
+ array_shift($v_arg_list);
401
+ $v_size--;
402
+ if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) {
403
+ $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options,
404
+ array (PCLZIP_OPT_PATH => 'optional',
405
+ PCLZIP_OPT_REMOVE_PATH => 'optional',
406
+ PCLZIP_OPT_REMOVE_ALL_PATH => 'optional',
407
+ PCLZIP_OPT_EXTRACT_AS_STRING => 'optional',
408
+ PCLZIP_OPT_ADD_PATH => 'optional',
409
+ PCLZIP_CB_PRE_EXTRACT => 'optional',
410
+ PCLZIP_CB_POST_EXTRACT => 'optional',
411
+ PCLZIP_OPT_SET_CHMOD => 'optional',
412
+ PCLZIP_OPT_REPLACE_NEWER => 'optional'
413
+ ,PCLZIP_OPT_STOP_ON_ERROR => 'optional'
414
+ ,PCLZIP_OPT_EXTRACT_DIR_RESTRICTION => 'optional',
415
+ PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional',
416
+ PCLZIP_OPT_TEMP_FILE_ON => 'optional',
417
+ PCLZIP_OPT_TEMP_FILE_OFF => 'optional'
418
+ ));
419
+ if ($v_result != 1) {
420
+ return 0;
421
+ }
422
+ if (isset($v_options[PCLZIP_OPT_PATH])) {
423
+ $v_path = $v_options[PCLZIP_OPT_PATH];
424
+ }
425
+ if (isset($v_options[PCLZIP_OPT_REMOVE_PATH])) {
426
+ $v_remove_path = $v_options[PCLZIP_OPT_REMOVE_PATH];
427
+ }
428
+ if (isset($v_options[PCLZIP_OPT_REMOVE_ALL_PATH])) {
429
+ $v_remove_all_path = $v_options[PCLZIP_OPT_REMOVE_ALL_PATH];
430
+ }
431
+ if (isset($v_options[PCLZIP_OPT_ADD_PATH])) {
432
+ if ((strlen($v_path) > 0) && (substr($v_path, -1) != '/')) {
433
+ $v_path .= '/';
434
+ }
435
+ $v_path .= $v_options[PCLZIP_OPT_ADD_PATH];
436
+ }
437
+ if (!isset($v_options[PCLZIP_OPT_EXTRACT_AS_STRING])) {
438
+ $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = FALSE;
439
+ }
440
+ else {
441
+ }
442
+ }
443
+ else {
444
+ $v_path = $v_arg_list[0];
445
+ if ($v_size == 2) {
446
+ $v_remove_path = $v_arg_list[1];
447
+ }
448
+ else if ($v_size > 2) {
449
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments");
450
+ return 0;
451
+ }
452
+ }
453
+ }
454
+ $v_arg_trick = array (PCLZIP_OPT_BY_INDEX, $p_index);
455
+ $v_options_trick = array();
456
+ $v_result = $this->privParseOptions($v_arg_trick, sizeof($v_arg_trick), $v_options_trick,
457
+ array (PCLZIP_OPT_BY_INDEX => 'optional' ));
458
+ if ($v_result != 1) {
459
+ return 0;
460
+ }
461
+ $v_options[PCLZIP_OPT_BY_INDEX] = $v_options_trick[PCLZIP_OPT_BY_INDEX];
462
+ $this->privOptionDefaultThreshold($v_options);
463
+ if (($v_result = $this->privExtractByRule($p_list, $v_path, $v_remove_path, $v_remove_all_path, $v_options)) < 1) {
464
+ return(0);
465
+ }
466
+ return $p_list;
467
+ }
468
+ function delete()
469
+ {
470
+ $v_result=1;
471
+ $this->privErrorReset();
472
+ if (!$this->privCheckFormat()) {
473
+ return(0);
474
+ }
475
+ $v_options = array();
476
+ $v_size = func_num_args();
477
+ if ($v_size > 0) {
478
+ $v_arg_list = func_get_args();
479
+ $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options,
480
+ array (PCLZIP_OPT_BY_NAME => 'optional',
481
+ PCLZIP_OPT_BY_EREG => 'optional',
482
+ PCLZIP_OPT_BY_PREG => 'optional',
483
+ PCLZIP_OPT_BY_INDEX => 'optional' ));
484
+ if ($v_result != 1) {
485
+ return 0;
486
+ }
487
+ }
488
+ $this->privDisableMagicQuotes();
489
+ $v_list = array();
490
+ if (($v_result = $this->privDeleteByRule($v_list, $v_options)) != 1) {
491
+ $this->privSwapBackMagicQuotes();
492
+ unset($v_list);
493
+ return(0);
494
+ }
495
+ $this->privSwapBackMagicQuotes();
496
+ return $v_list;
497
+ }
498
+ function deleteByIndex($p_index)
499
+ {
500
+ $p_list = $this->delete(PCLZIP_OPT_BY_INDEX, $p_index);
501
+ return $p_list;
502
+ }
503
+ function properties()
504
+ {
505
+ $this->privErrorReset();
506
+ $this->privDisableMagicQuotes();
507
+ if (!$this->privCheckFormat()) {
508
+ $this->privSwapBackMagicQuotes();
509
+ return(0);
510
+ }
511
+ $v_prop = array();
512
+ $v_prop['comment'] = '';
513
+ $v_prop['nb'] = 0;
514
+ $v_prop['status'] = 'not_exist';
515
+ if (@is_file($this->zipname))
516
+ {
517
+ if (($this->zip_fd = @fopen($this->zipname, 'rb')) == 0)
518
+ {
519
+ $this->privSwapBackMagicQuotes();
520
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->zipname.'\' in binary read mode');
521
+ return 0;
522
+ }
523
+ $v_central_dir = array();
524
+ if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1)
525
+ {
526
+ $this->privSwapBackMagicQuotes();
527
+ return 0;
528
+ }
529
+ $this->privCloseFd();
530
+ $v_prop['comment'] = $v_central_dir['comment'];
531
+ $v_prop['nb'] = $v_central_dir['entries'];
532
+ $v_prop['status'] = 'ok';
533
+ }
534
+ $this->privSwapBackMagicQuotes();
535
+ return $v_prop;
536
+ }
537
+ function duplicate($p_archive)
538
+ {
539
+ $v_result = 1;
540
+ $this->privErrorReset();
541
+ if ((is_object($p_archive)) && (get_class($p_archive) == 'pclzip'))
542
+ {
543
+ $v_result = $this->privDuplicate($p_archive->zipname);
544
+ }
545
+ else if (is_string($p_archive))
546
+ {
547
+ if (!is_file($p_archive)) {
548
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "No file with filename '".$p_archive."'");
549
+ $v_result = PCLZIP_ERR_MISSING_FILE;
550
+ }
551
+ else {
552
+ $v_result = $this->privDuplicate($p_archive);
553
+ }
554
+ }
555
+ else
556
+ {
557
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_archive_to_add");
558
+ $v_result = PCLZIP_ERR_INVALID_PARAMETER;
559
+ }
560
+ return $v_result;
561
+ }
562
+ function merge($p_archive_to_add)
563
+ {
564
+ $v_result = 1;
565
+ $this->privErrorReset();
566
+ if (!$this->privCheckFormat()) {
567
+ return(0);
568
+ }
569
+ if ((is_object($p_archive_to_add)) && (get_class($p_archive_to_add) == 'pclzip'))
570
+ {
571
+ $v_result = $this->privMerge($p_archive_to_add);
572
+ }
573
+ else if (is_string($p_archive_to_add))
574
+ {
575
+ $v_object_archive = new PclZip($p_archive_to_add);
576
+ $v_result = $this->privMerge($v_object_archive);
577
+ }
578
+ else
579
+ {
580
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_archive_to_add");
581
+ $v_result = PCLZIP_ERR_INVALID_PARAMETER;
582
+ }
583
+ return $v_result;
584
+ }
585
+ function errorCode()
586
+ {
587
+ if (PCLZIP_ERROR_EXTERNAL == 1) {
588
+ return(PclErrorCode());
589
+ }
590
+ else {
591
+ return($this->error_code);
592
+ }
593
+ }
594
+ function errorName($p_with_code=false)
595
+ {
596
+ $v_name = array ( PCLZIP_ERR_NO_ERROR => 'PCLZIP_ERR_NO_ERROR',
597
+ PCLZIP_ERR_WRITE_OPEN_FAIL => 'PCLZIP_ERR_WRITE_OPEN_FAIL',
598
+ PCLZIP_ERR_READ_OPEN_FAIL => 'PCLZIP_ERR_READ_OPEN_FAIL',
599
+ PCLZIP_ERR_INVALID_PARAMETER => 'PCLZIP_ERR_INVALID_PARAMETER',
600
+ PCLZIP_ERR_MISSING_FILE => 'PCLZIP_ERR_MISSING_FILE',
601
+ PCLZIP_ERR_FILENAME_TOO_LONG => 'PCLZIP_ERR_FILENAME_TOO_LONG',
602
+ PCLZIP_ERR_INVALID_ZIP => 'PCLZIP_ERR_INVALID_ZIP',
603
+ PCLZIP_ERR_BAD_EXTRACTED_FILE => 'PCLZIP_ERR_BAD_EXTRACTED_FILE',
604
+ PCLZIP_ERR_DIR_CREATE_FAIL => 'PCLZIP_ERR_DIR_CREATE_FAIL',
605
+ PCLZIP_ERR_BAD_EXTENSION => 'PCLZIP_ERR_BAD_EXTENSION',
606
+ PCLZIP_ERR_BAD_FORMAT => 'PCLZIP_ERR_BAD_FORMAT',
607
+ PCLZIP_ERR_DELETE_FILE_FAIL => 'PCLZIP_ERR_DELETE_FILE_FAIL',
608
+ PCLZIP_ERR_RENAME_FILE_FAIL => 'PCLZIP_ERR_RENAME_FILE_FAIL',
609
+ PCLZIP_ERR_BAD_CHECKSUM => 'PCLZIP_ERR_BAD_CHECKSUM',
610
+ PCLZIP_ERR_INVALID_ARCHIVE_ZIP => 'PCLZIP_ERR_INVALID_ARCHIVE_ZIP',
611
+ PCLZIP_ERR_MISSING_OPTION_VALUE => 'PCLZIP_ERR_MISSING_OPTION_VALUE',
612
+ PCLZIP_ERR_INVALID_OPTION_VALUE => 'PCLZIP_ERR_INVALID_OPTION_VALUE',
613
+ PCLZIP_ERR_UNSUPPORTED_COMPRESSION => 'PCLZIP_ERR_UNSUPPORTED_COMPRESSION',
614
+ PCLZIP_ERR_UNSUPPORTED_ENCRYPTION => 'PCLZIP_ERR_UNSUPPORTED_ENCRYPTION'
615
+ ,PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE => 'PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE'
616
+ ,PCLZIP_ERR_DIRECTORY_RESTRICTION => 'PCLZIP_ERR_DIRECTORY_RESTRICTION'
617
+ );
618
+ if (isset($v_name[$this->error_code])) {
619
+ $v_value = $v_name[$this->error_code];
620
+ }
621
+ else {
622
+ $v_value = 'NoName';
623
+ }
624
+ if ($p_with_code) {
625
+ return($v_value.' ('.$this->error_code.')');
626
+ }
627
+ else {
628
+ return($v_value);
629
+ }
630
+ }
631
+ function errorInfo($p_full=false)
632
+ {
633
+ if (PCLZIP_ERROR_EXTERNAL == 1) {
634
+ return(PclErrorString());
635
+ }
636
+ else {
637
+ if ($p_full) {
638
+ return($this->errorName(true)." : ".$this->error_string);
639
+ }
640
+ else {
641
+ return($this->error_string." [code ".$this->error_code."]");
642
+ }
643
+ }
644
+ }
645
+ // --------------------------------------------------------------------------------
646
+ // ***** UNDER THIS LINE ARE DEFINED PRIVATE INTERNAL FUNCTIONS *****
647
+ // ***** *****
648
+ // ***** THESES FUNCTIONS MUST NOT BE USED DIRECTLY *****
649
+ // --------------------------------------------------------------------------------
650
+ function privCheckFormat($p_level=0)
651
+ {
652
+ $v_result = true;
653
+ // ----- Reset the file system cache
654
+ clearstatcache();
655
+ $this->privErrorReset();
656
+ if (!is_file($this->zipname)) {
657
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "Missing archive file '".$this->zipname."'");
658
+ return(false);
659
+ }
660
+ if (!is_readable($this->zipname)) {
661
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to read archive '".$this->zipname."'");
662
+ return(false);
663
+ }
664
+ return $v_result;
665
+ }
666
+ function privParseOptions(&$p_options_list, $p_size, &$v_result_list, $v_requested_options=false)
667
+ {
668
+ $v_result=1;
669
+ $i=0;
670
+ while ($i<$p_size) {
671
+ if (!isset($v_requested_options[$p_options_list[$i]])) {
672
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid optional parameter '".$p_options_list[$i]."' for this method");
673
+ return PclZip::errorCode();
674
+ }
675
+ switch ($p_options_list[$i]) {
676
+ case PCLZIP_OPT_PATH :
677
+ case PCLZIP_OPT_REMOVE_PATH :
678
+ case PCLZIP_OPT_ADD_PATH :
679
+ if (($i+1) >= $p_size) {
680
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
681
+ return PclZip::errorCode();
682
+ }
683
+ $v_result_list[$p_options_list[$i]] = PclZipUtilTranslateWinPath($p_options_list[$i+1], FALSE);
684
+ $i++;
685
+ break;
686
+ case PCLZIP_OPT_TEMP_FILE_THRESHOLD :
687
+ if (($i+1) >= $p_size) {
688
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
689
+ return PclZip::errorCode();
690
+ }
691
+ if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_OFF])) {
692
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_OFF'");
693
+ return PclZip::errorCode();
694
+ }
695
+ $v_value = $p_options_list[$i+1];
696
+ if ((!is_integer($v_value)) || ($v_value<0)) {
697
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Integer expected for option '".PclZipUtilOptionText($p_options_list[$i])."'");
698
+ return PclZip::errorCode();
699
+ }
700
+ $v_result_list[$p_options_list[$i]] = $v_value*1048576;
701
+ $i++;
702
+ break;
703
+ case PCLZIP_OPT_TEMP_FILE_ON :
704
+ if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_OFF])) {
705
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_OFF'");
706
+ return PclZip::errorCode();
707
+ }
708
+ $v_result_list[$p_options_list[$i]] = true;
709
+ break;
710
+ case PCLZIP_OPT_TEMP_FILE_OFF :
711
+ if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_ON])) {
712
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_ON'");
713
+ return PclZip::errorCode();
714
+ }
715
+ if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_THRESHOLD])) {
716
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_THRESHOLD'");
717
+ return PclZip::errorCode();
718
+ }
719
+ $v_result_list[$p_options_list[$i]] = true;
720
+ break;
721
+ case PCLZIP_OPT_EXTRACT_DIR_RESTRICTION :
722
+ if (($i+1) >= $p_size) {
723
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
724
+ return PclZip::errorCode();
725
+ }
726
+ if ( is_string($p_options_list[$i+1])
727
+ && ($p_options_list[$i+1] != '')) {
728
+ $v_result_list[$p_options_list[$i]] = PclZipUtilTranslateWinPath($p_options_list[$i+1], FALSE);
729
+ $i++;
730
+ }
731
+ else {
732
+ }
733
+ break;
734
+ case PCLZIP_OPT_BY_NAME :
735
+ if (($i+1) >= $p_size) {
736
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
737
+ return PclZip::errorCode();
738
+ }
739
+ if (is_string($p_options_list[$i+1])) {
740
+ $v_result_list[$p_options_list[$i]][0] = $p_options_list[$i+1];
741
+ }
742
+ else if (is_array($p_options_list[$i+1])) {
743
+ $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1];
744
+ }
745
+ else {
746
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Wrong parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
747
+ return PclZip::errorCode();
748
+ }
749
+ $i++;
750
+ break;
751
+ case PCLZIP_OPT_BY_EREG :
752
+ $p_options_list[$i] = PCLZIP_OPT_BY_PREG;
753
+ case PCLZIP_OPT_BY_PREG :
754
+ if (($i+1) >= $p_size) {
755
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
756
+ return PclZip::errorCode();
757
+ }
758
+ if (is_string($p_options_list[$i+1])) {
759
+ $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1];
760
+ }
761
+ else {
762
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Wrong parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
763
+ return PclZip::errorCode();
764
+ }
765
+ $i++;
766
+ break;
767
+ case PCLZIP_OPT_COMMENT :
768
+ case PCLZIP_OPT_ADD_COMMENT :
769
+ case PCLZIP_OPT_PREPEND_COMMENT :
770
+ if (($i+1) >= $p_size) {
771
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE,
772
+ "Missing parameter value for option '"
773
+ .PclZipUtilOptionText($p_options_list[$i])
774
+ ."'");
775
+ return PclZip::errorCode();
776
+ }
777
+ if (is_string($p_options_list[$i+1])) {
778
+ $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1];
779
+ }
780
+ else {
781
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE,
782
+ "Wrong parameter value for option '"
783
+ .PclZipUtilOptionText($p_options_list[$i])
784
+ ."'");
785
+ return PclZip::errorCode();
786
+ }
787
+ $i++;
788
+ break;
789
+ case PCLZIP_OPT_BY_INDEX :
790
+ if (($i+1) >= $p_size) {
791
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
792
+ return PclZip::errorCode();
793
+ }
794
+ $v_work_list = array();
795
+ if (is_string($p_options_list[$i+1])) {
796
+ $p_options_list[$i+1] = strtr($p_options_list[$i+1], ' ', '');
797
+ $v_work_list = explode(",", $p_options_list[$i+1]);
798
+ }
799
+ else if (is_integer($p_options_list[$i+1])) {
800
+ $v_work_list[0] = $p_options_list[$i+1].'-'.$p_options_list[$i+1];
801
+ }
802
+ else if (is_array($p_options_list[$i+1])) {
803
+ $v_work_list = $p_options_list[$i+1];
804
+ }
805
+ else {
806
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Value must be integer, string or array for option '".PclZipUtilOptionText($p_options_list[$i])."'");
807
+ return PclZip::errorCode();
808
+ }
809
+ $v_sort_flag=false;
810
+ $v_sort_value=0;
811
+ for ($j=0; $j<sizeof($v_work_list); $j++) {
812
+ $v_item_list = explode("-", $v_work_list[$j]);
813
+ $v_size_item_list = sizeof($v_item_list);
814
+ if ($v_size_item_list == 1) {
815
+ $v_result_list[$p_options_list[$i]][$j]['start'] = $v_item_list[0];
816
+ $v_result_list[$p_options_list[$i]][$j]['end'] = $v_item_list[0];
817
+ }
818
+ elseif ($v_size_item_list == 2) {
819
+ $v_result_list[$p_options_list[$i]][$j]['start'] = $v_item_list[0];
820
+ $v_result_list[$p_options_list[$i]][$j]['end'] = $v_item_list[1];
821
+ }
822
+ else {
823
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Too many values in index range for option '".PclZipUtilOptionText($p_options_list[$i])."'");
824
+ return PclZip::errorCode();
825
+ }
826
+ if ($v_result_list[$p_options_list[$i]][$j]['start'] < $v_sort_value) {
827
+ $v_sort_flag=true;
828
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Invalid order of index range for option '".PclZipUtilOptionText($p_options_list[$i])."'");
829
+ return PclZip::errorCode();
830
+ }
831
+ $v_sort_value = $v_result_list[$p_options_list[$i]][$j]['start'];
832
+ }
833
+ if ($v_sort_flag) {
834
+ }
835
+ $i++;
836
+ break;
837
+ case PCLZIP_OPT_REMOVE_ALL_PATH :
838
+ case PCLZIP_OPT_EXTRACT_AS_STRING :
839
+ case PCLZIP_OPT_NO_COMPRESSION :
840
+ case PCLZIP_OPT_EXTRACT_IN_OUTPUT :
841
+ case PCLZIP_OPT_REPLACE_NEWER :
842
+ case PCLZIP_OPT_STOP_ON_ERROR :
843
+ $v_result_list[$p_options_list[$i]] = true;
844
+ break;
845
+ case PCLZIP_OPT_SET_CHMOD :
846
+ if (($i+1) >= $p_size) {
847
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
848
+ return PclZip::errorCode();
849
+ }
850
+ $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1];
851
+ $i++;
852
+ break;
853
+ case PCLZIP_CB_PRE_EXTRACT :
854
+ case PCLZIP_CB_POST_EXTRACT :
855
+ case PCLZIP_CB_PRE_ADD :
856
+ case PCLZIP_CB_POST_ADD :
857
+ /* for futur use
858
+ case PCLZIP_CB_PRE_DELETE :
859
+ case PCLZIP_CB_POST_DELETE :
860
+ case PCLZIP_CB_PRE_LIST :
861
+ case PCLZIP_CB_POST_LIST :
862
+ */
863
+ if (($i+1) >= $p_size) {
864
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
865
+ return PclZip::errorCode();
866
+ }
867
+ $v_function_name = $p_options_list[$i+1];
868
+ if (!function_exists($v_function_name)) {
869
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Function '".$v_function_name."()' is not an existing function for option '".PclZipUtilOptionText($p_options_list[$i])."'");
870
+ return PclZip::errorCode();
871
+ }
872
+ $v_result_list[$p_options_list[$i]] = $v_function_name;
873
+ $i++;
874
+ break;
875
+ default :
876
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER,
877
+ "Unknown parameter '"
878
+ .$p_options_list[$i]."'");
879
+ return PclZip::errorCode();
880
+ }
881
+ $i++;
882
+ }
883
+ if ($v_requested_options !== false) {
884
+ for ($key=reset($v_requested_options); $key=key($v_requested_options); $key=next($v_requested_options)) {
885
+ if ($v_requested_options[$key] == 'mandatory') {
886
+ if (!isset($v_result_list[$key])) {
887
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Missing mandatory parameter ".PclZipUtilOptionText($key)."(".$key.")");
888
+ return PclZip::errorCode();
889
+ }
890
+ }
891
+ }
892
+ }
893
+ if (!isset($v_result_list[PCLZIP_OPT_TEMP_FILE_THRESHOLD])) {
894
+ }
895
+ return $v_result;
896
+ }
897
+ function privOptionDefaultThreshold(&$p_options)
898
+ {
899
+ $v_result=1;
900
+ if (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD])
901
+ || isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF])) {
902
+ return $v_result;
903
+ }
904
+ $v_memory_limit = ini_get('memory_limit');
905
+ $v_memory_limit = trim($v_memory_limit);
906
+ $last = strtolower(substr($v_memory_limit, -1));
907
+ if($last == 'g')
908
+ $v_memory_limit = $v_memory_limit*1073741824;
909
+ if($last == 'm')
910
+ $v_memory_limit = $v_memory_limit*1048576;
911
+ if($last == 'k')
912
+ $v_memory_limit = $v_memory_limit*1024;
913
+ $p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] = floor($v_memory_limit*PCLZIP_TEMPORARY_FILE_RATIO);
914
+ if ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] < 1048576) {
915
+ unset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]);
916
+ }
917
+ return $v_result;
918
+ }
919
+ function privFileDescrParseAtt(&$p_file_list, &$p_filedescr, $v_options, $v_requested_options=false)
920
+ {
921
+ $v_result=1;
922
+ foreach ($p_file_list as $v_key => $v_value) {
923
+ if (!isset($v_requested_options[$v_key])) {
924
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid file attribute '".$v_key."' for this file");
925
+ return PclZip::errorCode();
926
+ }
927
+ switch ($v_key) {
928
+ case PCLZIP_ATT_FILE_NAME :
929
+ if (!is_string($v_value)) {
930
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'");
931
+ return PclZip::errorCode();
932
+ }
933
+ $p_filedescr['filename'] = PclZipUtilPathReduction($v_value);
934
+ if ($p_filedescr['filename'] == '') {
935
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty filename for attribute '".PclZipUtilOptionText($v_key)."'");
936
+ return PclZip::errorCode();
937
+ }
938
+ break;
939
+ case PCLZIP_ATT_FILE_NEW_SHORT_NAME :
940
+ if (!is_string($v_value)) {
941
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'");
942
+ return PclZip::errorCode();
943
+ }
944
+ $p_filedescr['new_short_name'] = PclZipUtilPathReduction($v_value);
945
+ if ($p_filedescr['new_short_name'] == '') {
946
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty short filename for attribute '".PclZipUtilOptionText($v_key)."'");
947
+ return PclZip::errorCode();
948
+ }
949
+ break;
950
+ case PCLZIP_ATT_FILE_NEW_FULL_NAME :
951
+ if (!is_string($v_value)) {
952
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'");
953
+ return PclZip::errorCode();
954
+ }
955
+ $p_filedescr['new_full_name'] = PclZipUtilPathReduction($v_value);
956
+ if ($p_filedescr['new_full_name'] == '') {
957
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty full filename for attribute '".PclZipUtilOptionText($v_key)."'");
958
+ return PclZip::errorCode();
959
+ }
960
+ break;
961
+ case PCLZIP_ATT_FILE_COMMENT :
962
+ if (!is_string($v_value)) {
963
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'");
964
+ return PclZip::errorCode();
965
+ }
966
+ $p_filedescr['comment'] = $v_value;
967
+ break;
968
+ case PCLZIP_ATT_FILE_MTIME :
969
+ if (!is_integer($v_value)) {
970
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". Integer expected for attribute '".PclZipUtilOptionText($v_key)."'");
971
+ return PclZip::errorCode();
972
+ }
973
+ $p_filedescr['mtime'] = $v_value;
974
+ break;
975
+ case PCLZIP_ATT_FILE_CONTENT :
976
+ $p_filedescr['content'] = $v_value;
977
+ break;
978
+ default :
979
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER,
980
+ "Unknown parameter '".$v_key."'");
981
+ return PclZip::errorCode();
982
+ }
983
+ if ($v_requested_options !== false) {
984
+ for ($key=reset($v_requested_options); $key=key($v_requested_options); $key=next($v_requested_options)) {
985
+ if ($v_requested_options[$key] == 'mandatory') {
986
+ if (!isset($p_file_list[$key])) {
987
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Missing mandatory parameter ".PclZipUtilOptionText($key)."(".$key.")");
988
+ return PclZip::errorCode();
989
+ }
990
+ }
991
+ }
992
+ }
993
+ }
994
+ return $v_result;
995
+ }
996
+ function privFileDescrExpand(&$p_filedescr_list, &$p_options)
997
+ {
998
+ $v_result=1;
999
+ $v_result_list = array();
1000
+ for ($i=0; $i<sizeof($p_filedescr_list); $i++) {
1001
+ $v_descr = $p_filedescr_list[$i];
1002
+ $v_descr['filename'] = PclZipUtilTranslateWinPath($v_descr['filename'], false);
1003
+ $v_descr['filename'] = PclZipUtilPathReduction($v_descr['filename']);
1004
+ if (file_exists($v_descr['filename'])) {
1005
+ if (@is_file($v_descr['filename'])) {
1006
+ $v_descr['type'] = 'file';
1007
+ }
1008
+ else if (@is_dir($v_descr['filename'])) {
1009
+ $v_descr['type'] = 'folder';
1010
+ }
1011
+ else if (@is_link($v_descr['filename'])) {
1012
+ continue;
1013
+ }
1014
+ else {
1015
+ continue;
1016
+ }
1017
+ }
1018
+ else if (isset($v_descr['content'])) {
1019
+ $v_descr['type'] = 'virtual_file';
1020
+ }
1021
+ else {
1022
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "File '".$v_descr['filename']."' does not exist");
1023
+ return PclZip::errorCode();
1024
+ }
1025
+ $this->privCalculateStoredFilename($v_descr, $p_options);
1026
+ $v_result_list[sizeof($v_result_list)] = $v_descr;
1027
+ if ($v_descr['type'] == 'folder') {
1028
+ $v_dirlist_descr = array();
1029
+ $v_dirlist_nb = 0;
1030
+ if ($v_folder_handler = @opendir($v_descr['filename'])) {
1031
+ while (($v_item_handler = @readdir($v_folder_handler)) !== false) {
1032
+ if (($v_item_handler == '.') || ($v_item_handler == '..')) {
1033
+ continue;
1034
+ }
1035
+ $v_dirlist_descr[$v_dirlist_nb]['filename'] = $v_descr['filename'].'/'.$v_item_handler;
1036
+ if (($v_descr['stored_filename'] != $v_descr['filename'])
1037
+ && (!isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH]))) {
1038
+ if ($v_descr['stored_filename'] != '') {
1039
+ $v_dirlist_descr[$v_dirlist_nb]['new_full_name'] = $v_descr['stored_filename'].'/'.$v_item_handler;
1040
+ }
1041
+ else {
1042
+ $v_dirlist_descr[$v_dirlist_nb]['new_full_name'] = $v_item_handler;
1043
+ }
1044
+ }
1045
+ $v_dirlist_nb++;
1046
+ }
1047
+ @closedir($v_folder_handler);
1048
+ }
1049
+ else {
1050
+ }
1051
+ if ($v_dirlist_nb != 0) {
1052
+ if (($v_result = $this->privFileDescrExpand($v_dirlist_descr, $p_options)) != 1) {
1053
+ return $v_result;
1054
+ }
1055
+ $v_result_list = array_merge($v_result_list, $v_dirlist_descr);
1056
+ }
1057
+ else {
1058
+ }
1059
+ unset($v_dirlist_descr);
1060
+ }
1061
+ }
1062
+ $p_filedescr_list = $v_result_list;
1063
+ return $v_result;
1064
+ }
1065
+ function privCreate($p_filedescr_list, &$p_result_list, &$p_options)
1066
+ {
1067
+ $v_result=1;
1068
+ $v_list_detail = array();
1069
+ $this->privDisableMagicQuotes();
1070
+ if (($v_result = $this->privOpenFd('wb')) != 1)
1071
+ {
1072
+ return $v_result;
1073
+ }
1074
+ $v_result = $this->privAddList($p_filedescr_list, $p_result_list, $p_options);
1075
+ $this->privCloseFd();
1076
+ $this->privSwapBackMagicQuotes();
1077
+ return $v_result;
1078
+ }
1079
+ function privAdd($p_filedescr_list, &$p_result_list, &$p_options)
1080
+ {
1081
+ $v_result=1;
1082
+ $v_list_detail = array();
1083
+ if ((!is_file($this->zipname)) || (filesize($this->zipname) == 0))
1084
+ {
1085
+ $v_result = $this->privCreate($p_filedescr_list, $p_result_list, $p_options);
1086
+ return $v_result;
1087
+ }
1088
+ $this->privDisableMagicQuotes();
1089
+ if (($v_result=$this->privOpenFd('rb')) != 1)
1090
+ {
1091
+ $this->privSwapBackMagicQuotes();
1092
+ return $v_result;
1093
+ }
1094
+ $v_central_dir = array();
1095
+ if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1)
1096
+ {
1097
+ $this->privCloseFd();
1098
+ $this->privSwapBackMagicQuotes();
1099
+ return $v_result;
1100
+ }
1101
+ @rewind($this->zip_fd);
1102
+ $v_zip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.tmp';
1103
+ if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0)
1104
+ {
1105
+ $this->privCloseFd();
1106
+ $this->privSwapBackMagicQuotes();
1107
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_zip_temp_name.'\' in binary write mode');
1108
+ return PclZip::errorCode();
1109
+ }
1110
+ $v_size = $v_central_dir['offset'];
1111
+ while ($v_size != 0)
1112
+ {
1113
+ $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
1114
+ $v_buffer = fread($this->zip_fd, $v_read_size);
1115
+ @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size);
1116
+ $v_size -= $v_read_size;
1117
+ }
1118
+ $v_swap = $this->zip_fd;
1119
+ $this->zip_fd = $v_zip_temp_fd;
1120
+ $v_zip_temp_fd = $v_swap;
1121
+ $v_header_list = array();
1122
+ if (($v_result = $this->privAddFileList($p_filedescr_list, $v_header_list, $p_options)) != 1)
1123
+ {
1124
+ fclose($v_zip_temp_fd);
1125
+ $this->privCloseFd();
1126
+ @unlink($v_zip_temp_name);
1127
+ $this->privSwapBackMagicQuotes();
1128
+ return $v_result;
1129
+ }
1130
+ $v_offset = @ftell($this->zip_fd);
1131
+ $v_size = $v_central_dir['size'];
1132
+ while ($v_size != 0)
1133
+ {
1134
+ $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
1135
+ $v_buffer = @fread($v_zip_temp_fd, $v_read_size);
1136
+ @fwrite($this->zip_fd, $v_buffer, $v_read_size);
1137
+ $v_size -= $v_read_size;
1138
+ }
1139
+ for ($i=0, $v_count=0; $i<sizeof($v_header_list); $i++)
1140
+ {
1141
+ if ($v_header_list[$i]['status'] == 'ok') {
1142
+ if (($v_result = $this->privWriteCentralFileHeader($v_header_list[$i])) != 1) {
1143
+ fclose($v_zip_temp_fd);
1144
+ $this->privCloseFd();
1145
+ @unlink($v_zip_temp_name);
1146
+ $this->privSwapBackMagicQuotes();
1147
+ return $v_result;
1148
+ }
1149
+ $v_count++;
1150
+ }
1151
+ $this->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]);
1152
+ }
1153
+ $v_comment = $v_central_dir['comment'];
1154
+ if (isset($p_options[PCLZIP_OPT_COMMENT])) {
1155
+ $v_comment = $p_options[PCLZIP_OPT_COMMENT];
1156
+ }
1157
+ if (isset($p_options[PCLZIP_OPT_ADD_COMMENT])) {
1158
+ $v_comment = $v_comment.$p_options[PCLZIP_OPT_ADD_COMMENT];
1159
+ }
1160
+ if (isset($p_options[PCLZIP_OPT_PREPEND_COMMENT])) {
1161
+ $v_comment = $p_options[PCLZIP_OPT_PREPEND_COMMENT].$v_comment;
1162
+ }
1163
+ $v_size = @ftell($this->zip_fd)-$v_offset;
1164
+ if (($v_result = $this->privWriteCentralHeader($v_count+$v_central_dir['entries'], $v_size, $v_offset, $v_comment)) != 1)
1165
+ {
1166
+ unset($v_header_list);
1167
+ $this->privSwapBackMagicQuotes();
1168
+ return $v_result;
1169
+ }
1170
+ $v_swap = $this->zip_fd;
1171
+ $this->zip_fd = $v_zip_temp_fd;
1172
+ $v_zip_temp_fd = $v_swap;
1173
+ $this->privCloseFd();
1174
+ @fclose($v_zip_temp_fd);
1175
+ $this->privSwapBackMagicQuotes();
1176
+ @unlink($this->zipname);
1177
+ PclZipUtilRename($v_zip_temp_name, $this->zipname);
1178
+ return $v_result;
1179
+ }
1180
+ function privOpenFd($p_mode)
1181
+ {
1182
+ $v_result=1;
1183
+ if ($this->zip_fd != 0)
1184
+ {
1185
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Zip file \''.$this->zipname.'\' already open');
1186
+ return PclZip::errorCode();
1187
+ }
1188
+ if (($this->zip_fd = @fopen($this->zipname, $p_mode)) == 0)
1189
+ {
1190
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->zipname.'\' in '.$p_mode.' mode');
1191
+ return PclZip::errorCode();
1192
+ }
1193
+ return $v_result;
1194
+ }
1195
+ function privCloseFd()
1196
+ {
1197
+ $v_result=1;
1198
+ if ($this->zip_fd != 0)
1199
+ @fclose($this->zip_fd);
1200
+ $this->zip_fd = 0;
1201
+ return $v_result;
1202
+ }
1203
+ // function privAddList($p_list, &$p_result_list, $p_add_dir, $p_remove_dir, $p_remove_all_dir, &$p_options)
1204
+ function privAddList($p_filedescr_list, &$p_result_list, &$p_options)
1205
+ {
1206
+ $v_result=1;
1207
+ $v_header_list = array();
1208
+ if (($v_result = $this->privAddFileList($p_filedescr_list, $v_header_list, $p_options)) != 1)
1209
+ {
1210
+ return $v_result;
1211
+ }
1212
+ $v_offset = @ftell($this->zip_fd);
1213
+ for ($i=0,$v_count=0; $i<sizeof($v_header_list); $i++)
1214
+ {
1215
+ if ($v_header_list[$i]['status'] == 'ok') {
1216
+ if (($v_result = $this->privWriteCentralFileHeader($v_header_list[$i])) != 1) {
1217
+ return $v_result;
1218
+ }
1219
+ $v_count++;
1220
+ }
1221
+ $this->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]);
1222
+ }
1223
+ $v_comment = '';
1224
+ if (isset($p_options[PCLZIP_OPT_COMMENT])) {
1225
+ $v_comment = $p_options[PCLZIP_OPT_COMMENT];
1226
+ }
1227
+ $v_size = @ftell($this->zip_fd)-$v_offset;
1228
+ if (($v_result = $this->privWriteCentralHeader($v_count, $v_size, $v_offset, $v_comment)) != 1)
1229
+ {
1230
+ unset($v_header_list);
1231
+ return $v_result;
1232
+ }
1233
+ return $v_result;
1234
+ }
1235
+ function privAddFileList($p_filedescr_list, &$p_result_list, &$p_options)
1236
+ {
1237
+ $v_result=1;
1238
+ $v_header = array();
1239
+ $v_nb = sizeof($p_result_list);
1240
+ for ($j=0; ($j<sizeof($p_filedescr_list)) && ($v_result==1); $j++) {
1241
+ $p_filedescr_list[$j]['filename']
1242
+ = PclZipUtilTranslateWinPath($p_filedescr_list[$j]['filename'], false);
1243
+ if ($p_filedescr_list[$j]['filename'] == "") {
1244
+ continue;
1245
+ }
1246
+ if ( ($p_filedescr_list[$j]['type'] != 'virtual_file')
1247
+ && (!file_exists($p_filedescr_list[$j]['filename']))) {
1248
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "File '".$p_filedescr_list[$j]['filename']."' does not exist");
1249
+ return PclZip::errorCode();
1250
+ }
1251
+ // if ( (is_file($p_filedescr_list[$j]['filename']))
1252
+ // || ( is_dir($p_filedescr_list[$j]['filename'])
1253
+ if ( ($p_filedescr_list[$j]['type'] == 'file')
1254
+ || ($p_filedescr_list[$j]['type'] == 'virtual_file')
1255
+ || ( ($p_filedescr_list[$j]['type'] == 'folder')
1256
+ && ( !isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH])
1257
+ || !$p_options[PCLZIP_OPT_REMOVE_ALL_PATH]))
1258
+ ) {
1259
+ $v_result = $this->privAddFile($p_filedescr_list[$j], $v_header,
1260
+ $p_options);
1261
+ if ($v_result != 1) {
1262
+ return $v_result;
1263
+ }
1264
+ $p_result_list[$v_nb++] = $v_header;
1265
+ }
1266
+ }
1267
+ return $v_result;
1268
+ }
1269
+ function privAddFile($p_filedescr, &$p_header, &$p_options)
1270
+ {
1271
+ $v_result=1;
1272
+ $p_filename = $p_filedescr['filename'];
1273
+ if ($p_filename == "") {
1274
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid file list parameter (invalid or empty list)");
1275
+ return PclZip::errorCode();
1276
+ }
1277
+ /* TBC : Removed
1278
+ if (isset($p_filedescr['stored_filename'])) {
1279
+ $v_stored_filename = $p_filedescr['stored_filename'];
1280
+ }
1281
+ else {
1282
+ $v_stored_filename = $p_filedescr['stored_filename'];
1283
+ }
1284
+ */
1285
+ clearstatcache();
1286
+ $p_header['version'] = 20;
1287
+ $p_header['version_extracted'] = 10;
1288
+ $p_header['flag'] = 0;
1289
+ $p_header['compression'] = 0;
1290
+ $p_header['crc'] = 0;
1291
+ $p_header['compressed_size'] = 0;
1292
+ $p_header['filename_len'] = strlen($p_filename);
1293
+ $p_header['extra_len'] = 0;
1294
+ $p_header['disk'] = 0;
1295
+ $p_header['internal'] = 0;
1296
+ $p_header['offset'] = 0;
1297
+ $p_header['filename'] = $p_filename;
1298
+ // TBC : Removed $p_header['stored_filename'] = $v_stored_filename;
1299
+ $p_header['stored_filename'] = $p_filedescr['stored_filename'];
1300
+ $p_header['extra'] = '';
1301
+ $p_header['status'] = 'ok';
1302
+ $p_header['index'] = -1;
1303
+ if ($p_filedescr['type']=='file') {
1304
+ $p_header['external'] = 0x00000000;
1305
+ $p_header['size'] = filesize($p_filename);
1306
+ }
1307
+ else if ($p_filedescr['type']=='folder') {
1308
+ $p_header['external'] = 0x00000010;
1309
+ $p_header['mtime'] = filemtime($p_filename);
1310
+ $p_header['size'] = filesize($p_filename);
1311
+ }
1312
+ else if ($p_filedescr['type'] == 'virtual_file') {
1313
+ $p_header['external'] = 0x00000000;
1314
+ $p_header['size'] = strlen($p_filedescr['content']);
1315
+ }
1316
+ if (isset($p_filedescr['mtime'])) {
1317
+ $p_header['mtime'] = $p_filedescr['mtime'];
1318
+ }
1319
+ else if ($p_filedescr['type'] == 'virtual_file') {
1320
+ $p_header['mtime'] = time();
1321
+ }
1322
+ else {
1323
+ $p_header['mtime'] = filemtime($p_filename);
1324
+ }
1325
+ if (isset($p_filedescr['comment'])) {
1326
+ $p_header['comment_len'] = strlen($p_filedescr['comment']);
1327
+ $p_header['comment'] = $p_filedescr['comment'];
1328
+ }
1329
+ else {
1330
+ $p_header['comment_len'] = 0;
1331
+ $p_header['comment'] = '';
1332
+ }
1333
+ if (isset($p_options[PCLZIP_CB_PRE_ADD])) {
1334
+ $v_local_header = array();
1335
+ $this->privConvertHeader2FileInfo($p_header, $v_local_header);
1336
+ // eval('$v_result = '.$p_options[PCLZIP_CB_PRE_ADD].'(PCLZIP_CB_PRE_ADD, $v_local_header);');
1337
+ $v_result = $p_options[PCLZIP_CB_PRE_ADD](PCLZIP_CB_PRE_ADD, $v_local_header);
1338
+ if ($v_result == 0) {
1339
+ $p_header['status'] = "skipped";
1340
+ $v_result = 1;
1341
+ }
1342
+ if ($p_header['stored_filename'] != $v_local_header['stored_filename']) {
1343
+ $p_header['stored_filename'] = PclZipUtilPathReduction($v_local_header['stored_filename']);
1344
+ }
1345
+ }
1346
+ if ($p_header['stored_filename'] == "") {
1347
+ $p_header['status'] = "filtered";
1348
+ }
1349
+ if (strlen($p_header['stored_filename']) > 0xFF) {
1350
+ $p_header['status'] = 'filename_too_long';
1351
+ }
1352
+ if ($p_header['status'] == 'ok') {
1353
+ if ($p_filedescr['type'] == 'file') {
1354
+ if ( (!isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF]))
1355
+ && (isset($p_options[PCLZIP_OPT_TEMP_FILE_ON])
1356
+ || (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD])
1357
+ && ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] <= $p_header['size'])) ) ) {
1358
+ $v_result = $this->privAddFileUsingTempFile($p_filedescr, $p_header, $p_options);
1359
+ if ($v_result < PCLZIP_ERR_NO_ERROR) {
1360
+ return $v_result;
1361
+ }
1362
+ }
1363
+ else {
1364
+ if (($v_file = @fopen($p_filename, "rb")) == 0) {
1365
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to open file '$p_filename' in binary read mode");
1366
+ return PclZip::errorCode();
1367
+ }
1368
+ $v_content = @fread($v_file, $p_header['size']);
1369
+ @fclose($v_file);
1370
+ $p_header['crc'] = @crc32($v_content);
1371
+ if ($p_options[PCLZIP_OPT_NO_COMPRESSION]) {
1372
+ $p_header['compressed_size'] = $p_header['size'];
1373
+ $p_header['compression'] = 0;
1374
+ }
1375
+ else {
1376
+ $v_content = @gzdeflate($v_content);
1377
+ $p_header['compressed_size'] = strlen($v_content);
1378
+ $p_header['compression'] = 8;
1379
+ }
1380
+ if (($v_result = $this->privWriteFileHeader($p_header)) != 1) {
1381
+ @fclose($v_file);
1382
+ return $v_result;
1383
+ }
1384
+ @fwrite($this->zip_fd, $v_content, $p_header['compressed_size']);
1385
+ }
1386
+ }
1387
+ else if ($p_filedescr['type'] == 'virtual_file') {
1388
+ $v_content = $p_filedescr['content'];
1389
+ $p_header['crc'] = @crc32($v_content);
1390
+ if ($p_options[PCLZIP_OPT_NO_COMPRESSION]) {
1391
+ $p_header['compressed_size'] = $p_header['size'];
1392
+ $p_header['compression'] = 0;
1393
+ }
1394
+ else {
1395
+ $v_content = @gzdeflate($v_content);
1396
+ $p_header['compressed_size'] = strlen($v_content);
1397
+ $p_header['compression'] = 8;
1398
+ }
1399
+ if (($v_result = $this->privWriteFileHeader($p_header)) != 1) {
1400
+ @fclose($v_file);
1401
+ return $v_result;
1402
+ }
1403
+ @fwrite($this->zip_fd, $v_content, $p_header['compressed_size']);
1404
+ }
1405
+ else if ($p_filedescr['type'] == 'folder') {
1406
+ if (@substr($p_header['stored_filename'], -1) != '/') {
1407
+ $p_header['stored_filename'] .= '/';
1408
+ }
1409
+ $p_header['size'] = 0;
1410
+ $p_header['external'] = 0x00000010; // Value for a folder : to be checked
1411
+ if (($v_result = $this->privWriteFileHeader($p_header)) != 1)
1412
+ {
1413
+ return $v_result;
1414
+ }
1415
+ }
1416
+ }
1417
+ if (isset($p_options[PCLZIP_CB_POST_ADD])) {
1418
+ $v_local_header = array();
1419
+ $this->privConvertHeader2FileInfo($p_header, $v_local_header);
1420
+ // eval('$v_result = '.$p_options[PCLZIP_CB_POST_ADD].'(PCLZIP_CB_POST_ADD, $v_local_header);');
1421
+ $v_result = $p_options[PCLZIP_CB_POST_ADD](PCLZIP_CB_POST_ADD, $v_local_header);
1422
+ if ($v_result == 0) {
1423
+ $v_result = 1;
1424
+ }
1425
+ }
1426
+ return $v_result;
1427
+ }
1428
+ function privAddFileUsingTempFile($p_filedescr, &$p_header, &$p_options)
1429
+ {
1430
+ $v_result=PCLZIP_ERR_NO_ERROR;
1431
+ $p_filename = $p_filedescr['filename'];
1432
+ if (($v_file = @fopen($p_filename, "rb")) == 0) {
1433
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to open file '$p_filename' in binary read mode");
1434
+ return PclZip::errorCode();
1435
+ }
1436
+ $v_gzip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.gz';
1437
+ if (($v_file_compressed = @gzopen($v_gzip_temp_name, "wb")) == 0) {
1438
+ fclose($v_file);
1439
+ PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary write mode');
1440
+ return PclZip::errorCode();
1441
+ }
1442
+ $v_size = filesize($p_filename);
1443
+ while ($v_size != 0) {
1444
+ $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
1445
+ $v_buffer = @fread($v_file, $v_read_size);
1446
+ @gzputs($v_file_compressed, $v_buffer, $v_read_size);
1447
+ $v_size -= $v_read_size;
1448
+ }
1449
+ @fclose($v_file);
1450
+ @gzclose($v_file_compressed);
1451
+ if (filesize($v_gzip_temp_name) < 18) {
1452
+ PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'gzip temporary file \''.$v_gzip_temp_name.'\' has invalid filesize - should be minimum 18 bytes');
1453
+ return PclZip::errorCode();
1454
+ }
1455
+ if (($v_file_compressed = @fopen($v_gzip_temp_name, "rb")) == 0) {
1456
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary read mode');
1457
+ return PclZip::errorCode();
1458
+ }
1459
+ $v_binary_data = @fread($v_file_compressed, 10);
1460
+ $v_data_header = unpack('a1id1/a1id2/a1cm/a1flag/Vmtime/a1xfl/a1os', $v_binary_data);
1461
+ $v_data_header['os'] = bin2hex($v_data_header['os']);
1462
+ @fseek($v_file_compressed, filesize($v_gzip_temp_name)-8);
1463
+ $v_binary_data = @fread($v_file_compressed, 8);
1464
+ $v_data_footer = unpack('Vcrc/Vcompressed_size', $v_binary_data);
1465
+ $p_header['compression'] = ord($v_data_header['cm']);
1466
+ $p_header['crc'] = $v_data_footer['crc'];
1467
+ $p_header['compressed_size'] = filesize($v_gzip_temp_name)-18;
1468
+ @fclose($v_file_compressed);
1469
+ if (($v_result = $this->privWriteFileHeader($p_header)) != 1) {
1470
+ return $v_result;
1471
+ }
1472
+ if (($v_file_compressed = @fopen($v_gzip_temp_name, "rb")) == 0)
1473
+ {
1474
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary read mode');
1475
+ return PclZip::errorCode();
1476
+ }
1477
+ fseek($v_file_compressed, 10);
1478
+ $v_size = $p_header['compressed_size'];
1479
+ while ($v_size != 0)
1480
+ {
1481
+ $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
1482
+ $v_buffer = @fread($v_file_compressed, $v_read_size);
1483
+ @fwrite($this->zip_fd, $v_buffer, $v_read_size);
1484
+ $v_size -= $v_read_size;
1485
+ }
1486
+ @fclose($v_file_compressed);
1487
+ @unlink($v_gzip_temp_name);
1488
+ return $v_result;
1489
+ }
1490
+ function privCalculateStoredFilename(&$p_filedescr, &$p_options)
1491
+ {
1492
+ $v_result=1;
1493
+ $p_filename = $p_filedescr['filename'];
1494
+ if (isset($p_options[PCLZIP_OPT_ADD_PATH])) {
1495
+ $p_add_dir = $p_options[PCLZIP_OPT_ADD_PATH];
1496
+ }
1497
+ else {
1498
+ $p_add_dir = '';
1499
+ }
1500
+ if (isset($p_options[PCLZIP_OPT_REMOVE_PATH])) {
1501
+ $p_remove_dir = $p_options[PCLZIP_OPT_REMOVE_PATH];
1502
+ }
1503
+ else {
1504
+ $p_remove_dir = '';
1505
+ }
1506
+ if (isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH])) {
1507
+ $p_remove_all_dir = $p_options[PCLZIP_OPT_REMOVE_ALL_PATH];
1508
+ }
1509
+ else {
1510
+ $p_remove_all_dir = 0;
1511
+ }
1512
+ if (isset($p_filedescr['new_full_name'])) {
1513
+ $v_stored_filename = PclZipUtilTranslateWinPath($p_filedescr['new_full_name']);
1514
+ }
1515
+ else {
1516
+ if (isset($p_filedescr['new_short_name'])) {
1517
+ $v_path_info = pathinfo($p_filename);
1518
+ $v_dir = '';
1519
+ if ($v_path_info['dirname'] != '') {
1520
+ $v_dir = $v_path_info['dirname'].'/';
1521
+ }
1522
+ $v_stored_filename = $v_dir.$p_filedescr['new_short_name'];
1523
+ }
1524
+ else {
1525
+ $v_stored_filename = $p_filename;
1526
+ }
1527
+ if ($p_remove_all_dir) {
1528
+ $v_stored_filename = basename($p_filename);
1529
+ }
1530
+ else if ($p_remove_dir != "") {
1531
+ if (substr($p_remove_dir, -1) != '/')
1532
+ $p_remove_dir .= "/";
1533
+ if ( (substr($p_filename, 0, 2) == "./")
1534
+ || (substr($p_remove_dir, 0, 2) == "./")) {
1535
+ if ( (substr($p_filename, 0, 2) == "./")
1536
+ && (substr($p_remove_dir, 0, 2) != "./")) {
1537
+ $p_remove_dir = "./".$p_remove_dir;
1538
+ }
1539
+ if ( (substr($p_filename, 0, 2) != "./")
1540
+ && (substr($p_remove_dir, 0, 2) == "./")) {
1541
+ $p_remove_dir = substr($p_remove_dir, 2);
1542
+ }
1543
+ }
1544
+ $v_compare = PclZipUtilPathInclusion($p_remove_dir,
1545
+ $v_stored_filename);
1546
+ if ($v_compare > 0) {
1547
+ if ($v_compare == 2) {
1548
+ $v_stored_filename = "";
1549
+ }
1550
+ else {
1551
+ $v_stored_filename = substr($v_stored_filename,
1552
+ strlen($p_remove_dir));
1553
+ }
1554
+ }
1555
+ }
1556
+ $v_stored_filename = PclZipUtilTranslateWinPath($v_stored_filename);
1557
+ if ($p_add_dir != "") {
1558
+ if (substr($p_add_dir, -1) == "/")
1559
+ $v_stored_filename = $p_add_dir.$v_stored_filename;
1560
+ else
1561
+ $v_stored_filename = $p_add_dir."/".$v_stored_filename;
1562
+ }
1563
+ }
1564
+ $v_stored_filename = PclZipUtilPathReduction($v_stored_filename);
1565
+ $p_filedescr['stored_filename'] = $v_stored_filename;
1566
+ return $v_result;
1567
+ }
1568
+ function privWriteFileHeader(&$p_header)
1569
+ {
1570
+ $v_result=1;
1571
+ $p_header['offset'] = ftell($this->zip_fd);
1572
+ $v_date = getdate($p_header['mtime']);
1573
+ $v_mtime = ($v_date['hours']<<11) + ($v_date['minutes']<<5) + $v_date['seconds']/2;
1574
+ $v_mdate = (($v_date['year']-1980)<<9) + ($v_date['mon']<<5) + $v_date['mday'];
1575
+ $v_binary_data = pack("VvvvvvVVVvv", 0x04034b50,
1576
+ $p_header['version_extracted'], $p_header['flag'],
1577
+ $p_header['compression'], $v_mtime, $v_mdate,
1578
+ $p_header['crc'], $p_header['compressed_size'],
1579
+ $p_header['size'],
1580
+ strlen($p_header['stored_filename']),
1581
+ $p_header['extra_len']);
1582
+ fputs($this->zip_fd, $v_binary_data, 30);
1583
+ if (strlen($p_header['stored_filename']) != 0)
1584
+ {
1585
+ fputs($this->zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename']));
1586
+ }
1587
+ if ($p_header['extra_len'] != 0)
1588
+ {
1589
+ fputs($this->zip_fd, $p_header['extra'], $p_header['extra_len']);
1590
+ }
1591
+ return $v_result;
1592
+ }
1593
+ function privWriteCentralFileHeader(&$p_header)
1594
+ {
1595
+ $v_result=1;
1596
+ $v_date = getdate($p_header['mtime']);
1597
+ $v_mtime = ($v_date['hours']<<11) + ($v_date['minutes']<<5) + $v_date['seconds']/2;
1598
+ $v_mdate = (($v_date['year']-1980)<<9) + ($v_date['mon']<<5) + $v_date['mday'];
1599
+ $v_binary_data = pack("VvvvvvvVVVvvvvvVV", 0x02014b50,
1600
+ $p_header['version'], $p_header['version_extracted'],
1601
+ $p_header['flag'], $p_header['compression'],
1602
+ $v_mtime, $v_mdate, $p_header['crc'],
1603
+ $p_header['compressed_size'], $p_header['size'],
1604
+ strlen($p_header['stored_filename']),
1605
+ $p_header['extra_len'], $p_header['comment_len'],
1606
+ $p_header['disk'], $p_header['internal'],
1607
+ $p_header['external'], $p_header['offset']);
1608
+ fputs($this->zip_fd, $v_binary_data, 46);
1609
+ if (strlen($p_header['stored_filename']) != 0)
1610
+ {
1611
+ fputs($this->zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename']));
1612
+ }
1613
+ if ($p_header['extra_len'] != 0)
1614
+ {
1615
+ fputs($this->zip_fd, $p_header['extra'], $p_header['extra_len']);
1616
+ }
1617
+ if ($p_header['comment_len'] != 0)
1618
+ {
1619
+ fputs($this->zip_fd, $p_header['comment'], $p_header['comment_len']);
1620
+ }
1621
+ return $v_result;
1622
+ }
1623
+ function privWriteCentralHeader($p_nb_entries, $p_size, $p_offset, $p_comment)
1624
+ {
1625
+ $v_result=1;
1626
+ $v_binary_data = pack("VvvvvVVv", 0x06054b50, 0, 0, $p_nb_entries,
1627
+ $p_nb_entries, $p_size,
1628
+ $p_offset, strlen($p_comment));
1629
+ fputs($this->zip_fd, $v_binary_data, 22);
1630
+ if (strlen($p_comment) != 0)
1631
+ {
1632
+ fputs($this->zip_fd, $p_comment, strlen($p_comment));
1633
+ }
1634
+ return $v_result;
1635
+ }
1636
+ function privList(&$p_list)
1637
+ {
1638
+ $v_result=1;
1639
+ $this->privDisableMagicQuotes();
1640
+ if (($this->zip_fd = @fopen($this->zipname, 'rb')) == 0)
1641
+ {
1642
+ $this->privSwapBackMagicQuotes();
1643
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->zipname.'\' in binary read mode');
1644
+ return PclZip::errorCode();
1645
+ }
1646
+ $v_central_dir = array();
1647
+ if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1)
1648
+ {
1649
+ $this->privSwapBackMagicQuotes();
1650
+ return $v_result;
1651
+ }
1652
+ @rewind($this->zip_fd);
1653
+ if (@fseek($this->zip_fd, $v_central_dir['offset']))
1654
+ {
1655
+ $this->privSwapBackMagicQuotes();
1656
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
1657
+ return PclZip::errorCode();
1658
+ }
1659
+ for ($i=0; $i<$v_central_dir['entries']; $i++)
1660
+ {
1661
+ if (($v_result = $this->privReadCentralFileHeader($v_header)) != 1)
1662
+ {
1663
+ $this->privSwapBackMagicQuotes();
1664
+ return $v_result;
1665
+ }
1666
+ $v_header['index'] = $i;
1667
+ $this->privConvertHeader2FileInfo($v_header, $p_list[$i]);
1668
+ unset($v_header);
1669
+ }
1670
+ $this->privCloseFd();
1671
+ $this->privSwapBackMagicQuotes();
1672
+ return $v_result;
1673
+ }
1674
+ function privConvertHeader2FileInfo($p_header, &$p_info)
1675
+ {
1676
+ $v_result=1;
1677
+ $v_temp_path = PclZipUtilPathReduction($p_header['filename']);
1678
+ $p_info['filename'] = $v_temp_path;
1679
+ $v_temp_path = PclZipUtilPathReduction($p_header['stored_filename']);
1680
+ $p_info['stored_filename'] = $v_temp_path;
1681
+ $p_info['size'] = $p_header['size'];
1682
+ $p_info['compressed_size'] = $p_header['compressed_size'];
1683
+ $p_info['mtime'] = $p_header['mtime'];
1684
+ $p_info['comment'] = $p_header['comment'];
1685
+ $p_info['folder'] = (($p_header['external']&0x00000010)==0x00000010);
1686
+ $p_info['index'] = $p_header['index'];
1687
+ $p_info['status'] = $p_header['status'];
1688
+ $p_info['crc'] = $p_header['crc'];
1689
+ return $v_result;
1690
+ }
1691
+ function privExtractByRule(&$p_file_list, $p_path, $p_remove_path, $p_remove_all_path, &$p_options)
1692
+ {
1693
+ $v_result=1;
1694
+ $this->privDisableMagicQuotes();
1695
+ if ( ($p_path == "")
1696
+ || ( (substr($p_path, 0, 1) != "/")
1697
+ && (substr($p_path, 0, 3) != "../")
1698
+ && (substr($p_path,1,2)!=":/")))
1699
+ $p_path = "./".$p_path;
1700
+ if (($p_path != "./") && ($p_path != "/"))
1701
+ {
1702
+ while (substr($p_path, -1) == "/")
1703
+ {
1704
+ $p_path = substr($p_path, 0, strlen($p_path)-1);
1705
+ }
1706
+ }
1707
+ if (($p_remove_path != "") && (substr($p_remove_path, -1) != '/'))
1708
+ {
1709
+ $p_remove_path .= '/';
1710
+ }
1711
+ $p_remove_path_size = strlen($p_remove_path);
1712
+ if (($v_result = $this->privOpenFd('rb')) != 1)
1713
+ {
1714
+ $this->privSwapBackMagicQuotes();
1715
+ return $v_result;
1716
+ }
1717
+ $v_central_dir = array();
1718
+ if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1)
1719
+ {
1720
+ $this->privCloseFd();
1721
+ $this->privSwapBackMagicQuotes();
1722
+ return $v_result;
1723
+ }
1724
+ $v_pos_entry = $v_central_dir['offset'];
1725
+ $j_start = 0;
1726
+ for ($i=0, $v_nb_extracted=0; $i<$v_central_dir['entries']; $i++)
1727
+ {
1728
+ @rewind($this->zip_fd);
1729
+ if (@fseek($this->zip_fd, $v_pos_entry))
1730
+ {
1731
+ $this->privCloseFd();
1732
+ $this->privSwapBackMagicQuotes();
1733
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
1734
+ return PclZip::errorCode();
1735
+ }
1736
+ $v_header = array();
1737
+ if (($v_result = $this->privReadCentralFileHeader($v_header)) != 1)
1738
+ {
1739
+ $this->privCloseFd();
1740
+ $this->privSwapBackMagicQuotes();
1741
+ return $v_result;
1742
+ }
1743
+ $v_header['index'] = $i;
1744
+ $v_pos_entry = ftell($this->zip_fd);
1745
+ $v_extract = false;
1746
+ if ( (isset($p_options[PCLZIP_OPT_BY_NAME]))
1747
+ && ($p_options[PCLZIP_OPT_BY_NAME] != 0)) {
1748
+ for ($j=0; ($j<sizeof($p_options[PCLZIP_OPT_BY_NAME])) && (!$v_extract); $j++) {
1749
+ if (substr($p_options[PCLZIP_OPT_BY_NAME][$j], -1) == "/") {
1750
+ if ( (strlen($v_header['stored_filename']) > strlen($p_options[PCLZIP_OPT_BY_NAME][$j]))
1751
+ && (substr($v_header['stored_filename'], 0, strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) == $p_options[PCLZIP_OPT_BY_NAME][$j])) {
1752
+ $v_extract = true;
1753
+ }
1754
+ }
1755
+ elseif ($v_header['stored_filename'] == $p_options[PCLZIP_OPT_BY_NAME][$j]) {
1756
+ $v_extract = true;
1757
+ }
1758
+ }
1759
+ }
1760
+ /*
1761
+ else if ( (isset($p_options[PCLZIP_OPT_BY_EREG]))
1762
+ && ($p_options[PCLZIP_OPT_BY_EREG] != "")) {
1763
+ if (ereg($p_options[PCLZIP_OPT_BY_EREG], $v_header['stored_filename'])) {
1764
+ $v_extract = true;
1765
+ }
1766
+ }
1767
+ */
1768
+ else if ( (isset($p_options[PCLZIP_OPT_BY_PREG]))
1769
+ && ($p_options[PCLZIP_OPT_BY_PREG] != "")) {
1770
+ if (preg_match($p_options[PCLZIP_OPT_BY_PREG], $v_header['stored_filename'])) {
1771
+ $v_extract = true;
1772
+ }
1773
+ }
1774
+ else if ( (isset($p_options[PCLZIP_OPT_BY_INDEX]))
1775
+ && ($p_options[PCLZIP_OPT_BY_INDEX] != 0)) {
1776
+ for ($j=$j_start; ($j<sizeof($p_options[PCLZIP_OPT_BY_INDEX])) && (!$v_extract); $j++) {
1777
+ if (($i>=$p_options[PCLZIP_OPT_BY_INDEX][$j]['start']) && ($i<=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end'])) {
1778
+ $v_extract = true;
1779
+ }
1780
+ if ($i>=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end']) {
1781
+ $j_start = $j+1;
1782
+ }
1783
+ if ($p_options[PCLZIP_OPT_BY_INDEX][$j]['start']>$i) {
1784
+ break;
1785
+ }
1786
+ }
1787
+ }
1788
+ else {
1789
+ $v_extract = true;
1790
+ }
1791
+ // ----- Check compression method
1792
+ if ( ($v_extract)
1793
+ && ( ($v_header['compression'] != 8)
1794
+ && ($v_header['compression'] != 0))) {
1795
+ $v_header['status'] = 'unsupported_compression';
1796
+ if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR]))
1797
+ && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) {
1798
+ $this->privSwapBackMagicQuotes();
1799
+ PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_COMPRESSION,
1800
+ "Filename '".$v_header['stored_filename']."' is "
1801
+ ."compressed by an unsupported compression "
1802
+ ."method (".$v_header['compression'].") ");
1803
+ return PclZip::errorCode();
1804
+ }
1805
+ }
1806
+ // ----- Check encrypted files
1807
+ if (($v_extract) && (($v_header['flag'] & 1) == 1)) {
1808
+ $v_header['status'] = 'unsupported_encryption';
1809
+ if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR]))
1810
+ && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) {
1811
+ $this->privSwapBackMagicQuotes();
1812
+ PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_ENCRYPTION,
1813
+ "Unsupported encryption for "
1814
+ ." filename '".$v_header['stored_filename']
1815
+ ."'");
1816
+ return PclZip::errorCode();
1817
+ }
1818
+ }
1819
+ if (($v_extract) && ($v_header['status'] != 'ok')) {
1820
+ $v_result = $this->privConvertHeader2FileInfo($v_header,
1821
+ $p_file_list[$v_nb_extracted++]);
1822
+ if ($v_result != 1) {
1823
+ $this->privCloseFd();
1824
+ $this->privSwapBackMagicQuotes();
1825
+ return $v_result;
1826
+ }
1827
+ $v_extract = false;
1828
+ }
1829
+ if ($v_extract)
1830
+ {
1831
+ @rewind($this->zip_fd);
1832
+ if (@fseek($this->zip_fd, $v_header['offset']))
1833
+ {
1834
+ $this->privCloseFd();
1835
+ $this->privSwapBackMagicQuotes();
1836
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
1837
+ return PclZip::errorCode();
1838
+ }
1839
+ if ($p_options[PCLZIP_OPT_EXTRACT_AS_STRING]) {
1840
+ $v_string = '';
1841
+ $v_result1 = $this->privExtractFileAsString($v_header, $v_string, $p_options);
1842
+ if ($v_result1 < 1) {
1843
+ $this->privCloseFd();
1844
+ $this->privSwapBackMagicQuotes();
1845
+ return $v_result1;
1846
+ }
1847
+ if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted])) != 1)
1848
+ {
1849
+ $this->privCloseFd();
1850
+ $this->privSwapBackMagicQuotes();
1851
+ return $v_result;
1852
+ }
1853
+ $p_file_list[$v_nb_extracted]['content'] = $v_string;
1854
+ $v_nb_extracted++;
1855
+ if ($v_result1 == 2) {
1856
+ break;
1857
+ }
1858
+ }
1859
+ elseif ( (isset($p_options[PCLZIP_OPT_EXTRACT_IN_OUTPUT]))
1860
+ && ($p_options[PCLZIP_OPT_EXTRACT_IN_OUTPUT])) {
1861
+ $v_result1 = $this->privExtractFileInOutput($v_header, $p_options);
1862
+ if ($v_result1 < 1) {
1863
+ $this->privCloseFd();
1864
+ $this->privSwapBackMagicQuotes();
1865
+ return $v_result1;
1866
+ }
1867
+ if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++])) != 1) {
1868
+ $this->privCloseFd();
1869
+ $this->privSwapBackMagicQuotes();
1870
+ return $v_result;
1871
+ }
1872
+ if ($v_result1 == 2) {
1873
+ break;
1874
+ }
1875
+ }
1876
+ else {
1877
+ $v_result1 = $this->privExtractFile($v_header,
1878
+ $p_path, $p_remove_path,
1879
+ $p_remove_all_path,
1880
+ $p_options);
1881
+ if ($v_result1 < 1) {
1882
+ $this->privCloseFd();
1883
+ $this->privSwapBackMagicQuotes();
1884
+ return $v_result1;
1885
+ }
1886
+ if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++])) != 1)
1887
+ {
1888
+ $this->privCloseFd();
1889
+ $this->privSwapBackMagicQuotes();
1890
+ return $v_result;
1891
+ }
1892
+ if ($v_result1 == 2) {
1893
+ break;
1894
+ }
1895
+ }
1896
+ }
1897
+ }
1898
+ $this->privCloseFd();
1899
+ $this->privSwapBackMagicQuotes();
1900
+ return $v_result;
1901
+ }
1902
+ function privExtractFile(&$p_entry, $p_path, $p_remove_path, $p_remove_all_path, &$p_options)
1903
+ {
1904
+ $v_result=1;
1905
+ if (($v_result = $this->privReadFileHeader($v_header)) != 1)
1906
+ {
1907
+ return $v_result;
1908
+ }
1909
+ if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) {
1910
+ }
1911
+ if ($p_remove_all_path == true) {
1912
+ if (($p_entry['external']&0x00000010)==0x00000010) {
1913
+ $p_entry['status'] = "filtered";
1914
+ return $v_result;
1915
+ }
1916
+ $p_entry['filename'] = basename($p_entry['filename']);
1917
+ }
1918
+ else if ($p_remove_path != "")
1919
+ {
1920
+ if (PclZipUtilPathInclusion($p_remove_path, $p_entry['filename']) == 2)
1921
+ {
1922
+ $p_entry['status'] = "filtered";
1923
+ return $v_result;
1924
+ }
1925
+ $p_remove_path_size = strlen($p_remove_path);
1926
+ if (substr($p_entry['filename'], 0, $p_remove_path_size) == $p_remove_path)
1927
+ {
1928
+ $p_entry['filename'] = substr($p_entry['filename'], $p_remove_path_size);
1929
+ }
1930
+ }
1931
+ if ($p_path != '') {
1932
+ $p_entry['filename'] = $p_path."/".$p_entry['filename'];
1933
+ }
1934
+ if (isset($p_options[PCLZIP_OPT_EXTRACT_DIR_RESTRICTION])) {
1935
+ $v_inclusion
1936
+ = PclZipUtilPathInclusion($p_options[PCLZIP_OPT_EXTRACT_DIR_RESTRICTION],
1937
+ $p_entry['filename']);
1938
+ if ($v_inclusion == 0) {
1939
+ PclZip::privErrorLog(PCLZIP_ERR_DIRECTORY_RESTRICTION,
1940
+ "Filename '".$p_entry['filename']."' is "
1941
+ ."outside PCLZIP_OPT_EXTRACT_DIR_RESTRICTION");
1942
+ return PclZip::errorCode();
1943
+ }
1944
+ }
1945
+ if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) {
1946
+ $v_local_header = array();
1947
+ $this->privConvertHeader2FileInfo($p_entry, $v_local_header);
1948
+ // eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);');
1949
+ $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header);
1950
+ if ($v_result == 0) {
1951
+ $p_entry['status'] = "skipped";
1952
+ $v_result = 1;
1953
+ }
1954
+ if ($v_result == 2) {
1955
+ $p_entry['status'] = "aborted";
1956
+ $v_result = PCLZIP_ERR_USER_ABORTED;
1957
+ }
1958
+ $p_entry['filename'] = $v_local_header['filename'];
1959
+ }
1960
+ if ($p_entry['status'] == 'ok') {
1961
+ if (file_exists($p_entry['filename']))
1962
+ {
1963
+ if (is_dir($p_entry['filename']))
1964
+ {
1965
+ $p_entry['status'] = "already_a_directory";
1966
+ if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR]))
1967
+ && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) {
1968
+ PclZip::privErrorLog(PCLZIP_ERR_ALREADY_A_DIRECTORY,
1969
+ "Filename '".$p_entry['filename']."' is "
1970
+ ."already used by an existing directory");
1971
+ return PclZip::errorCode();
1972
+ }
1973
+ }
1974
+ else if (!is_writeable($p_entry['filename']))
1975
+ {
1976
+ $p_entry['status'] = "write_protected";
1977
+ if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR]))
1978
+ && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) {
1979
+ PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL,
1980
+ "Filename '".$p_entry['filename']."' exists "
1981
+ ."and is write protected");
1982
+ return PclZip::errorCode();
1983
+ }
1984
+ }
1985
+ else if (filemtime($p_entry['filename']) > $p_entry['mtime'])
1986
+ {
1987
+ if ( (isset($p_options[PCLZIP_OPT_REPLACE_NEWER]))
1988
+ && ($p_options[PCLZIP_OPT_REPLACE_NEWER]===true)) {
1989
+ }
1990
+ else {
1991
+ $p_entry['status'] = "newer_exist";
1992
+ if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR]))
1993
+ && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) {
1994
+ PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL,
1995
+ "Newer version of '".$p_entry['filename']."' exists "
1996
+ ."and option PCLZIP_OPT_REPLACE_NEWER is not selected");
1997
+ return PclZip::errorCode();
1998
+ }
1999
+ }
2000
+ }
2001
+ else {
2002
+ }
2003
+ }
2004
+ else {
2005
+ if ((($p_entry['external']&0x00000010)==0x00000010) || (substr($p_entry['filename'], -1) == '/'))
2006
+ $v_dir_to_check = $p_entry['filename'];
2007
+ else if (!strstr($p_entry['filename'], "/"))
2008
+ $v_dir_to_check = "";
2009
+ else
2010
+ $v_dir_to_check = dirname($p_entry['filename']);
2011
+ if (($v_result = $this->privDirCheck($v_dir_to_check, (($p_entry['external']&0x00000010)==0x00000010))) != 1) {
2012
+ $p_entry['status'] = "path_creation_fail";
2013
+ $v_result = 1;
2014
+ }
2015
+ }
2016
+ }
2017
+ if ($p_entry['status'] == 'ok') {
2018
+ if (!(($p_entry['external']&0x00000010)==0x00000010))
2019
+ {
2020
+ if ($p_entry['compression'] == 0) {
2021
+ // ----- Opening destination file
2022
+ if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0)
2023
+ {
2024
+ $p_entry['status'] = "write_error";
2025
+ return $v_result;
2026
+ }
2027
+ $v_size = $p_entry['compressed_size'];
2028
+ while ($v_size != 0)
2029
+ {
2030
+ $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
2031
+ $v_buffer = @fread($this->zip_fd, $v_read_size);
2032
+ /* Try to speed up the code
2033
+ $v_binary_data = pack('a'.$v_read_size, $v_buffer);
2034
+ @fwrite($v_dest_file, $v_binary_data, $v_read_size);
2035
+ */
2036
+ @fwrite($v_dest_file, $v_buffer, $v_read_size);
2037
+ $v_size -= $v_read_size;
2038
+ }
2039
+ fclose($v_dest_file);
2040
+ touch($p_entry['filename'], $p_entry['mtime']);
2041
+ }
2042
+ else {
2043
+ if (($p_entry['flag'] & 1) == 1) {
2044
+ PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_ENCRYPTION, 'File \''.$p_entry['filename'].'\' is encrypted. Encrypted files are not supported.');
2045
+ return PclZip::errorCode();
2046
+ }
2047
+ if ( (!isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF]))
2048
+ && (isset($p_options[PCLZIP_OPT_TEMP_FILE_ON])
2049
+ || (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD])
2050
+ && ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] <= $p_entry['size'])) ) ) {
2051
+ $v_result = $this->privExtractFileUsingTempFile($p_entry, $p_options);
2052
+ if ($v_result < PCLZIP_ERR_NO_ERROR) {
2053
+ return $v_result;
2054
+ }
2055
+ }
2056
+ else {
2057
+ $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']);
2058
+ $v_file_content = @gzinflate($v_buffer);
2059
+ unset($v_buffer);
2060
+ if ($v_file_content === FALSE) {
2061
+ $p_entry['status'] = "error";
2062
+ return $v_result;
2063
+ }
2064
+ if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) {
2065
+ $p_entry['status'] = "write_error";
2066
+ return $v_result;
2067
+ }
2068
+ @fwrite($v_dest_file, $v_file_content, $p_entry['size']);
2069
+ unset($v_file_content);
2070
+ @fclose($v_dest_file);
2071
+ }
2072
+ @touch($p_entry['filename'], $p_entry['mtime']);
2073
+ }
2074
+ if (isset($p_options[PCLZIP_OPT_SET_CHMOD])) {
2075
+ @chmod($p_entry['filename'], $p_options[PCLZIP_OPT_SET_CHMOD]);
2076
+ }
2077
+ }
2078
+ }
2079
+ // ----- Change abort status
2080
+ if ($p_entry['status'] == "aborted") {
2081
+ $p_entry['status'] = "skipped";
2082
+ }
2083
+ elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) {
2084
+ $v_local_header = array();
2085
+ $this->privConvertHeader2FileInfo($p_entry, $v_local_header);
2086
+ // eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);');
2087
+ $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header);
2088
+ if ($v_result == 2) {
2089
+ $v_result = PCLZIP_ERR_USER_ABORTED;
2090
+ }
2091
+ }
2092
+ return $v_result;
2093
+ }
2094
+ function privExtractFileUsingTempFile(&$p_entry, &$p_options)
2095
+ {
2096
+ $v_result=1;
2097
+ $v_gzip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.gz';
2098
+ if (($v_dest_file = @fopen($v_gzip_temp_name, "wb")) == 0) {
2099
+ fclose($v_file);
2100
+ PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary write mode');
2101
+ return PclZip::errorCode();
2102
+ }
2103
+ $v_binary_data = pack('va1a1Va1a1', 0x8b1f, Chr($p_entry['compression']), Chr(0x00), time(), Chr(0x00), Chr(3));
2104
+ @fwrite($v_dest_file, $v_binary_data, 10);
2105
+ $v_size = $p_entry['compressed_size'];
2106
+ while ($v_size != 0)
2107
+ {
2108
+ $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
2109
+ $v_buffer = @fread($this->zip_fd, $v_read_size);
2110
+ @fwrite($v_dest_file, $v_buffer, $v_read_size);
2111
+ $v_size -= $v_read_size;
2112
+ }
2113
+ $v_binary_data = pack('VV', $p_entry['crc'], $p_entry['size']);
2114
+ @fwrite($v_dest_file, $v_binary_data, 8);
2115
+ @fclose($v_dest_file);
2116
+ if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) {
2117
+ $p_entry['status'] = "write_error";
2118
+ return $v_result;
2119
+ }
2120
+ if (($v_src_file = @gzopen($v_gzip_temp_name, 'rb')) == 0) {
2121
+ @fclose($v_dest_file);
2122
+ $p_entry['status'] = "read_error";
2123
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary read mode');
2124
+ return PclZip::errorCode();
2125
+ }
2126
+ $v_size = $p_entry['size'];
2127
+ while ($v_size != 0) {
2128
+ $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
2129
+ $v_buffer = @gzread($v_src_file, $v_read_size);
2130
+ @fwrite($v_dest_file, $v_buffer, $v_read_size);
2131
+ $v_size -= $v_read_size;
2132
+ }
2133
+ @fclose($v_dest_file);
2134
+ @gzclose($v_src_file);
2135
+ @unlink($v_gzip_temp_name);
2136
+ return $v_result;
2137
+ }
2138
+ function privExtractFileInOutput(&$p_entry, &$p_options)
2139
+ {
2140
+ $v_result=1;
2141
+ if (($v_result = $this->privReadFileHeader($v_header)) != 1) {
2142
+ return $v_result;
2143
+ }
2144
+ if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) {
2145
+ }
2146
+ if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) {
2147
+ $v_local_header = array();
2148
+ $this->privConvertHeader2FileInfo($p_entry, $v_local_header);
2149
+ // eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);');
2150
+ $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header);
2151
+ if ($v_result == 0) {
2152
+ $p_entry['status'] = "skipped";
2153
+ $v_result = 1;
2154
+ }
2155
+ if ($v_result == 2) {
2156
+ $p_entry['status'] = "aborted";
2157
+ $v_result = PCLZIP_ERR_USER_ABORTED;
2158
+ }
2159
+ $p_entry['filename'] = $v_local_header['filename'];
2160
+ }
2161
+ if ($p_entry['status'] == 'ok') {
2162
+ if (!(($p_entry['external']&0x00000010)==0x00000010)) {
2163
+ if ($p_entry['compressed_size'] == $p_entry['size']) {
2164
+ $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']);
2165
+ echo $v_buffer;
2166
+ unset($v_buffer);
2167
+ }
2168
+ else {
2169
+ $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']);
2170
+ $v_file_content = gzinflate($v_buffer);
2171
+ unset($v_buffer);
2172
+ echo $v_file_content;
2173
+ unset($v_file_content);
2174
+ }
2175
+ }
2176
+ }
2177
+ // ----- Change abort status
2178
+ if ($p_entry['status'] == "aborted") {
2179
+ $p_entry['status'] = "skipped";
2180
+ }
2181
+ elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) {
2182
+ $v_local_header = array();
2183
+ $this->privConvertHeader2FileInfo($p_entry, $v_local_header);
2184
+ // eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);');
2185
+ $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header);
2186
+ if ($v_result == 2) {
2187
+ $v_result = PCLZIP_ERR_USER_ABORTED;
2188
+ }
2189
+ }
2190
+ return $v_result;
2191
+ }
2192
+ function privExtractFileAsString(&$p_entry, &$p_string, &$p_options)
2193
+ {
2194
+ $v_result=1;
2195
+ $v_header = array();
2196
+ if (($v_result = $this->privReadFileHeader($v_header)) != 1)
2197
+ {
2198
+ return $v_result;
2199
+ }
2200
+ if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) {
2201
+ }
2202
+ if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) {
2203
+ $v_local_header = array();
2204
+ $this->privConvertHeader2FileInfo($p_entry, $v_local_header);
2205
+ // eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);');
2206
+ $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header);
2207
+ if ($v_result == 0) {
2208
+ $p_entry['status'] = "skipped";
2209
+ $v_result = 1;
2210
+ }
2211
+ if ($v_result == 2) {
2212
+ $p_entry['status'] = "aborted";
2213
+ $v_result = PCLZIP_ERR_USER_ABORTED;
2214
+ }
2215
+ $p_entry['filename'] = $v_local_header['filename'];
2216
+ }
2217
+ if ($p_entry['status'] == 'ok') {
2218
+ if (!(($p_entry['external']&0x00000010)==0x00000010)) {
2219
+ if ($p_entry['compression'] == 0) {
2220
+ $p_string = @fread($this->zip_fd, $p_entry['compressed_size']);
2221
+ }
2222
+ else {
2223
+ $v_data = @fread($this->zip_fd, $p_entry['compressed_size']);
2224
+ if (($p_string = @gzinflate($v_data)) === FALSE) {
2225
+ }
2226
+ }
2227
+ }
2228
+ else {
2229
+ }
2230
+ }
2231
+ // ----- Change abort status
2232
+ if ($p_entry['status'] == "aborted") {
2233
+ $p_entry['status'] = "skipped";
2234
+ }
2235
+ elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) {
2236
+ $v_local_header = array();
2237
+ $this->privConvertHeader2FileInfo($p_entry, $v_local_header);
2238
+ $v_local_header['content'] = $p_string;
2239
+ $p_string = '';
2240
+ // eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);');
2241
+ $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header);
2242
+ $p_string = $v_local_header['content'];
2243
+ unset($v_local_header['content']);
2244
+ if ($v_result == 2) {
2245
+ $v_result = PCLZIP_ERR_USER_ABORTED;
2246
+ }
2247
+ }
2248
+ return $v_result;
2249
+ }
2250
+ function privReadFileHeader(&$p_header)
2251
+ {
2252
+ $v_result=1;
2253
+ $v_binary_data = @fread($this->zip_fd, 4);
2254
+ $v_data = unpack('Vid', $v_binary_data);
2255
+ if ($v_data['id'] != 0x04034b50)
2256
+ {
2257
+ PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Invalid archive structure');
2258
+ return PclZip::errorCode();
2259
+ }
2260
+ $v_binary_data = fread($this->zip_fd, 26);
2261
+ if (strlen($v_binary_data) != 26)
2262
+ {
2263
+ $p_header['filename'] = "";
2264
+ $p_header['status'] = "invalid_header";
2265
+ PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid block size : ".strlen($v_binary_data));
2266
+ return PclZip::errorCode();
2267
+ }
2268
+ $v_data = unpack('vversion/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len', $v_binary_data);
2269
+ $p_header['filename'] = fread($this->zip_fd, $v_data['filename_len']);
2270
+ if ($v_data['extra_len'] != 0) {
2271
+ $p_header['extra'] = fread($this->zip_fd, $v_data['extra_len']);
2272
+ }
2273
+ else {
2274
+ $p_header['extra'] = '';
2275
+ }
2276
+ $p_header['version_extracted'] = $v_data['version'];
2277
+ $p_header['compression'] = $v_data['compression'];
2278
+ $p_header['size'] = $v_data['size'];
2279
+ $p_header['compressed_size'] = $v_data['compressed_size'];
2280
+ $p_header['crc'] = $v_data['crc'];
2281
+ $p_header['flag'] = $v_data['flag'];
2282
+ $p_header['filename_len'] = $v_data['filename_len'];
2283
+ $p_header['mdate'] = $v_data['mdate'];
2284
+ $p_header['mtime'] = $v_data['mtime'];
2285
+ if ($p_header['mdate'] && $p_header['mtime'])
2286
+ {
2287
+ $v_hour = ($p_header['mtime'] & 0xF800) >> 11;
2288
+ $v_minute = ($p_header['mtime'] & 0x07E0) >> 5;
2289
+ $v_seconde = ($p_header['mtime'] & 0x001F)*2;
2290
+ $v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980;
2291
+ $v_month = ($p_header['mdate'] & 0x01E0) >> 5;
2292
+ $v_day = $p_header['mdate'] & 0x001F;
2293
+ $p_header['mtime'] = @mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year);
2294
+ }
2295
+ else
2296
+ {
2297
+ $p_header['mtime'] = time();
2298
+ }
2299
+ $p_header['stored_filename'] = $p_header['filename'];
2300
+ $p_header['status'] = "ok";
2301
+ return $v_result;
2302
+ }
2303
+ function privReadCentralFileHeader(&$p_header)
2304
+ {
2305
+ $v_result=1;
2306
+ $v_binary_data = @fread($this->zip_fd, 4);
2307
+ $v_data = unpack('Vid', $v_binary_data);
2308
+ if ($v_data['id'] != 0x02014b50)
2309
+ {
2310
+ PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Invalid archive structure');
2311
+ return PclZip::errorCode();
2312
+ }
2313
+ $v_binary_data = fread($this->zip_fd, 42);
2314
+ if (strlen($v_binary_data) != 42)
2315
+ {
2316
+ $p_header['filename'] = "";
2317
+ $p_header['status'] = "invalid_header";
2318
+ PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid block size : ".strlen($v_binary_data));
2319
+ return PclZip::errorCode();
2320
+ }
2321
+ $p_header = unpack('vversion/vversion_extracted/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len/vcomment_len/vdisk/vinternal/Vexternal/Voffset', $v_binary_data);
2322
+ if ($p_header['filename_len'] != 0)
2323
+ $p_header['filename'] = fread($this->zip_fd, $p_header['filename_len']);
2324
+ else
2325
+ $p_header['filename'] = '';
2326
+ if ($p_header['extra_len'] != 0)
2327
+ $p_header['extra'] = fread($this->zip_fd, $p_header['extra_len']);
2328
+ else
2329
+ $p_header['extra'] = '';
2330
+ if ($p_header['comment_len'] != 0)
2331
+ $p_header['comment'] = fread($this->zip_fd, $p_header['comment_len']);
2332
+ else
2333
+ $p_header['comment'] = '';
2334
+ if (1)
2335
+ {
2336
+ $v_hour = ($p_header['mtime'] & 0xF800) >> 11;
2337
+ $v_minute = ($p_header['mtime'] & 0x07E0) >> 5;
2338
+ $v_seconde = ($p_header['mtime'] & 0x001F)*2;
2339
+ $v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980;
2340
+ $v_month = ($p_header['mdate'] & 0x01E0) >> 5;
2341
+ $v_day = $p_header['mdate'] & 0x001F;
2342
+ $p_header['mtime'] = @mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year);
2343
+ }
2344
+ else
2345
+ {
2346
+ $p_header['mtime'] = time();
2347
+ }
2348
+ $p_header['stored_filename'] = $p_header['filename'];
2349
+ $p_header['status'] = 'ok';
2350
+ if (substr($p_header['filename'], -1) == '/') {
2351
+ $p_header['external'] = 0x00000010;
2352
+ }
2353
+ return $v_result;
2354
+ }
2355
+ function privCheckFileHeaders(&$p_local_header, &$p_central_header)
2356
+ {
2357
+ $v_result=1;
2358
+ // ----- Check the static values
2359
+ // TBC
2360
+ if ($p_local_header['filename'] != $p_central_header['filename']) {
2361
+ }
2362
+ if ($p_local_header['version_extracted'] != $p_central_header['version_extracted']) {
2363
+ }
2364
+ if ($p_local_header['flag'] != $p_central_header['flag']) {
2365
+ }
2366
+ if ($p_local_header['compression'] != $p_central_header['compression']) {
2367
+ }
2368
+ if ($p_local_header['mtime'] != $p_central_header['mtime']) {
2369
+ }
2370
+ if ($p_local_header['filename_len'] != $p_central_header['filename_len']) {
2371
+ }
2372
+ // ----- Look for flag bit 3
2373
+ if (($p_local_header['flag'] & 8) == 8) {
2374
+ $p_local_header['size'] = $p_central_header['size'];
2375
+ $p_local_header['compressed_size'] = $p_central_header['compressed_size'];
2376
+ $p_local_header['crc'] = $p_central_header['crc'];
2377
+ }
2378
+ return $v_result;
2379
+ }
2380
+ function privReadEndCentralDir(&$p_central_dir)
2381
+ {
2382
+ $v_result=1;
2383
+ $v_size = filesize($this->zipname);
2384
+ @fseek($this->zip_fd, $v_size);
2385
+ if (@ftell($this->zip_fd) != $v_size)
2386
+ {
2387
+ PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to go to the end of the archive \''.$this->zipname.'\'');
2388
+ return PclZip::errorCode();
2389
+ }
2390
+ $v_found = 0;
2391
+ if ($v_size > 26) {
2392
+ @fseek($this->zip_fd, $v_size-22);
2393
+ if (($v_pos = @ftell($this->zip_fd)) != ($v_size-22))
2394
+ {
2395
+ PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to seek back to the middle of the archive \''.$this->zipname.'\'');
2396
+ return PclZip::errorCode();
2397
+ }
2398
+ $v_binary_data = @fread($this->zip_fd, 4);
2399
+ $v_data = @unpack('Vid', $v_binary_data);
2400
+ if ($v_data['id'] == 0x06054b50) {
2401
+ $v_found = 1;
2402
+ }
2403
+ $v_pos = ftell($this->zip_fd);
2404
+ }
2405
+ if (!$v_found) {
2406
+ $v_maximum_size = 65557; // 0xFFFF + 22;
2407
+ if ($v_maximum_size > $v_size)
2408
+ $v_maximum_size = $v_size;
2409
+ @fseek($this->zip_fd, $v_size-$v_maximum_size);
2410
+ if (@ftell($this->zip_fd) != ($v_size-$v_maximum_size))
2411
+ {
2412
+ PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to seek back to the middle of the archive \''.$this->zipname.'\'');
2413
+ return PclZip::errorCode();
2414
+ }
2415
+ $v_pos = ftell($this->zip_fd);
2416
+ $v_bytes = 0x00000000;
2417
+ while ($v_pos < $v_size)
2418
+ {
2419
+ $v_byte = @fread($this->zip_fd, 1);
2420
+ $v_bytes = ( ($v_bytes & 0xFFFFFF) << 8) | Ord($v_byte);
2421
+ if ($v_bytes == 0x504b0506)
2422
+ {
2423
+ $v_pos++;
2424
+ break;
2425
+ }
2426
+ $v_pos++;
2427
+ }
2428
+ if ($v_pos == $v_size)
2429
+ {
2430
+ PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Unable to find End of Central Dir Record signature");
2431
+ return PclZip::errorCode();
2432
+ }
2433
+ }
2434
+ $v_binary_data = fread($this->zip_fd, 18);
2435
+ if (strlen($v_binary_data) != 18)
2436
+ {
2437
+ PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid End of Central Dir Record size : ".strlen($v_binary_data));
2438
+ return PclZip::errorCode();
2439
+ }
2440
+ $v_data = unpack('vdisk/vdisk_start/vdisk_entries/ventries/Vsize/Voffset/vcomment_size', $v_binary_data);
2441
+ if (($v_pos + $v_data['comment_size'] + 18) != $v_size) {
2442
+ // ----- Removed in release 2.2 see readme file
2443
+ // The check of the file size is a little too strict.
2444
+ // Some bugs where found when a zip is encrypted/decrypted with 'crypt'.
2445
+ // While decrypted, zip has training 0 bytes
2446
+ if (0) {
2447
+ PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT,
2448
+ 'The central dir is not at the end of the archive.'
2449
+ .' Some trailing bytes exists after the archive.');
2450
+ return PclZip::errorCode();
2451
+ }
2452
+ }
2453
+ if ($v_data['comment_size'] != 0) {
2454
+ $p_central_dir['comment'] = fread($this->zip_fd, $v_data['comment_size']);
2455
+ }
2456
+ else
2457
+ $p_central_dir['comment'] = '';
2458
+ $p_central_dir['entries'] = $v_data['entries'];
2459
+ $p_central_dir['disk_entries'] = $v_data['disk_entries'];
2460
+ $p_central_dir['offset'] = $v_data['offset'];
2461
+ $p_central_dir['size'] = $v_data['size'];
2462
+ $p_central_dir['disk'] = $v_data['disk'];
2463
+ $p_central_dir['disk_start'] = $v_data['disk_start'];
2464
+ return $v_result;
2465
+ }
2466
+ function privDeleteByRule(&$p_result_list, &$p_options)
2467
+ {
2468
+ $v_result=1;
2469
+ $v_list_detail = array();
2470
+ if (($v_result=$this->privOpenFd('rb')) != 1)
2471
+ {
2472
+ return $v_result;
2473
+ }
2474
+ $v_central_dir = array();
2475
+ if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1)
2476
+ {
2477
+ $this->privCloseFd();
2478
+ return $v_result;
2479
+ }
2480
+ @rewind($this->zip_fd);
2481
+ $v_pos_entry = $v_central_dir['offset'];
2482
+ @rewind($this->zip_fd);
2483
+ if (@fseek($this->zip_fd, $v_pos_entry))
2484
+ {
2485
+ $this->privCloseFd();
2486
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
2487
+ return PclZip::errorCode();
2488
+ }
2489
+ $v_header_list = array();
2490
+ $j_start = 0;
2491
+ for ($i=0, $v_nb_extracted=0; $i<$v_central_dir['entries']; $i++)
2492
+ {
2493
+ $v_header_list[$v_nb_extracted] = array();
2494
+ if (($v_result = $this->privReadCentralFileHeader($v_header_list[$v_nb_extracted])) != 1)
2495
+ {
2496
+ $this->privCloseFd();
2497
+ return $v_result;
2498
+ }
2499
+ $v_header_list[$v_nb_extracted]['index'] = $i;
2500
+ $v_found = false;
2501
+ if ( (isset($p_options[PCLZIP_OPT_BY_NAME]))
2502
+ && ($p_options[PCLZIP_OPT_BY_NAME] != 0)) {
2503
+ for ($j=0; ($j<sizeof($p_options[PCLZIP_OPT_BY_NAME])) && (!$v_found); $j++) {
2504
+ if (substr($p_options[PCLZIP_OPT_BY_NAME][$j], -1) == "/") {
2505
+ if ( (strlen($v_header_list[$v_nb_extracted]['stored_filename']) > strlen($p_options[PCLZIP_OPT_BY_NAME][$j]))
2506
+ && (substr($v_header_list[$v_nb_extracted]['stored_filename'], 0, strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) == $p_options[PCLZIP_OPT_BY_NAME][$j])) {
2507
+ $v_found = true;
2508
+ }
2509
+ elseif ( (($v_header_list[$v_nb_extracted]['external']&0x00000010)==0x00000010) /* Indicates a folder */
2510
+ && ($v_header_list[$v_nb_extracted]['stored_filename'].'/' == $p_options[PCLZIP_OPT_BY_NAME][$j])) {
2511
+ $v_found = true;
2512
+ }
2513
+ }
2514
+ elseif ($v_header_list[$v_nb_extracted]['stored_filename'] == $p_options[PCLZIP_OPT_BY_NAME][$j]) {
2515
+ $v_found = true;
2516
+ }
2517
+ }
2518
+ }
2519
+ /*
2520
+ else if ( (isset($p_options[PCLZIP_OPT_BY_EREG]))
2521
+ && ($p_options[PCLZIP_OPT_BY_EREG] != "")) {
2522
+ if (ereg($p_options[PCLZIP_OPT_BY_EREG], $v_header_list[$v_nb_extracted]['stored_filename'])) {
2523
+ $v_found = true;
2524
+ }
2525
+ }
2526
+ */
2527
+ else if ( (isset($p_options[PCLZIP_OPT_BY_PREG]))
2528
+ && ($p_options[PCLZIP_OPT_BY_PREG] != "")) {
2529
+ if (preg_match($p_options[PCLZIP_OPT_BY_PREG], $v_header_list[$v_nb_extracted]['stored_filename'])) {
2530
+ $v_found = true;
2531
+ }
2532
+ }
2533
+ else if ( (isset($p_options[PCLZIP_OPT_BY_INDEX]))
2534
+ && ($p_options[PCLZIP_OPT_BY_INDEX] != 0)) {
2535
+ for ($j=$j_start; ($j<sizeof($p_options[PCLZIP_OPT_BY_INDEX])) && (!$v_found); $j++) {
2536
+ if (($i>=$p_options[PCLZIP_OPT_BY_INDEX][$j]['start']) && ($i<=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end'])) {
2537
+ $v_found = true;
2538
+ }
2539
+ if ($i>=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end']) {
2540
+ $j_start = $j+1;
2541
+ }
2542
+ if ($p_options[PCLZIP_OPT_BY_INDEX][$j]['start']>$i) {
2543
+ break;
2544
+ }
2545
+ }
2546
+ }
2547
+ else {
2548
+ $v_found = true;
2549
+ }
2550
+ if ($v_found)
2551
+ {
2552
+ unset($v_header_list[$v_nb_extracted]);
2553
+ }
2554
+ else
2555
+ {
2556
+ $v_nb_extracted++;
2557
+ }
2558
+ }
2559
+ if ($v_nb_extracted > 0) {
2560
+ $v_zip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.tmp';
2561
+ $v_temp_zip = new PclZip($v_zip_temp_name);
2562
+ if (($v_result = $v_temp_zip->privOpenFd('wb')) != 1) {
2563
+ $this->privCloseFd();
2564
+ return $v_result;
2565
+ }
2566
+ for ($i=0; $i<sizeof($v_header_list); $i++) {
2567
+ @rewind($this->zip_fd);
2568
+ if (@fseek($this->zip_fd, $v_header_list[$i]['offset'])) {
2569
+ $this->privCloseFd();
2570
+ $v_temp_zip->privCloseFd();
2571
+ @unlink($v_zip_temp_name);
2572
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
2573
+ return PclZip::errorCode();
2574
+ }
2575
+ $v_local_header = array();
2576
+ if (($v_result = $this->privReadFileHeader($v_local_header)) != 1) {
2577
+ $this->privCloseFd();
2578
+ $v_temp_zip->privCloseFd();
2579
+ @unlink($v_zip_temp_name);
2580
+ return $v_result;
2581
+ }
2582
+ if ($this->privCheckFileHeaders($v_local_header,
2583
+ $v_header_list[$i]) != 1) {
2584
+ }
2585
+ unset($v_local_header);
2586
+ if (($v_result = $v_temp_zip->privWriteFileHeader($v_header_list[$i])) != 1) {
2587
+ $this->privCloseFd();
2588
+ $v_temp_zip->privCloseFd();
2589
+ @unlink($v_zip_temp_name);
2590
+ return $v_result;
2591
+ }
2592
+ if (($v_result = PclZipUtilCopyBlock($this->zip_fd, $v_temp_zip->zip_fd, $v_header_list[$i]['compressed_size'])) != 1) {
2593
+ $this->privCloseFd();
2594
+ $v_temp_zip->privCloseFd();
2595
+ @unlink($v_zip_temp_name);
2596
+ return $v_result;
2597
+ }
2598
+ }
2599
+ $v_offset = @ftell($v_temp_zip->zip_fd);
2600
+ for ($i=0; $i<sizeof($v_header_list); $i++) {
2601
+ if (($v_result = $v_temp_zip->privWriteCentralFileHeader($v_header_list[$i])) != 1) {
2602
+ $v_temp_zip->privCloseFd();
2603
+ $this->privCloseFd();
2604
+ @unlink($v_zip_temp_name);
2605
+ return $v_result;
2606
+ }
2607
+ $v_temp_zip->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]);
2608
+ }
2609
+ $v_comment = '';
2610
+ if (isset($p_options[PCLZIP_OPT_COMMENT])) {
2611
+ $v_comment = $p_options[PCLZIP_OPT_COMMENT];
2612
+ }
2613
+ $v_size = @ftell($v_temp_zip->zip_fd)-$v_offset;
2614
+ if (($v_result = $v_temp_zip->privWriteCentralHeader(sizeof($v_header_list), $v_size, $v_offset, $v_comment)) != 1) {
2615
+ unset($v_header_list);
2616
+ $v_temp_zip->privCloseFd();
2617
+ $this->privCloseFd();
2618
+ @unlink($v_zip_temp_name);
2619
+ return $v_result;
2620
+ }
2621
+ $v_temp_zip->privCloseFd();
2622
+ $this->privCloseFd();
2623
+ @unlink($this->zipname);
2624
+ PclZipUtilRename($v_zip_temp_name, $this->zipname);
2625
+ unset($v_temp_zip);
2626
+ }
2627
+ else if ($v_central_dir['entries'] != 0) {
2628
+ $this->privCloseFd();
2629
+ if (($v_result = $this->privOpenFd('wb')) != 1) {
2630
+ return $v_result;
2631
+ }
2632
+ if (($v_result = $this->privWriteCentralHeader(0, 0, 0, '')) != 1) {
2633
+ return $v_result;
2634
+ }
2635
+ $this->privCloseFd();
2636
+ }
2637
+ return $v_result;
2638
+ }
2639
+ function privDirCheck($p_dir, $p_is_dir=false)
2640
+ {
2641
+ $v_result = 1;
2642
+ if (($p_is_dir) && (substr($p_dir, -1)=='/'))
2643
+ {
2644
+ $p_dir = substr($p_dir, 0, strlen($p_dir)-1);
2645
+ }
2646
+ if ((is_dir($p_dir)) || ($p_dir == ""))
2647
+ {
2648
+ return 1;
2649
+ }
2650
+ $p_parent_dir = dirname($p_dir);
2651
+ if ($p_parent_dir != $p_dir)
2652
+ {
2653
+ if ($p_parent_dir != "")
2654
+ {
2655
+ if (($v_result = $this->privDirCheck($p_parent_dir)) != 1)
2656
+ {
2657
+ return $v_result;
2658
+ }
2659
+ }
2660
+ }
2661
+ if (!@mkdir($p_dir, 0777))
2662
+ {
2663
+ PclZip::privErrorLog(PCLZIP_ERR_DIR_CREATE_FAIL, "Unable to create directory '$p_dir'");
2664
+ return PclZip::errorCode();
2665
+ }
2666
+ return $v_result;
2667
+ }
2668
+ function privMerge(&$p_archive_to_add)
2669
+ {
2670
+ $v_result=1;
2671
+ if (!is_file($p_archive_to_add->zipname))
2672
+ {
2673
+ $v_result = 1;
2674
+ return $v_result;
2675
+ }
2676
+ if (!is_file($this->zipname))
2677
+ {
2678
+ $v_result = $this->privDuplicate($p_archive_to_add->zipname);
2679
+ return $v_result;
2680
+ }
2681
+ if (($v_result=$this->privOpenFd('rb')) != 1)
2682
+ {
2683
+ return $v_result;
2684
+ }
2685
+ $v_central_dir = array();
2686
+ if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1)
2687
+ {
2688
+ $this->privCloseFd();
2689
+ return $v_result;
2690
+ }
2691
+ @rewind($this->zip_fd);
2692
+ if (($v_result=$p_archive_to_add->privOpenFd('rb')) != 1)
2693
+ {
2694
+ $this->privCloseFd();
2695
+ return $v_result;
2696
+ }
2697
+ $v_central_dir_to_add = array();
2698
+ if (($v_result = $p_archive_to_add->privReadEndCentralDir($v_central_dir_to_add)) != 1)
2699
+ {
2700
+ $this->privCloseFd();
2701
+ $p_archive_to_add->privCloseFd();
2702
+ return $v_result;
2703
+ }
2704
+ @rewind($p_archive_to_add->zip_fd);
2705
+ $v_zip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.tmp';
2706
+ if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0)
2707
+ {
2708
+ $this->privCloseFd();
2709
+ $p_archive_to_add->privCloseFd();
2710
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_zip_temp_name.'\' in binary write mode');
2711
+ return PclZip::errorCode();
2712
+ }
2713
+ $v_size = $v_central_dir['offset'];
2714
+ while ($v_size != 0)
2715
+ {
2716
+ $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
2717
+ $v_buffer = fread($this->zip_fd, $v_read_size);
2718
+ @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size);
2719
+ $v_size -= $v_read_size;
2720
+ }
2721
+ $v_size = $v_central_dir_to_add['offset'];
2722
+ while ($v_size != 0)
2723
+ {
2724
+ $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
2725
+ $v_buffer = fread($p_archive_to_add->zip_fd, $v_read_size);
2726
+ @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size);
2727
+ $v_size -= $v_read_size;
2728
+ }
2729
+ $v_offset = @ftell($v_zip_temp_fd);
2730
+ $v_size = $v_central_dir['size'];
2731
+ while ($v_size != 0)
2732
+ {
2733
+ $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
2734
+ $v_buffer = @fread($this->zip_fd, $v_read_size);
2735
+ @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size);
2736
+ $v_size -= $v_read_size;
2737
+ }
2738
+ $v_size = $v_central_dir_to_add['size'];
2739
+ while ($v_size != 0)
2740
+ {
2741
+ $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
2742
+ $v_buffer = @fread($p_archive_to_add->zip_fd, $v_read_size);
2743
+ @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size);
2744
+ $v_size -= $v_read_size;
2745
+ }
2746
+ $v_comment = $v_central_dir['comment'].' '.$v_central_dir_to_add['comment'];
2747
+ $v_size = @ftell($v_zip_temp_fd)-$v_offset;
2748
+ $v_swap = $this->zip_fd;
2749
+ $this->zip_fd = $v_zip_temp_fd;
2750
+ $v_zip_temp_fd = $v_swap;
2751
+ if (($v_result = $this->privWriteCentralHeader($v_central_dir['entries']+$v_central_dir_to_add['entries'], $v_size, $v_offset, $v_comment)) != 1)
2752
+ {
2753
+ $this->privCloseFd();
2754
+ $p_archive_to_add->privCloseFd();
2755
+ @fclose($v_zip_temp_fd);
2756
+ $this->zip_fd = null;
2757
+ unset($v_header_list);
2758
+ return $v_result;
2759
+ }
2760
+ $v_swap = $this->zip_fd;
2761
+ $this->zip_fd = $v_zip_temp_fd;
2762
+ $v_zip_temp_fd = $v_swap;
2763
+ $this->privCloseFd();
2764
+ $p_archive_to_add->privCloseFd();
2765
+ @fclose($v_zip_temp_fd);
2766
+ @unlink($this->zipname);
2767
+ PclZipUtilRename($v_zip_temp_name, $this->zipname);
2768
+ return $v_result;
2769
+ }
2770
+ function privDuplicate($p_archive_filename)
2771
+ {
2772
+ $v_result=1;
2773
+ if (!is_file($p_archive_filename))
2774
+ {
2775
+ $v_result = 1;
2776
+ return $v_result;
2777
+ }
2778
+ if (($v_result=$this->privOpenFd('wb')) != 1)
2779
+ {
2780
+ return $v_result;
2781
+ }
2782
+ if (($v_zip_temp_fd = @fopen($p_archive_filename, 'rb')) == 0)
2783
+ {
2784
+ $this->privCloseFd();
2785
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive file \''.$p_archive_filename.'\' in binary write mode');
2786
+ return PclZip::errorCode();
2787
+ }
2788
+ $v_size = filesize($p_archive_filename);
2789
+ while ($v_size != 0)
2790
+ {
2791
+ $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
2792
+ $v_buffer = fread($v_zip_temp_fd, $v_read_size);
2793
+ @fwrite($this->zip_fd, $v_buffer, $v_read_size);
2794
+ $v_size -= $v_read_size;
2795
+ }
2796
+ $this->privCloseFd();
2797
+ @fclose($v_zip_temp_fd);
2798
+ return $v_result;
2799
+ }
2800
+ function privErrorLog($p_error_code=0, $p_error_string='')
2801
+ {
2802
+ if (PCLZIP_ERROR_EXTERNAL == 1) {
2803
+ PclError($p_error_code, $p_error_string);
2804
+ }
2805
+ else {
2806
+ $this->error_code = $p_error_code;
2807
+ $this->error_string = $p_error_string;
2808
+ }
2809
+ }
2810
+ function privErrorReset()
2811
+ {
2812
+ if (PCLZIP_ERROR_EXTERNAL == 1) {
2813
+ PclErrorReset();
2814
+ }
2815
+ else {
2816
+ $this->error_code = 0;
2817
+ $this->error_string = '';
2818
+ }
2819
+ }
2820
+ function privDisableMagicQuotes()
2821
+ {
2822
+ $v_result=1;
2823
+ if ( (!function_exists("get_magic_quotes_runtime"))
2824
+ || (!function_exists("set_magic_quotes_runtime"))) {
2825
+ return $v_result;
2826
+ }
2827
+ if ($this->magic_quotes_status != -1) {
2828
+ return $v_result;
2829
+ }
2830
+ // ----- Get and memorize the magic_quote value
2831
+ $this->magic_quotes_status = @get_magic_quotes_runtime();
2832
+ // ----- Disable magic_quotes
2833
+ if ($this->magic_quotes_status == 1) {
2834
+ @set_magic_quotes_runtime(0);
2835
+ }
2836
+ return $v_result;
2837
+ }
2838
+ function privSwapBackMagicQuotes()
2839
+ {
2840
+ $v_result=1;
2841
+ if ( (!function_exists("get_magic_quotes_runtime"))
2842
+ || (!function_exists("set_magic_quotes_runtime"))) {
2843
+ return $v_result;
2844
+ }
2845
+ if ($this->magic_quotes_status != -1) {
2846
+ return $v_result;
2847
+ }
2848
+ // ----- Swap back magic_quotes
2849
+ if ($this->magic_quotes_status == 1) {
2850
+ @set_magic_quotes_runtime($this->magic_quotes_status);
2851
+ }
2852
+ return $v_result;
2853
+ }
2854
+ }
2855
+ function PclZipUtilPathReduction($p_dir)
2856
+ {
2857
+ $v_result = "";
2858
+ if ($p_dir != "") {
2859
+ $v_list = explode("/", $p_dir);
2860
+ $v_skip = 0;
2861
+ for ($i=sizeof($v_list)-1; $i>=0; $i--) {
2862
+ if ($v_list[$i] == ".") {
2863
+ }
2864
+ else if ($v_list[$i] == "..") {
2865
+ $v_skip++;
2866
+ }
2867
+ else if ($v_list[$i] == "") {
2868
+ // ----- First '/' i.e. root slash
2869
+ if ($i == 0) {
2870
+ $v_result = "/".$v_result;
2871
+ if ($v_skip > 0) {
2872
+ // ----- It is an invalid path, so the path is not modified
2873
+ // TBC
2874
+ $v_result = $p_dir;
2875
+ $v_skip = 0;
2876
+ }
2877
+ }
2878
+ // ----- Last '/' i.e. indicates a directory
2879
+ else if ($i == (sizeof($v_list)-1)) {
2880
+ $v_result = $v_list[$i];
2881
+ }
2882
+ // ----- Double '/' inside the path
2883
+ else {
2884
+ }
2885
+ }
2886
+ else {
2887
+ // ----- Look for item to skip
2888
+ if ($v_skip > 0) {
2889
+ $v_skip--;
2890
+ }
2891
+ else {
2892
+ $v_result = $v_list[$i].($i!=(sizeof($v_list)-1)?"/".$v_result:"");
2893
+ }
2894
+ }
2895
+ }
2896
+ if ($v_skip > 0) {
2897
+ while ($v_skip > 0) {
2898
+ $v_result = '../'.$v_result;
2899
+ $v_skip--;
2900
+ }
2901
+ }
2902
+ }
2903
+ return $v_result;
2904
+ }
2905
+ function PclZipUtilPathInclusion($p_dir, $p_path)
2906
+ {
2907
+ $v_result = 1;
2908
+ if ( ($p_dir == '.')
2909
+ || ((strlen($p_dir) >=2) && (substr($p_dir, 0, 2) == './'))) {
2910
+ $p_dir = PclZipUtilTranslateWinPath(getcwd(), FALSE).'/'.substr($p_dir, 1);
2911
+ }
2912
+ if ( ($p_path == '.')
2913
+ || ((strlen($p_path) >=2) && (substr($p_path, 0, 2) == './'))) {
2914
+ $p_path = PclZipUtilTranslateWinPath(getcwd(), FALSE).'/'.substr($p_path, 1);
2915
+ }
2916
+ $v_list_dir = explode("/", $p_dir);
2917
+ $v_list_dir_size = sizeof($v_list_dir);
2918
+ $v_list_path = explode("/", $p_path);
2919
+ $v_list_path_size = sizeof($v_list_path);
2920
+ $i = 0;
2921
+ $j = 0;
2922
+ while (($i < $v_list_dir_size) && ($j < $v_list_path_size) && ($v_result)) {
2923
+ if ($v_list_dir[$i] == '') {
2924
+ $i++;
2925
+ continue;
2926
+ }
2927
+ if ($v_list_path[$j] == '') {
2928
+ $j++;
2929
+ continue;
2930
+ }
2931
+ if (($v_list_dir[$i] != $v_list_path[$j]) && ($v_list_dir[$i] != '') && ( $v_list_path[$j] != '')) {
2932
+ $v_result = 0;
2933
+ }
2934
+ $i++;
2935
+ $j++;
2936
+ }
2937
+ if ($v_result) {
2938
+ while (($j < $v_list_path_size) && ($v_list_path[$j] == '')) $j++;
2939
+ while (($i < $v_list_dir_size) && ($v_list_dir[$i] == '')) $i++;
2940
+ if (($i >= $v_list_dir_size) && ($j >= $v_list_path_size)) {
2941
+ $v_result = 2;
2942
+ }
2943
+ else if ($i < $v_list_dir_size) {
2944
+ $v_result = 0;
2945
+ }
2946
+ }
2947
+ return $v_result;
2948
+ }
2949
+ function PclZipUtilCopyBlock($p_src, $p_dest, $p_size, $p_mode=0)
2950
+ {
2951
+ $v_result = 1;
2952
+ if ($p_mode==0)
2953
+ {
2954
+ while ($p_size != 0)
2955
+ {
2956
+ $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE);
2957
+ $v_buffer = @fread($p_src, $v_read_size);
2958
+ @fwrite($p_dest, $v_buffer, $v_read_size);
2959
+ $p_size -= $v_read_size;
2960
+ }
2961
+ }
2962
+ else if ($p_mode==1)
2963
+ {
2964
+ while ($p_size != 0)
2965
+ {
2966
+ $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE);
2967
+ $v_buffer = @gzread($p_src, $v_read_size);
2968
+ @fwrite($p_dest, $v_buffer, $v_read_size);
2969
+ $p_size -= $v_read_size;
2970
+ }
2971
+ }
2972
+ else if ($p_mode==2)
2973
+ {
2974
+ while ($p_size != 0)
2975
+ {
2976
+ $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE);
2977
+ $v_buffer = @fread($p_src, $v_read_size);
2978
+ @gzwrite($p_dest, $v_buffer, $v_read_size);
2979
+ $p_size -= $v_read_size;
2980
+ }
2981
+ }
2982
+ else if ($p_mode==3)
2983
+ {
2984
+ while ($p_size != 0)
2985
+ {
2986
+ $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE);
2987
+ $v_buffer = @gzread($p_src, $v_read_size);
2988
+ @gzwrite($p_dest, $v_buffer, $v_read_size);
2989
+ $p_size -= $v_read_size;
2990
+ }
2991
+ }
2992
+ return $v_result;
2993
+ }
2994
+ function PclZipUtilRename($p_src, $p_dest)
2995
+ {
2996
+ $v_result = 1;
2997
+ if (!@rename($p_src, $p_dest)) {
2998
+ if (!@copy($p_src, $p_dest)) {
2999
+ $v_result = 0;
3000
+ }
3001
+ else if (!@unlink($p_src)) {
3002
+ $v_result = 0;
3003
+ }
3004
+ }
3005
+ return $v_result;
3006
+ }
3007
+ function PclZipUtilOptionText($p_option)
3008
+ {
3009
+ $v_list = get_defined_constants();
3010
+ for (reset($v_list); $v_key = key($v_list); next($v_list)) {
3011
+ $v_prefix = substr($v_key, 0, 10);
3012
+ if (( ($v_prefix == 'PCLZIP_OPT')
3013
+ || ($v_prefix == 'PCLZIP_CB_')
3014
+ || ($v_prefix == 'PCLZIP_ATT'))
3015
+ && ($v_list[$v_key] == $p_option)) {
3016
+ return $v_key;
3017
+ }
3018
+ }
3019
+ $v_result = 'Unknown';
3020
+ return $v_result;
3021
+ }
3022
+ function PclZipUtilTranslateWinPath($p_path, $p_remove_disk_letter=true)
3023
+ {
3024
+ if (stristr(php_uname(), 'windows')) {
3025
+ if (($p_remove_disk_letter) && (($v_position = strpos($p_path, ':')) != false)) {
3026
+ $p_path = substr($p_path, $v_position+1);
3027
+ }
3028
+ if ((strpos($p_path, '\\') > 0) || (substr($p_path, 0,1) == '\\')) {
3029
+ $p_path = strtr($p_path, '\\', '/');
3030
+ }
3031
+ }
3032
+ return $p_path;
3033
+ }
3034
+ ?>
modules/phpseclib/Crypt/AES.php ADDED
@@ -0,0 +1,540 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3
+
4
+ /**
5
+ * Pure-PHP implementation of AES.
6
+ *
7
+ * Uses mcrypt, if available, and an internal implementation, otherwise.
8
+ *
9
+ * PHP versions 4 and 5
10
+ *
11
+ * If {@link Crypt_AES::setKeyLength() setKeyLength()} isn't called, it'll be calculated from
12
+ * {@link Crypt_AES::setKey() setKey()}. ie. if the key is 128-bits, the key length will be 128-bits. If it's 136-bits
13
+ * it'll be null-padded to 160-bits and 160 bits will be the key length until {@link Crypt_Rijndael::setKey() setKey()}
14
+ * is called, again, at which point, it'll be recalculated.
15
+ *
16
+ * Since Crypt_AES extends Crypt_Rijndael, some functions are available to be called that, in the context of AES, don't
17
+ * make a whole lot of sense. {@link Crypt_AES::setBlockLength() setBlockLength()}, for instance. Calling that function,
18
+ * however possible, won't do anything (AES has a fixed block length whereas Rijndael has a variable one).
19
+ *
20
+ * Here's a short example of how to use this library:
21
+ * <code>
22
+ * <?php
23
+ * include('Crypt/AES.php');
24
+ *
25
+ * $aes = new Crypt_AES();
26
+ *
27
+ * $aes->setKey('abcdefghijklmnop');
28
+ *
29
+ * $size = 10 * 1024;
30
+ * $plaintext = '';
31
+ * for ($i = 0; $i < $size; $i++) {
32
+ * $plaintext.= 'a';
33
+ * }
34
+ *
35
+ * echo $aes->decrypt($aes->encrypt($plaintext));
36
+ * ?>
37
+ * </code>
38
+ *
39
+ * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
40
+ * of this software and associated documentation files (the "Software"), to deal
41
+ * in the Software without restriction, including without limitation the rights
42
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
43
+ * copies of the Software, and to permit persons to whom the Software is
44
+ * furnished to do so, subject to the following conditions:
45
+ *
46
+ * The above copyright notice and this permission notice shall be included in
47
+ * all copies or substantial portions of the Software.
48
+ *
49
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
50
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
51
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
52
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
53
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
54
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
55
+ * THE SOFTWARE.
56
+ *
57
+ * @category Crypt
58
+ * @package Crypt_AES
59
+ * @author Jim Wigginton <terrafrost@php.net>
60
+ * @copyright MMVIII Jim Wigginton
61
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
62
+ * @link http://phpseclib.sourceforge.net
63
+ */
64
+
65
+ /**
66
+ * Include Crypt_Rijndael
67
+ */
68
+ if (!class_exists('Crypt_Rijndael')) {
69
+ require_once 'Rijndael.php';
70
+ }
71
+
72
+ /**#@+
73
+ * @access public
74
+ * @see Crypt_AES::encrypt()
75
+ * @see Crypt_AES::decrypt()
76
+ */
77
+ /**
78
+ * Encrypt / decrypt using the Counter mode.
79
+ *
80
+ * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
81
+ *
82
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
83
+ */
84
+ define('CRYPT_AES_MODE_CTR', -1);
85
+ /**
86
+ * Encrypt / decrypt using the Electronic Code Book mode.
87
+ *
88
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
89
+ */
90
+ define('CRYPT_AES_MODE_ECB', 1);
91
+ /**
92
+ * Encrypt / decrypt using the Code Book Chaining mode.
93
+ *
94
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
95
+ */
96
+ define('CRYPT_AES_MODE_CBC', 2);
97
+ /**
98
+ * Encrypt / decrypt using the Cipher Feedback mode.
99
+ *
100
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
101
+ */
102
+ define('CRYPT_AES_MODE_CFB', 3);
103
+ /**
104
+ * Encrypt / decrypt using the Cipher Feedback mode.
105
+ *
106
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
107
+ */
108
+ define('CRYPT_AES_MODE_OFB', 4);
109
+ /**#@-*/
110
+
111
+ /**#@+
112
+ * @access private
113
+ * @see Crypt_AES::Crypt_AES()
114
+ */
115
+ /**
116
+ * Toggles the internal implementation
117
+ */
118
+ define('CRYPT_AES_MODE_INTERNAL', 1);
119
+ /**
120
+ * Toggles the mcrypt implementation
121
+ */
122
+ define('CRYPT_AES_MODE_MCRYPT', 2);
123
+ /**#@-*/
124
+
125
+ /**
126
+ * Pure-PHP implementation of AES.
127
+ *
128
+ * @author Jim Wigginton <terrafrost@php.net>
129
+ * @version 0.1.0
130
+ * @access public
131
+ * @package Crypt_AES
132
+ */
133
+ class Crypt_AES extends Crypt_Rijndael {
134
+ /**
135
+ * mcrypt resource for encryption
136
+ *
137
+ * The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
138
+ * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
139
+ *
140
+ * @see Crypt_AES::encrypt()
141
+ * @var String
142
+ * @access private
143
+ */
144
+ var $enmcrypt;
145
+
146
+ /**
147
+ * mcrypt resource for decryption
148
+ *
149
+ * The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
150
+ * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
151
+ *
152
+ * @see Crypt_AES::decrypt()
153
+ * @var String
154
+ * @access private
155
+ */
156
+ var $demcrypt;
157
+
158
+ /**
159
+ * mcrypt resource for CFB mode
160
+ *
161
+ * @see Crypt_AES::encrypt()
162
+ * @see Crypt_AES::decrypt()
163
+ * @var String
164
+ * @access private
165
+ */
166
+ var $ecb;
167
+
168
+ /**
169
+ * Default Constructor.
170
+ *
171
+ * Determines whether or not the mcrypt extension should be used. $mode should only, at present, be
172
+ * CRYPT_AES_MODE_ECB or CRYPT_AES_MODE_CBC. If not explictly set, CRYPT_AES_MODE_CBC will be used.
173
+ *
174
+ * @param optional Integer $mode
175
+ * @return Crypt_AES
176
+ * @access public
177
+ */
178
+ function Crypt_AES($mode = CRYPT_AES_MODE_CBC)
179
+ {
180
+ if ( !defined('CRYPT_AES_MODE') ) {
181
+ switch (true) {
182
+ case extension_loaded('mcrypt') && in_array('rijndael-128', mcrypt_list_algorithms()):
183
+ define('CRYPT_AES_MODE', CRYPT_AES_MODE_MCRYPT);
184
+ break;
185
+ default:
186
+ define('CRYPT_AES_MODE', CRYPT_AES_MODE_INTERNAL);
187
+ }
188
+ }
189
+
190
+ switch ( CRYPT_AES_MODE ) {
191
+ case CRYPT_AES_MODE_MCRYPT:
192
+ switch ($mode) {
193
+ case CRYPT_AES_MODE_ECB:
194
+ $this->paddable = true;
195
+ $this->mode = MCRYPT_MODE_ECB;
196
+ break;
197
+ case CRYPT_AES_MODE_CTR:
198
+ // ctr doesn't have a constant associated with it even though it appears to be fairly widely
199
+ // supported. in lieu of knowing just how widely supported it is, i've, for now, opted not to
200
+ // include a compatibility layer. the layer has been implemented but, for now, is commented out.
201
+ $this->mode = 'ctr';
202
+ //$this->mode = in_array('ctr', mcrypt_list_modes()) ? 'ctr' : CRYPT_AES_MODE_CTR;
203
+ break;
204
+ case CRYPT_AES_MODE_CFB:
205
+ $this->mode = 'ncfb';
206
+ break;
207
+ case CRYPT_AES_MODE_OFB:
208
+ $this->mode = MCRYPT_MODE_NOFB;
209
+ break;
210
+ case CRYPT_AES_MODE_CBC:
211
+ default:
212
+ $this->paddable = true;
213
+ $this->mode = MCRYPT_MODE_CBC;
214
+ }
215
+
216
+ break;
217
+ default:
218
+ switch ($mode) {
219
+ case CRYPT_AES_MODE_ECB:
220
+ $this->paddable = true;
221
+ $this->mode = CRYPT_RIJNDAEL_MODE_ECB;
222
+ break;
223
+ case CRYPT_AES_MODE_CTR:
224
+ $this->mode = CRYPT_RIJNDAEL_MODE_CTR;
225
+ break;
226
+ case CRYPT_AES_MODE_CFB:
227
+ $this->mode = CRYPT_RIJNDAEL_MODE_CFB;
228
+ break;
229
+ case CRYPT_AES_MODE_OFB:
230
+ $this->mode = CRYPT_RIJNDAEL_MODE_OFB;
231
+ break;
232
+ case CRYPT_AES_MODE_CBC:
233
+ default:
234
+ $this->paddable = true;
235
+ $this->mode = CRYPT_RIJNDAEL_MODE_CBC;
236
+ }
237
+ }
238
+
239
+ if (CRYPT_AES_MODE == CRYPT_AES_MODE_INTERNAL) {
240
+ parent::Crypt_Rijndael($this->mode);
241
+ }
242
+
243
+ }
244
+
245
+ /**
246
+ * Dummy function
247
+ *
248
+ * Since Crypt_AES extends Crypt_Rijndael, this function is, technically, available, but it doesn't do anything.
249
+ *
250
+ * @access public
251
+ * @param Integer $length
252
+ */
253
+ function setBlockLength($length)
254
+ {
255
+ return;
256
+ }
257
+
258
+ /**
259
+ * Sets the initialization vector. (optional)
260
+ *
261
+ * SetIV is not required when CRYPT_RIJNDAEL_MODE_ECB is being used. If not explictly set, it'll be assumed
262
+ * to be all zero's.
263
+ *
264
+ * @access public
265
+ * @param String $iv
266
+ */
267
+ function setIV($iv)
268
+ {
269
+ parent::setIV($iv);
270
+ if ( CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT ) {
271
+ $this->changed = true;
272
+ }
273
+ }
274
+
275
+ /**
276
+ * Encrypts a message.
277
+ *
278
+ * $plaintext will be padded with up to 16 additional bytes. Other AES implementations may or may not pad in the
279
+ * same manner. Other common approaches to padding and the reasons why it's necessary are discussed in the following
280
+ * URL:
281
+ *
282
+ * {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html}
283
+ *
284
+ * An alternative to padding is to, separately, send the length of the file. This is what SSH, in fact, does.
285
+ * strlen($plaintext) will still need to be a multiple of 16, however, arbitrary values can be added to make it that
286
+ * length.
287
+ *
288
+ * @see Crypt_AES::decrypt()
289
+ * @access public
290
+ * @param String $plaintext
291
+ */
292
+ function encrypt($plaintext)
293
+ {
294
+ if ( CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT ) {
295
+ $this->_mcryptSetup();
296
+
297
+ // re: http://phpseclib.sourceforge.net/cfb-demo.phps
298
+ // using mcrypt's default handing of CFB the above would output two different things. using phpseclib's
299
+ // rewritten CFB implementation the above outputs the same thing twice.
300
+ if ($this->mode == 'ncfb' && $this->continuousBuffer) {
301
+ $iv = &$this->encryptIV;
302
+ $pos = &$this->enbuffer['pos'];
303
+ $len = strlen($plaintext);
304
+ $ciphertext = '';
305
+ $i = 0;
306
+ if ($pos) {
307
+ $orig_pos = $pos;
308
+ $max = 16 - $pos;
309
+ if ($len >= $max) {
310
+ $i = $max;
311
+ $len-= $max;
312
+ $pos = 0;
313
+ } else {
314
+ $i = $len;
315
+ $pos+= $len;
316
+ $len = 0;
317
+ }
318
+ $ciphertext = substr($iv, $orig_pos) ^ $plaintext;
319
+ $iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
320
+ $this->enbuffer['enmcrypt_init'] = true;
321
+ }
322
+ if ($len >= 16) {
323
+ if ($this->enbuffer['enmcrypt_init'] === false || $len > 280) {
324
+ if ($this->enbuffer['enmcrypt_init'] === true) {
325
+ mcrypt_generic_init($this->enmcrypt, $this->key, $iv);
326
+ $this->enbuffer['enmcrypt_init'] = false;
327
+ }
328
+ $ciphertext.= mcrypt_generic($this->enmcrypt, substr($plaintext, $i, $len - $len % 16));
329
+ $iv = substr($ciphertext, -16);
330
+ $len%= 16;
331
+ } else {
332
+ while ($len >= 16) {
333
+ $iv = mcrypt_generic($this->ecb, $iv) ^ substr($plaintext, $i, 16);
334
+ $ciphertext.= $iv;
335
+ $len-= 16;
336
+ $i+= 16;
337
+ }
338
+ }
339
+ }
340
+
341
+ if ($len) {
342
+ $iv = mcrypt_generic($this->ecb, $iv);
343
+ $block = $iv ^ substr($plaintext, -$len);
344
+ $iv = substr_replace($iv, $block, 0, $len);
345
+ $ciphertext.= $block;
346
+ $pos = $len;
347
+ }
348
+
349
+ return $ciphertext;
350
+ }
351
+
352
+ if ($this->paddable) {
353
+ $plaintext = $this->_pad($plaintext);
354
+ }
355
+
356
+ $ciphertext = mcrypt_generic($this->enmcrypt, $plaintext);
357
+
358
+ if (!$this->continuousBuffer) {
359
+ mcrypt_generic_init($this->enmcrypt, $this->key, $this->iv);
360
+ }
361
+
362
+ return $ciphertext;
363
+ }
364
+
365
+ return parent::encrypt($plaintext);
366
+ }
367
+
368
+ /**
369
+ * Decrypts a message.
370
+ *
371
+ * If strlen($ciphertext) is not a multiple of 16, null bytes will be added to the end of the string until it is.
372
+ *
373
+ * @see Crypt_AES::encrypt()
374
+ * @access public
375
+ * @param String $ciphertext
376
+ */
377
+ function decrypt($ciphertext)
378
+ {
379
+ if ( CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT ) {
380
+ $this->_mcryptSetup();
381
+
382
+ if ($this->mode == 'ncfb' && $this->continuousBuffer) {
383
+ $iv = &$this->decryptIV;
384
+ $pos = &$this->debuffer['pos'];
385
+ $len = strlen($ciphertext);
386
+ $plaintext = '';
387
+ $i = 0;
388
+ if ($pos) {
389
+ $orig_pos = $pos;
390
+ $max = 16 - $pos;
391
+ if ($len >= $max) {
392
+ $i = $max;
393
+ $len-= $max;
394
+ $pos = 0;
395
+ } else {
396
+ $i = $len;
397
+ $pos+= $len;
398
+ $len = 0;
399
+ }
400
+ // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
401
+ $plaintext = substr($iv, $orig_pos) ^ $ciphertext;
402
+ $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
403
+ }
404
+ if ($len >= 16) {
405
+ $cb = substr($ciphertext, $i, $len - $len % 16);
406
+ $plaintext.= mcrypt_generic($this->ecb, $iv . $cb) ^ $cb;
407
+ $iv = substr($cb, -16);
408
+ $len%= 16;
409
+ }
410
+ if ($len) {
411
+ $iv = mcrypt_generic($this->ecb, $iv);
412
+ $plaintext.= $iv ^ substr($ciphertext, -$len);
413
+ $iv = substr_replace($iv, substr($ciphertext, -$len), 0, $len);
414
+ $pos = $len;
415
+ }
416
+
417
+ return $plaintext;
418
+ }
419
+
420
+ if ($this->paddable) {
421
+ // we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic :
422
+ // "The data is padded with "\0" to make sure the length of the data is n * blocksize."
423
+ $ciphertext = str_pad($ciphertext, (strlen($ciphertext) + 15) & 0xFFFFFFF0, chr(0));
424
+ }
425
+
426
+ $plaintext = mdecrypt_generic($this->demcrypt, $ciphertext);
427
+
428
+ if (!$this->continuousBuffer) {
429
+ mcrypt_generic_init($this->demcrypt, $this->key, $this->iv);
430
+ }
431
+
432
+ return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
433
+ }
434
+
435
+ return parent::decrypt($ciphertext);
436
+ }
437
+
438
+ /**
439
+ * Setup mcrypt
440
+ *
441
+ * Validates all the variables.
442
+ *
443
+ * @access private
444
+ */
445
+ function _mcryptSetup()
446
+ {
447
+ if (!$this->changed) {
448
+ return;
449
+ }
450
+
451
+ if (!$this->explicit_key_length) {
452
+ // this just copied from Crypt_Rijndael::_setup()
453
+ $length = strlen($this->key) >> 2;
454
+ if ($length > 8) {
455
+ $length = 8;
456
+ } else if ($length < 4) {
457
+ $length = 4;
458
+ }
459
+ $this->Nk = $length;
460
+ $this->key_size = $length << 2;
461
+ }
462
+
463
+ switch ($this->Nk) {
464
+ case 4: // 128
465
+ $this->key_size = 16;
466
+ break;
467
+ case 5: // 160
468
+ case 6: // 192
469
+ $this->key_size = 24;
470
+ break;
471
+ case 7: // 224
472
+ case 8: // 256
473
+ $this->key_size = 32;
474
+ }
475
+
476
+ $this->key = str_pad(substr($this->key, 0, $this->key_size), $this->key_size, chr(0));
477
+ $this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($this->iv, 0, 16), 16, chr(0));
478
+
479
+ if (!isset($this->enmcrypt)) {
480
+ $mode = $this->mode;
481
+ //$mode = $this->mode == CRYPT_AES_MODE_CTR ? MCRYPT_MODE_ECB : $this->mode;
482
+
483
+ $this->demcrypt = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', $mode, '');
484
+ $this->enmcrypt = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', $mode, '');
485
+
486
+ if ($mode == 'ncfb') {
487
+ $this->ecb = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_ECB, '');
488
+ }
489
+
490
+ } // else should mcrypt_generic_deinit be called?
491
+
492
+ mcrypt_generic_init($this->demcrypt, $this->key, $this->iv);
493
+ mcrypt_generic_init($this->enmcrypt, $this->key, $this->iv);
494
+
495
+ if ($this->mode == 'ncfb') {
496
+ mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
497
+ }
498
+
499
+ $this->changed = false;
500
+ }
501
+
502
+ /**
503
+ * Treat consecutive "packets" as if they are a continuous buffer.
504
+ *
505
+ * The default behavior.
506
+ *
507
+ * @see Crypt_Rijndael::disableContinuousBuffer()
508
+ * @access public
509
+ */
510
+ function enableContinuousBuffer()
511
+ {
512
+ parent::enableContinuousBuffer();
513
+
514
+ if (CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT) {
515
+ $this->enbuffer['enmcrypt_init'] = true;
516
+ $this->debuffer['demcrypt_init'] = true;
517
+ }
518
+ }
519
+
520
+ /**
521
+ * Treat consecutive packets as if they are a discontinuous buffer.
522
+ *
523
+ * The default behavior.
524
+ *
525
+ * @see Crypt_Rijndael::enableContinuousBuffer()
526
+ * @access public
527
+ */
528
+ function disableContinuousBuffer()
529
+ {
530
+ parent::disableContinuousBuffer();
531
+
532
+ if (CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT) {
533
+ mcrypt_generic_init($this->enmcrypt, $this->key, $this->iv);
534
+ mcrypt_generic_init($this->demcrypt, $this->key, $this->iv);
535
+ }
536
+ }
537
+ }
538
+
539
+ // vim: ts=4:sw=4:et:
540
+ // vim6: fdl=1:
modules/phpseclib/Crypt/Blowfish.php ADDED
@@ -0,0 +1,1468 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3
+
4
+ /**
5
+ * Pure-PHP implementation of Blowfish.
6
+ *
7
+ * Uses mcrypt, if available, and an internal implementation, otherwise.
8
+ *
9
+ * PHP versions 4 and 5
10
+ *
11
+ * Useful resources are as follows:
12
+ *
13
+ * - {@link http://en.wikipedia.org/wiki/Blowfish Wikipedia description of Blowfish}
14
+ *
15
+ * Here's a short example of how to use this library:
16
+ * <code>
17
+ * <?php
18
+ * include('Crypt/Blowfish.php');
19
+ *
20
+ * $blowfish = new Crypt_Blowfish();
21
+ *
22
+ * $blowfish->setKey('12345678901234567890123456789012');
23
+ *
24
+ * $plaintext = str_repeat('a', 1024);
25
+ *
26
+ * echo $blowfish->decrypt($blowfish->encrypt($plaintext));
27
+ * ?>
28
+ * </code>
29
+ *
30
+ * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
31
+ * of this software and associated documentation files (the "Software"), to deal
32
+ * in the Software without restriction, including without limitation the rights
33
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
34
+ * copies of the Software, and to permit persons to whom the Software is
35
+ * furnished to do so, subject to the following conditions:
36
+ *
37
+ * The above copyright notice and this permission notice shall be included in
38
+ * all copies or substantial portions of the Software.
39
+ *
40
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
41
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
42
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
43
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
44
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
45
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
46
+ * THE SOFTWARE.
47
+ *
48
+ * @category Crypt
49
+ * @package Crypt_Blowfish
50
+ * @author Jim Wigginton <terrafrost@php.net>
51
+ * @author Hans-Juergen Petrich <petrich@tronic-media.com>
52
+ * @copyright MMVII Jim Wigginton
53
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
54
+ * @version 1.0
55
+ * @link http://phpseclib.sourceforge.net
56
+ */
57
+
58
+ /**#@+
59
+ * @access public
60
+ * @see Crypt_Blowfish::encrypt()
61
+ * @see Crypt_Blowfish::decrypt()
62
+ */
63
+ /**
64
+ * Encrypt / decrypt using the Counter mode.
65
+ *
66
+ * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
67
+ *
68
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
69
+ */
70
+ define('CRYPT_BLOWFISH_MODE_CTR', -1);
71
+ /**
72
+ * Encrypt / decrypt using the Electronic Code Book mode.
73
+ *
74
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
75
+ */
76
+ define('CRYPT_BLOWFISH_MODE_ECB', 1);
77
+ /**
78
+ * Encrypt / decrypt using the Code Book Chaining mode.
79
+ *
80
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
81
+ */
82
+ define('CRYPT_BLOWFISH_MODE_CBC', 2);
83
+ /**
84
+ * Encrypt / decrypt using the Cipher Feedback mode.
85
+ *
86
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
87
+ */
88
+ define('CRYPT_BLOWFISH_MODE_CFB', 3);
89
+ /**
90
+ * Encrypt / decrypt using the Cipher Feedback mode.
91
+ *
92
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
93
+ */
94
+ define('CRYPT_BLOWFISH_MODE_OFB', 4);
95
+ /**#@-*/
96
+
97
+ /**#@+
98
+ * @access private
99
+ * @see Crypt_Blowfish::Crypt_Blowfish()
100
+ */
101
+ /**
102
+ * Toggles the internal implementation
103
+ */
104
+ define('CRYPT_BLOWFISH_MODE_INTERNAL', 1);
105
+ /**
106
+ * Toggles the mcrypt implementation
107
+ */
108
+ define('CRYPT_BLOWFISH_MODE_MCRYPT', 2);
109
+ /**#@-*/
110
+
111
+ /**
112
+ * Pure-PHP implementation of Blowfish.
113
+ *
114
+ * @author Jim Wigginton <terrafrost@php.net>
115
+ * @author Hans-Juergen Petrich <petrich@tronic-media.com>
116
+ * @version 1.0
117
+ * @access public
118
+ * @package Crypt_Blowfish
119
+ */
120
+ class Crypt_Blowfish {
121
+ /**
122
+ * The Key as String
123
+ *
124
+ * @see Crypt_Blowfish::setKey()
125
+ * @var Array
126
+ * @access private
127
+ */
128
+ var $key = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
129
+
130
+ /**
131
+ * The Encryption Mode
132
+ *
133
+ * @see Crypt_Blowfish::Crypt_Blowfish()
134
+ * @var Integer
135
+ * @access private
136
+ */
137
+ var $mode;
138
+
139
+ /**
140
+ * Continuous Buffer status
141
+ *
142
+ * @see Crypt_Blowfish::enableContinuousBuffer()
143
+ * @var Boolean
144
+ * @access private
145
+ */
146
+ var $continuousBuffer = false;
147
+
148
+ /**
149
+ * Padding status
150
+ *
151
+ * @see Crypt_Blowfish::enablePadding()
152
+ * @var Boolean
153
+ * @access private
154
+ */
155
+ var $padding = true;
156
+
157
+ /**
158
+ * The Initialization Vector
159
+ *
160
+ * @see Crypt_Blowfish::setIV()
161
+ * @var String
162
+ * @access private
163
+ */
164
+ var $iv = "\0\0\0\0\0\0\0\0";
165
+
166
+ /**
167
+ * A "sliding" Initialization Vector
168
+ *
169
+ * @see Crypt_Blowfish::enableContinuousBuffer()
170
+ * @var String
171
+ * @access private
172
+ */
173
+ var $encryptIV = "\0\0\0\0\0\0\0\0";
174
+
175
+ /**
176
+ * A "sliding" Initialization Vector
177
+ *
178
+ * @see Crypt_Blowfish::enableContinuousBuffer()
179
+ * @var String
180
+ * @access private
181
+ */
182
+ var $decryptIV = "\0\0\0\0\0\0\0\0";
183
+
184
+ /**
185
+ * mcrypt resource for encryption
186
+ *
187
+ * The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
188
+ * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
189
+ *
190
+ * @see Crypt_Blowfish::encrypt()
191
+ * @var String
192
+ * @access private
193
+ */
194
+ var $enmcrypt;
195
+
196
+ /**
197
+ * mcrypt resource for decryption
198
+ *
199
+ * The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
200
+ * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
201
+ *
202
+ * @see Crypt_Blowfish::decrypt()
203
+ * @var String
204
+ * @access private
205
+ */
206
+ var $demcrypt;
207
+
208
+ /**
209
+ * Does the enmcrypt resource need to be (re)initialized?
210
+ *
211
+ * @see Crypt_Blowfish::setKey()
212
+ * @see Crypt_Blowfish::setIV()
213
+ * @var Boolean
214
+ * @access private
215
+ */
216
+ var $enchanged = true;
217
+
218
+ /**
219
+ * Does the demcrypt resource need to be (re)initialized?
220
+ *
221
+ * @see Crypt_Blowfish::setKey()
222
+ * @see Crypt_Blowfish::setIV()
223
+ * @var Boolean
224
+ * @access private
225
+ */
226
+ var $dechanged = true;
227
+
228
+ /**
229
+ * Is the mode one that is paddable?
230
+ *
231
+ * @see Crypt_Blowfish::Crypt_Blowfish()
232
+ * @var Boolean
233
+ * @access private
234
+ */
235
+ var $paddable = false;
236
+
237
+ /**
238
+ * Encryption buffer for CTR, OFB and CFB modes
239
+ *
240
+ * @see Crypt_Blowfish::encrypt()
241
+ * @var Array
242
+ * @access private
243
+ */
244
+ var $enbuffer = array('encrypted' => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true);
245
+
246
+ /**
247
+ * Decryption buffer for CTR, OFB and CFB modes
248
+ *
249
+ * @see Crypt_Blowfish::decrypt()
250
+ * @var Array
251
+ * @access private
252
+ */
253
+ var $debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0, 'demcrypt_init' => true);
254
+
255
+ /**
256
+ * mcrypt resource for CFB mode
257
+ *
258
+ * @see Crypt_Blowfish::encrypt()
259
+ * @see Crypt_Blowfish::decrypt()
260
+ * @var String
261
+ * @access private
262
+ */
263
+ var $ecb;
264
+
265
+ /**
266
+ * Performance-optimized callback function for en/decrypt()
267
+ *
268
+ * @var Callback
269
+ * @access private
270
+ */
271
+ var $inline_crypt;
272
+
273
+ /**
274
+ * The fixed subkeys boxes ($sbox0 - $sbox3) with 256 entries each
275
+ *
276
+ * S-Box 1
277
+ *
278
+ * @access private
279
+ * @var array
280
+ */
281
+ var $sbox0 = array (
282
+ 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99,
283
+ 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e,
284
+ 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
285
+ 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e,
286
+ 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440,
287
+ 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
288
+ 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677,
289
+ 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032,
290
+ 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
291
+ 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0,
292
+ 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98,
293
+ 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
294
+ 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d,
295
+ 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7,
296
+ 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
297
+ 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09,
298
+ 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb,
299
+ 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
300
+ 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82,
301
+ 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573,
302
+ 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
303
+ 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8,
304
+ 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0,
305
+ 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
306
+ 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1,
307
+ 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9,
308
+ 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
309
+ 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af,
310
+ 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5,
311
+ 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
312
+ 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915,
313
+ 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a
314
+ );
315
+
316
+ /**
317
+ * S-Box 1
318
+ *
319
+ * @access private
320
+ * @var array
321
+ */
322
+ var $sbox1 = array(
323
+ 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,
324
+ 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e,
325
+ 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
326
+ 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,
327
+ 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8,
328
+ 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
329
+ 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,
330
+ 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331,
331
+ 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
332
+ 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,
333
+ 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2,
334
+ 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
335
+ 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,
336
+ 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3,
337
+ 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
338
+ 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960,
339
+ 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28,
340
+ 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
341
+ 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,
342
+ 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e,
343
+ 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
344
+ 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281,
345
+ 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696,
346
+ 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
347
+ 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0,
348
+ 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250,
349
+ 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
350
+ 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,
351
+ 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e,
352
+ 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
353
+ 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,
354
+ 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7
355
+ );
356
+
357
+ /**
358
+ * S-Box 2
359
+ *
360
+ * @access private
361
+ * @var array
362
+ */
363
+ var $sbox2 = array(
364
+ 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068,
365
+ 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,
366
+ 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
367
+ 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb,
368
+ 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,
369
+ 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
370
+ 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb,
371
+ 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,
372
+ 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
373
+ 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc,
374
+ 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,
375
+ 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
376
+ 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728,
377
+ 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,
378
+ 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
379
+ 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b,
380
+ 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,
381
+ 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
382
+ 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9,
383
+ 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,
384
+ 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
385
+ 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61,
386
+ 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,
387
+ 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
388
+ 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633,
389
+ 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,
390
+ 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
391
+ 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62,
392
+ 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,
393
+ 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
394
+ 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c,
395
+ 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0
396
+ );
397
+
398
+ /**
399
+ * S-Box 3
400
+ *
401
+ * @access private
402
+ * @var array
403
+ */
404
+ var $sbox3 = array(
405
+ 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe,
406
+ 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4,
407
+ 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
408
+ 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22,
409
+ 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6,
410
+ 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
411
+ 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51,
412
+ 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c,
413
+ 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
414
+ 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd,
415
+ 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319,
416
+ 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
417
+ 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32,
418
+ 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166,
419
+ 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
420
+ 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47,
421
+ 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d,
422
+ 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
423
+ 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd,
424
+ 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7,
425
+ 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
426
+ 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525,
427
+ 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442,
428
+ 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
429
+ 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d,
430
+ 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299,
431
+ 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
432
+ 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a,
433
+ 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b,
434
+ 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
435
+ 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9,
436
+ 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6
437
+ );
438
+
439
+ /**
440
+ * P-Array consists of 18 32-bit subkeys
441
+ *
442
+ * @var array $parray
443
+ * @access private
444
+ */
445
+ var $parray = array(
446
+ 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0,
447
+ 0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
448
+ 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b
449
+ );
450
+
451
+ /**
452
+ * The BCTX-working Array
453
+ *
454
+ * Holds the expanded key [p] and the key-depended s-boxes [sb]
455
+ *
456
+ * @var array $bctx
457
+ * @access private
458
+ */
459
+ var $bctx = array();
460
+
461
+ /**
462
+ * Default Constructor.
463
+ *
464
+ * Determines whether or not the mcrypt extension should be used.
465
+ * If not explictly set, CRYPT_BLOWFISH_MODE_CBC will be used.
466
+ *
467
+ * @param optional Integer $mode
468
+ * @access public
469
+ */
470
+ function Crypt_Blowfish($mode = CRYPT_BLOWFISH_MODE_CBC)
471
+ {
472
+ if ( !defined('CRYPT_BLOWFISH_MODE') ) {
473
+ switch (true) {
474
+ case extension_loaded('mcrypt') && in_array('blowfish', mcrypt_list_algorithms()):
475
+ define('CRYPT_BLOWFISH_MODE', CRYPT_BLOWFISH_MODE_MCRYPT);
476
+ break;
477
+ default:
478
+ define('CRYPT_BLOWFISH_MODE', CRYPT_BLOWFISH_MODE_INTERNAL);
479
+ }
480
+ }
481
+
482
+ switch ( CRYPT_BLOWFISH_MODE ) {
483
+ case CRYPT_BLOWFISH_MODE_MCRYPT:
484
+ switch ($mode) {
485
+ case CRYPT_BLOWFISH_MODE_ECB:
486
+ $this->paddable = true;
487
+ $this->mode = MCRYPT_MODE_ECB;
488
+ break;
489
+ case CRYPT_BLOWFISH_MODE_CTR:
490
+ $this->mode = 'ctr';
491
+ break;
492
+ case CRYPT_BLOWFISH_MODE_CFB:
493
+ $this->mode = 'ncfb';
494
+ $this->ecb = mcrypt_module_open(MCRYPT_BLOWFISH, '', MCRYPT_MODE_ECB, '');
495
+ break;
496
+ case CRYPT_BLOWFISH_MODE_OFB:
497
+ $this->mode = MCRYPT_MODE_NOFB;
498
+ break;
499
+ case CRYPT_BLOWFISH_MODE_CBC:
500
+ default:
501
+ $this->paddable = true;
502
+ $this->mode = MCRYPT_MODE_CBC;
503
+ }
504
+ $this->enmcrypt = mcrypt_module_open(MCRYPT_BLOWFISH, '', $this->mode, '');
505
+ $this->demcrypt = mcrypt_module_open(MCRYPT_BLOWFISH, '', $this->mode, '');
506
+
507
+ break;
508
+ default:
509
+ switch ($mode) {
510
+ case CRYPT_BLOWFISH_MODE_ECB:
511
+ case CRYPT_BLOWFISH_MODE_CBC:
512
+ $this->paddable = true;
513
+ $this->mode = $mode;
514
+ break;
515
+ case CRYPT_BLOWFISH_MODE_CTR:
516
+ case CRYPT_BLOWFISH_MODE_CFB:
517
+ case CRYPT_BLOWFISH_MODE_OFB:
518
+ $this->mode = $mode;
519
+ break;
520
+ default:
521
+ $this->paddable = true;
522
+ $this->mode = CRYPT_BLOWFISH_MODE_CBC;
523
+ }
524
+ $this->inline_crypt_setup();
525
+ }
526
+ }
527
+
528
+ /**
529
+ * Sets the key.
530
+ *
531
+ * Keys can be of any length. Blowfish, itself, requires the use of a key between 32 and max. 448-bits long.
532
+ * If the key is less than 32-bits we NOT fill the key to 32bit but let the key as it is to be compatible
533
+ * with mcrypt because mcrypt act this way with blowfish key's < 32 bits.
534
+ *
535
+ * If the key is more than 448-bits, we trim the excess bits.
536
+ *
537
+ * If the key is not explicitly set, or empty, it'll be assumed a 128 bits key to be all null bytes.
538
+ *
539
+ * @access public
540
+ * @param String $key
541
+ */
542
+ function setKey($key)
543
+ {
544
+ $keylength = strlen($key);
545
+
546
+ if (!$keylength) {
547
+ $key = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
548
+ }
549
+ elseif ($keylength > 56) {
550
+ $key = substr($key, 0, 56);
551
+ }
552
+
553
+ $this->key = $key;
554
+
555
+ $this->enchanged = true;
556
+ $this->dechanged = true;
557
+
558
+ if (CRYPT_BLOWFISH_MODE == CRYPT_BLOWFISH_MODE_MCRYPT) {
559
+ return;
560
+ }
561
+
562
+ /* key-expanding p[] and S-Box building sb[] */
563
+ $this->bctx = array(
564
+ 'p' => array(),
565
+ 'sb' => array(
566
+ $this->sbox0,
567
+ $this->sbox1,
568
+ $this->sbox2,
569
+ $this->sbox3
570
+ )
571
+ );
572
+
573
+ // unpack binary string in unsigned chars
574
+ $key = array_values(unpack('C*', $key));
575
+ $keyl = count($key);
576
+ for ($j = 0, $i = 0; $i < 18; ++$i) {
577
+ // xor P1 with the first 32-bits of the key, xor P2 with the second 32-bits ...
578
+ for ($data = 0, $k = 0; $k < 4; ++$k) {
579
+ $data = ($data << 8) | $key[$j];
580
+ if (++$j >= $keyl) {
581
+ $j = 0;
582
+ }
583
+ }
584
+ $this->bctx['p'][] = $this->parray[$i] ^ $data;
585
+ }
586
+
587
+ // encrypt the zero-string, replace P1 and P2 with the encrypted data,
588
+ // encrypt P3 and P4 with the new P1 and P2, do it with all P-array and subkeys
589
+ $datal = 0;
590
+ $datar = 0;
591
+ for ($i = 0; $i < 18; $i += 2) {
592
+ $this->_encryptBlock($datal, $datar);
593
+ $this->bctx['p'][$i ] = $datal;
594
+ $this->bctx['p'][$i + 1] = $datar;
595
+ }
596
+ for ($i = 0; $i < 4; ++$i) {
597
+ for ($j = 0; $j < 256; $j += 2) {
598
+ $this->_encryptBlock($datal, $datar);
599
+ $this->bctx['sb'][$i][$j ] = $datal;
600
+ $this->bctx['sb'][$i][$j + 1] = $datar;
601
+ }
602
+ }
603
+ }
604
+
605
+ /**
606
+ * Encrypt the block.
607
+ *
608
+ * @access private
609
+ * @param int $Xl left uInt32 part of the block
610
+ * @param int $Xr right uInt32 part of the block
611
+ * @return void
612
+ */
613
+ function _encryptBlock(&$Xl, &$Xr)
614
+ {
615
+ $p = $this->bctx['p'];
616
+ $sb_0 = $this->bctx['sb'][0];
617
+ $sb_1 = $this->bctx['sb'][1];
618
+ $sb_2 = $this->bctx['sb'][2];
619
+ $sb_3 = $this->bctx['sb'][3];
620
+ $l = $Xl;
621
+ $r = $Xr;
622
+
623
+ $i = -1;
624
+ while ($i < 15) {
625
+ $l^= $p[++$i];
626
+ $r^= ($sb_0[$l >> 24 & 0xff] +
627
+ $sb_1[$l >> 16 & 0xff] ^
628
+ $sb_2[$l >> 8 & 0xff]) +
629
+ $sb_3[$l & 0xff];
630
+
631
+ $r^= $p[++$i];
632
+ $l^= ($sb_0[$r >> 24 & 0xff] +
633
+ $sb_1[$r >> 16 & 0xff] ^
634
+ $sb_2[$r >> 8 & 0xff]) +
635
+ $sb_3[$r & 0xff];
636
+
637
+ }
638
+ $Xr = $l ^ $p[16];
639
+ $Xl = $r ^ $p[17];
640
+ }
641
+
642
+ /**
643
+ * Sets the password.
644
+ *
645
+ * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows:
646
+ * {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2}:
647
+ * $hash, $salt, $count
648
+ *
649
+ * @param String $password
650
+ * @param optional String $method
651
+ * @access public
652
+ */
653
+ function setPassword($password, $method = 'pbkdf2')
654
+ {
655
+ $key = '';
656
+
657
+ switch ($method) {
658
+ default: // 'pbkdf2'
659
+ list(, , $hash, $salt, $count) = func_get_args();
660
+ if (!isset($hash)) {
661
+ $hash = 'sha1';
662
+ }
663
+ // WPA and WPA2 use the SSID as the salt
664
+ if (!isset($salt)) {
665
+ $salt = 'phpseclib/salt';
666
+ }
667
+ // RFC2898#section-4.2 uses 1,000 iterations by default
668
+ // WPA and WPA2 use 4,096.
669
+ if (!isset($count)) {
670
+ $count = 1000;
671
+ }
672
+
673
+ if (!class_exists('Crypt_Hash')) {
674
+ require_once('Crypt/Hash.php');
675
+ }
676
+
677
+ $i = 1;
678
+ while (strlen($key) < 56) {
679
+ //$dk.= $this->_pbkdf($password, $salt, $count, $i++);
680
+ $hmac = new Crypt_Hash();
681
+ $hmac->setHash($hash);
682
+ $hmac->setKey($password);
683
+ $f = $u = $hmac->hash($salt . pack('N', $i++));
684
+ for ($j = 2; $j <= $count; $j++) {
685
+ $u = $hmac->hash($u);
686
+ $f^= $u;
687
+ }
688
+ $key.= $f;
689
+ }
690
+ }
691
+
692
+ $this->setKey($key);
693
+ }
694
+
695
+ /**
696
+ * Sets the initialization vector. (optional)
697
+ *
698
+ * SetIV is not required when CRYPT_BLOWFISH_MODE_ECB is being used. If not explictly set, it'll be assumed
699
+ * to be all null bytes.
700
+ *
701
+ * @access public
702
+ * @param String $iv
703
+ */
704
+ function setIV($iv)
705
+ {
706
+ $this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($iv, 0, 8), 8, chr(0));
707
+ $this->enchanged = true;
708
+ $this->dechanged = true;
709
+ }
710
+
711
+ /**
712
+ * Encrypts a message.
713
+ *
714
+ * $plaintext will be padded with up to 8 additional bytes. Other Blowfish implementations may or may not pad in the
715
+ * same manner. Other common approaches to padding and the reasons why it's necessary are discussed in the following
716
+ * URL:
717
+ *
718
+ * {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html}
719
+ *
720
+ * An alternative to padding is to, separately, send the length of the file. This is what SSH, in fact, does.
721
+ * strlen($plaintext) will still need to be a multiple of 8, however, arbitrary values can be added to make it that
722
+ * length.
723
+ *
724
+ * @see Crypt_Blowfish::decrypt()
725
+ * @access public
726
+ * @param String $plaintext
727
+ */
728
+ function encrypt($plaintext)
729
+ {
730
+ if ( CRYPT_BLOWFISH_MODE == CRYPT_BLOWFISH_MODE_MCRYPT ) {
731
+ if ($this->paddable) {
732
+ $plaintext = $this->_pad($plaintext);
733
+ }
734
+
735
+ if ($this->enchanged) {
736
+ mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
737
+ if ($this->mode == 'ncfb') {
738
+ mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0");
739
+ }
740
+ $this->enchanged = false;
741
+ }
742
+
743
+ if ($this->mode != 'ncfb' || !$this->continuousBuffer) {
744
+ $ciphertext = mcrypt_generic($this->enmcrypt, $plaintext);
745
+ } else {
746
+ $iv = &$this->encryptIV;
747
+ $pos = &$this->enbuffer['pos'];
748
+ $len = strlen($plaintext);
749
+ $ciphertext = '';
750
+ $i = 0;
751
+ if ($pos) {
752
+ $orig_pos = $pos;
753
+ $max = 8 - $pos;
754
+ if ($len >= $max) {
755
+ $i = $max;
756
+ $len-= $max;
757
+ $pos = 0;
758
+ } else {
759
+ $i = $len;
760
+ $pos+= $len;
761
+ $len = 0;
762
+ }
763
+ $ciphertext = substr($iv, $orig_pos) ^ $plaintext;
764
+ $iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
765
+ $this->enbuffer['enmcrypt_init'] = true;
766
+ }
767
+ if ($len >= 8) {
768
+ if ($this->enbuffer['enmcrypt_init'] === false || $len > 600) {
769
+ if ($this->enbuffer['enmcrypt_init'] === true) {
770
+ mcrypt_generic_init($this->enmcrypt, $this->key, $iv);
771
+ $this->enbuffer['enmcrypt_init'] = false;
772
+ }
773
+ $ciphertext.= mcrypt_generic($this->enmcrypt, substr($plaintext, $i, $len - $len % 8));
774
+ $iv = substr($ciphertext, -8);
775
+ $len%= 8;
776
+ } else {
777
+ while ($len >= 8) {
778
+ $iv = mcrypt_generic($this->ecb, $iv) ^ substr($plaintext, $i, 8);
779
+ $ciphertext.= $iv;
780
+ $len-= 8;
781
+ $i+= 8;
782
+ }
783
+ }
784
+ }
785
+ if ($len) {
786
+ $iv = mcrypt_generic($this->ecb, $iv);
787
+ $block = $iv ^ substr($plaintext, -$len);
788
+ $iv = substr_replace($iv, $block, 0, $len);
789
+ $ciphertext.= $block;
790
+ $pos = $len;
791
+ }
792
+ return $ciphertext;
793
+ }
794
+
795
+ if (!$this->continuousBuffer) {
796
+ mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
797
+ }
798
+
799
+ return $ciphertext;
800
+ }
801
+
802
+ if (empty($this->bctx)) {
803
+ $this->setKey($this->key);
804
+ }
805
+
806
+ $inline = $this->inline_crypt;
807
+ return $inline('encrypt', $this, $plaintext);
808
+ }
809
+
810
+ /**
811
+ * Decrypts a message.
812
+ *
813
+ * If strlen($ciphertext) is not a multiple of 8, null bytes will be added to the end of the string until it is.
814
+ *
815
+ * @see Crypt_Blowfish::encrypt()
816
+ * @access public
817
+ * @param String $ciphertext
818
+ */
819
+ function decrypt($ciphertext)
820
+ {
821
+ if ( CRYPT_BLOWFISH_MODE == CRYPT_BLOWFISH_MODE_MCRYPT ) {
822
+ if ($this->paddable) {
823
+ // we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic :
824
+ // "The data is padded with "\0" to make sure the length of the data is n * blocksize."
825
+ $ciphertext = str_pad($ciphertext, strlen($ciphertext) + (8 - strlen($ciphertext) % 8) % 8, chr(0));
826
+ }
827
+
828
+ if ($this->dechanged) {
829
+ mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
830
+ if ($this->mode == 'ncfb') {
831
+ mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0");
832
+ }
833
+ $this->dechanged = false;
834
+ }
835
+
836
+ if ($this->mode != 'ncfb' || !$this->continuousBuffer) {
837
+ $plaintext = mdecrypt_generic($this->demcrypt, $ciphertext);
838
+ } else {
839
+ $iv = &$this->decryptIV;
840
+ $pos = &$this->debuffer['pos'];
841
+ $len = strlen($ciphertext);
842
+ $plaintext = '';
843
+ $i = 0;
844
+ if ($pos) {
845
+ $orig_pos = $pos;
846
+ $max = 8 - $pos;
847
+ if ($len >= $max) {
848
+ $i = $max;
849
+ $len-= $max;
850
+ $pos = 0;
851
+ } else {
852
+ $i = $len;
853
+ $pos+= $len;
854
+ $len = 0;
855
+ }
856
+ $plaintext = substr($iv, $orig_pos) ^ $ciphertext;
857
+ $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
858
+ }
859
+ if ($len >= 8) {
860
+ $cb = substr($ciphertext, $i, $len - $len % 8);
861
+ $plaintext.= mcrypt_generic($this->ecb, $iv . $cb) ^ $cb;
862
+ $iv = substr($cb, -8);
863
+ $len%= 8;
864
+ }
865
+ if ($len) {
866
+ $iv = mcrypt_generic($this->ecb, $iv);
867
+ $plaintext.= $iv ^ substr($ciphertext, -$len);
868
+ $iv = substr_replace($iv, substr($ciphertext, -$len), 0, $len);
869
+ $pos = $len;
870
+ }
871
+ return $plaintext;
872
+ }
873
+
874
+ if (!$this->continuousBuffer) {
875
+ mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
876
+ }
877
+
878
+ return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
879
+ }
880
+
881
+ if (empty($this->bctx)) {
882
+ $this->setKey($this->key);
883
+ }
884
+
885
+ $inline = $this->inline_crypt;
886
+ return $inline('decrypt', $this, $ciphertext);
887
+ }
888
+
889
+ /**
890
+ * Treat consecutive "packets" as if they are a continuous buffer.
891
+ *
892
+ * @see Crypt_Blowfish::disableContinuousBuffer()
893
+ * @access public
894
+ */
895
+ function enableContinuousBuffer()
896
+ {
897
+ $this->continuousBuffer = true;
898
+ }
899
+
900
+ /**
901
+ * Treat consecutive packets as if they are a discontinuous buffer.
902
+ *
903
+ * The default behavior.
904
+ *
905
+ * @see Crypt_Blowfish::enableContinuousBuffer()
906
+ * @access public
907
+ */
908
+ function disableContinuousBuffer()
909
+ {
910
+ $this->continuousBuffer = false;
911
+ $this->encryptIV = $this->iv;
912
+ $this->decryptIV = $this->iv;
913
+ $this->enbuffer = array('encrypted' => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true);
914
+ $this->debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0, 'demcrypt_init' => true);
915
+
916
+ if (CRYPT_BLOWFISH_MODE == CRYPT_BLOWFISH_MODE_MCRYPT) {
917
+ mcrypt_generic_init($this->enmcrypt, $this->key, $this->iv);
918
+ mcrypt_generic_init($this->demcrypt, $this->key, $this->iv);
919
+ }
920
+ }
921
+
922
+ /**
923
+ * Pad "packets".
924
+ *
925
+ * Blowfish works by encrypting 8 bytes at a time. If you ever need to encrypt or decrypt something that's not
926
+ * a multiple of 8, it becomes necessary to pad the input so that it's length is a multiple of eight.
927
+ *
928
+ * Padding is enabled by default. Sometimes, however, it is undesirable to pad strings. Such is the case in SSH1,
929
+ * where "packets" are padded with random bytes before being encrypted. Unpad these packets and you risk stripping
930
+ * away characters that shouldn't be stripped away. (SSH knows how many bytes are added because the length is
931
+ * transmitted separately)
932
+ *
933
+ * @see Crypt_Blowfish::disablePadding()
934
+ * @access public
935
+ */
936
+ function enablePadding()
937
+ {
938
+ $this->padding = true;
939
+ }
940
+
941
+ /**
942
+ * Do not pad packets.
943
+ *
944
+ * @see Crypt_Blowfish::enablePadding()
945
+ * @access public
946
+ */
947
+ function disablePadding()
948
+ {
949
+ $this->padding = false;
950
+ }
951
+
952
+ /**
953
+ * Pads a string
954
+ *
955
+ * Pads a string using the RSA PKCS padding standards so that its length is a multiple of the blocksize (8).
956
+ *
957
+ * If padding is disabled and $text is not a multiple of the blocksize, the string will be padded regardless
958
+ * and padding will, hence forth, be enabled.
959
+ *
960
+ * @see Crypt_Blowfish::_unpad()
961
+ * @access private
962
+ */
963
+ function _pad($text)
964
+ {
965
+ $length = strlen($text);
966
+
967
+ if (!$this->padding) {
968
+ if ($length % 8 == 0) {
969
+ return $text;
970
+ } else {
971
+ user_error("The plaintext's length ($length) is not a multiple of the block size (8)");
972
+ $this->padding = true;
973
+ }
974
+ }
975
+
976
+ $pad = 8 - ($length % 8);
977
+
978
+ return str_pad($text, $length + $pad, chr($pad));
979
+ }
980
+
981
+ /**
982
+ * Unpads a string
983
+ *
984
+ * If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong
985
+ * and false will be returned.
986
+ *
987
+ * @see Crypt_Blowfish::_pad()
988
+ * @access private
989
+ */
990
+ function _unpad($text)
991
+ {
992
+ if (!$this->padding) {
993
+ return $text;
994
+ }
995
+
996
+ $length = ord($text[strlen($text) - 1]);
997
+
998
+ if (!$length || $length > 8) {
999
+ return false;
1000
+ }
1001
+
1002
+ return substr($text, 0, -$length);
1003
+ }
1004
+
1005
+ /**
1006
+ * String Shift
1007
+ *
1008
+ * Inspired by array_shift
1009
+ *
1010
+ * @param String $string
1011
+ * @return String
1012
+ * @access private
1013
+ */
1014
+ function _string_shift(&$string)
1015
+ {
1016
+ $substr = substr($string, 0, 8);
1017
+ $string = substr($string, 8);
1018
+ return $substr;
1019
+ }
1020
+
1021
+ /**
1022
+ * Generate CTR XOR encryption key
1023
+ *
1024
+ * Encrypt the output of this and XOR it against the ciphertext / plaintext to get the
1025
+ * plaintext / ciphertext in CTR mode.
1026
+ *
1027
+ * @see Crypt_Blowfish::decrypt()
1028
+ * @see Crypt_Blowfish::encrypt()
1029
+ * @access public
1030
+ * @param String $iv
1031
+ */
1032
+ function _generate_xor(&$iv)
1033
+ {
1034
+ $xor = $iv;
1035
+ for ($j = 4; $j <= 8; $j+=4) {
1036
+ $temp = substr($iv, -$j, 4);
1037
+ switch ($temp) {
1038
+ case "\xFF\xFF\xFF\xFF":
1039
+ $iv = substr_replace($iv, "\x00\x00\x00\x00", -$j, 4);
1040
+ break;
1041
+ case "\x7F\xFF\xFF\xFF":
1042
+ $iv = substr_replace($iv, "\x80\x00\x00\x00", -$j, 4);
1043
+ break 2;
1044
+ default:
1045
+ extract(unpack('Ncount', $temp));
1046
+ $iv = substr_replace($iv, pack('N', $count + 1), -$j, 4);
1047
+ break 2;
1048
+ }
1049
+ }
1050
+
1051
+ return $xor;
1052
+ }
1053
+
1054
+ /**
1055
+ * Creates performance-optimized function for de/encrypt(), storing it in $this->inline_crypt
1056
+ *
1057
+ * @access private
1058
+ */
1059
+ function inline_crypt_setup()
1060
+ {/*{{{*/
1061
+ $lambda_functions =& Crypt_Blowfish::get_lambda_functions();
1062
+ $block_size = 8;
1063
+ $mode = $this->mode;
1064
+ $code_hash = "$mode";
1065
+
1066
+ if (!isset($lambda_functions[$code_hash])) {
1067
+ $init_cryptBlock = '
1068
+ extract($self->bctx["p"], EXTR_PREFIX_ALL, "p");
1069
+ extract($self->bctx["sb"], EXTR_PREFIX_ALL, "sb");
1070
+ ';
1071
+
1072
+ // Generating encrypt code:
1073
+ $_encryptBlock = '
1074
+ $in = unpack("N*", $in);
1075
+ $l = $in[1];
1076
+ $r = $in[2];
1077
+ ';
1078
+ for ($i = 0; $i < 16; $i+= 2) {
1079
+ $_encryptBlock.= '
1080
+ $l^= $p_'.($i).';
1081
+ $r^= ($sb_0[$l >> 24 & 0xff] +
1082
+ $sb_1[$l >> 16 & 0xff] ^
1083
+ $sb_2[$l >> 8 & 0xff]) +
1084
+ $sb_3[$l & 0xff];
1085
+
1086
+ $r^= $p_'.($i + 1).';
1087
+ $l^= ($sb_0[$r >> 24 & 0xff] +
1088
+ $sb_1[$r >> 16 & 0xff] ^
1089
+ $sb_2[$r >> 8 & 0xff]) +
1090
+ $sb_3[$r & 0xff];
1091
+ ';
1092
+ }
1093
+ $_encryptBlock.= '
1094
+ $in = pack("N*", $r ^ $p_17, $l ^ $p_16);
1095
+ ';
1096
+
1097
+ // Generating decrypt code:
1098
+ $_decryptBlock = '
1099
+ $in = unpack("N*", $in);
1100
+ $l = $in[1];
1101
+ $r = $in[2];
1102
+ ';
1103
+
1104
+ for ($i = 17; $i > 2; $i-= 2) {
1105
+ $_decryptBlock.= '
1106
+ $l^= $p_'.($i).';
1107
+ $r^= ($sb_0[$l >> 24 & 0xff] +
1108
+ $sb_1[$l >> 16 & 0xff] ^
1109
+ $sb_2[$l >> 8 & 0xff]) +
1110
+ $sb_3[$l & 0xff];
1111
+
1112
+ $r^= $p_'.($i - 1).';
1113
+ $l^= ($sb_0[$r >> 24 & 0xff] +
1114
+ $sb_1[$r >> 16 & 0xff] ^
1115
+ $sb_2[$r >> 8 & 0xff]) +
1116
+ $sb_3[$r & 0xff];
1117
+ ';
1118
+ }
1119
+
1120
+ $_decryptBlock.= '
1121
+ $in = pack("N*", $r ^ $p_0, $l ^ $p_1);
1122
+ ';
1123
+
1124
+ // Generating mode of operation code:
1125
+ switch ($mode) {
1126
+ case CRYPT_BLOWFISH_MODE_ECB:
1127
+ $encrypt = '
1128
+ $ciphertext = "";
1129
+ $text = $self->_pad($text);
1130
+ $plaintext_len = strlen($text);
1131
+
1132
+ for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') {
1133
+ $in = substr($text, $i, '.$block_size.');
1134
+ '.$_encryptBlock.'
1135
+ $ciphertext.= $in;
1136
+ }
1137
+ return $ciphertext;
1138
+ ';
1139
+
1140
+ $decrypt = '
1141
+ $plaintext = "";
1142
+ $text = str_pad($text, strlen($text) + ('.$block_size.' - strlen($text) % '.$block_size.') % '.$block_size.', chr(0));
1143
+ $ciphertext_len = strlen($text);
1144
+
1145
+ for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') {
1146
+ $in = substr($text, $i, '.$block_size.');
1147
+ '.$_decryptBlock.'
1148
+ $plaintext.= $in;
1149
+ }
1150
+
1151
+ return $self->_unpad($plaintext);
1152
+ ';
1153
+ break;
1154
+ case CRYPT_BLOWFISH_MODE_CBC:
1155
+ $encrypt = '
1156
+ $ciphertext = "";
1157
+ $text = $self->_pad($text);
1158
+ $plaintext_len = strlen($text);
1159
+
1160
+ $in = $self->encryptIV;
1161
+
1162
+ for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') {
1163
+ $in = substr($text, $i, '.$block_size.') ^ $in;
1164
+ '.$_encryptBlock.'
1165
+ $ciphertext.= $in;
1166
+ }
1167
+
1168
+ if ($self->continuousBuffer) {
1169
+ $self->encryptIV = $in;
1170
+ }
1171
+
1172
+ return $ciphertext;
1173
+ ';
1174
+
1175
+ $decrypt = '
1176
+ $plaintext = "";
1177
+ $text = str_pad($text, strlen($text) + ('.$block_size.' - strlen($text) % '.$block_size.') % '.$block_size.', chr(0));
1178
+ $ciphertext_len = strlen($text);
1179
+
1180
+ $iv = $self->decryptIV;
1181
+
1182
+ for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') {
1183
+ $in = $block = substr($text, $i, '.$block_size.');
1184
+ '.$_decryptBlock.'
1185
+ $plaintext.= $in ^ $iv;
1186
+ $iv = $block;
1187
+ }
1188
+
1189
+ if ($self->continuousBuffer) {
1190
+ $self->decryptIV = $iv;
1191
+ }
1192
+
1193
+ return $self->_unpad($plaintext);
1194
+ ';
1195
+ break;
1196
+ case CRYPT_BLOWFISH_MODE_CTR:
1197
+ $encrypt = '
1198
+ $ciphertext = "";
1199
+ $plaintext_len = strlen($text);
1200
+ $xor = $self->encryptIV;
1201
+ $buffer = &$self->enbuffer;
1202
+
1203
+ if (strlen($buffer["encrypted"])) {
1204
+ for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') {
1205
+ $block = substr($text, $i, '.$block_size.');
1206
+ if (strlen($block) > strlen($buffer["encrypted"])) {
1207
+ $in = $self->_generate_xor($xor);
1208
+ '.$_encryptBlock.'
1209
+ $buffer["encrypted"].= $in;
1210
+ }
1211
+ $key = $self->_string_shift($buffer["encrypted"]);
1212
+ $ciphertext.= $block ^ $key;
1213
+ }
1214
+ } else {
1215
+ for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') {
1216
+ $block = substr($text, $i, '.$block_size.');
1217
+ $in = $self->_generate_xor($xor);
1218
+ '.$_encryptBlock.'
1219
+ $key = $in;
1220
+ $ciphertext.= $block ^ $key;
1221
+ }
1222
+ }
1223
+ if ($self->continuousBuffer) {
1224
+ $self->encryptIV = $xor;
1225
+ if ($start = $plaintext_len % '.$block_size.') {
1226
+ $buffer["encrypted"] = substr($key, $start) . $buffer["encrypted"];
1227
+ }
1228
+ }
1229
+
1230
+ return $ciphertext;
1231
+ ';
1232
+
1233
+ $decrypt = '
1234
+ $plaintext = "";
1235
+ $ciphertext_len = strlen($text);
1236
+ $xor = $self->decryptIV;
1237
+ $buffer = &$self->debuffer;
1238
+
1239
+ if (strlen($buffer["ciphertext"])) {
1240
+ for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') {
1241
+ $block = substr($text, $i, '.$block_size.');
1242
+ if (strlen($block) > strlen($buffer["ciphertext"])) {
1243
+ $in = $self->_generate_xor($xor);
1244
+ '.$_encryptBlock.'
1245
+ $buffer["ciphertext"].= $in;
1246
+ }
1247
+ $key = $self->_string_shift($buffer["ciphertext"]);
1248
+ $plaintext.= $block ^ $key;
1249
+ }
1250
+ } else {
1251
+ for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') {
1252
+ $block = substr($text, $i, '.$block_size.');
1253
+ $in = $self->_generate_xor($xor);
1254
+ '.$_encryptBlock.'
1255
+ $key = $in;
1256
+ $plaintext.= $block ^ $key;
1257
+ }
1258
+ }
1259
+ if ($self->continuousBuffer) {
1260
+ $self->decryptIV = $xor;
1261
+ if ($start = $ciphertext_len % '.$block_size.') {
1262
+ $buffer["ciphertext"] = substr($key, $start) . $buffer["ciphertext"];
1263
+ }
1264
+ }
1265
+ return $plaintext;
1266
+ ';
1267
+ break;
1268
+ case CRYPT_BLOWFISH_MODE_CFB:
1269
+ $encrypt = '
1270
+ $ciphertext = "";
1271
+ $buffer = &$self->enbuffer;
1272
+
1273
+ if ($self->continuousBuffer) {
1274
+ $iv = &$self->encryptIV;
1275
+ $pos = &$buffer["pos"];
1276
+ } else {
1277
+ $iv = $self->encryptIV;
1278
+ $pos = 0;
1279
+ }
1280
+ $len = strlen($text);
1281
+ $i = 0;
1282
+ if ($pos) {
1283
+ $orig_pos = $pos;
1284
+ $max = '.$block_size.' - $pos;
1285
+ if ($len >= $max) {
1286
+ $i = $max;
1287
+ $len-= $max;
1288
+ $pos = 0;
1289
+ } else {
1290
+ $i = $len;
1291
+ $pos+= $len;
1292
+ $len = 0;
1293
+ }
1294
+ $ciphertext = substr($iv, $orig_pos) ^ $text;
1295
+ $iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
1296
+ }
1297
+ while ($len >= '.$block_size.') {
1298
+ $in = $iv;
1299
+ '.$_encryptBlock.';
1300
+ $iv = $in ^ substr($text, $i, '.$block_size.');
1301
+ $ciphertext.= $iv;
1302
+ $len-= '.$block_size.';
1303
+ $i+= '.$block_size.';
1304
+ }
1305
+ if ($len) {
1306
+ $in = $iv;
1307
+ '.$_encryptBlock.'
1308
+ $iv = $in;
1309
+ $block = $iv ^ substr($text, $i);
1310
+ $iv = substr_replace($iv, $block, 0, $len);
1311
+ $ciphertext.= $block;
1312
+ $pos = $len;
1313
+ }
1314
+ return $ciphertext;
1315
+ ';
1316
+
1317
+ $decrypt = '
1318
+ $plaintext = "";
1319
+ $buffer = &$self->debuffer;
1320
+
1321
+ if ($self->continuousBuffer) {
1322
+ $iv = &$self->decryptIV;
1323
+ $pos = &$buffer["pos"];
1324
+ } else {
1325
+ $iv = $self->decryptIV;
1326
+ $pos = 0;
1327
+ }
1328
+ $len = strlen($text);
1329
+ $i = 0;
1330
+ if ($pos) {
1331
+ $orig_pos = $pos;
1332
+ $max = '.$block_size.' - $pos;
1333
+ if ($len >= $max) {
1334
+ $i = $max;
1335
+ $len-= $max;
1336
+ $pos = 0;
1337
+ } else {
1338
+ $i = $len;
1339
+ $pos+= $len;
1340
+ $len = 0;
1341
+ }
1342
+ $plaintext = substr($iv, $orig_pos) ^ $text;
1343
+ $iv = substr_replace($iv, substr($text, 0, $i), $orig_pos, $i);
1344
+ }
1345
+ while ($len >= '.$block_size.') {
1346
+ $in = $iv;
1347
+ '.$_encryptBlock.'
1348
+ $iv = $in;
1349
+ $cb = substr($text, $i, '.$block_size.');
1350
+ $plaintext.= $iv ^ $cb;
1351
+ $iv = $cb;
1352
+ $len-= '.$block_size.';
1353
+ $i+= '.$block_size.';
1354
+ }
1355
+ if ($len) {
1356
+ $in = $iv;
1357
+ '.$_encryptBlock.'
1358
+ $iv = $in;
1359
+ $plaintext.= $iv ^ substr($text, $i);
1360
+ $iv = substr_replace($iv, substr($text, $i), 0, $len);
1361
+ $pos = $len;
1362
+ }
1363
+
1364
+ return $plaintext;
1365
+ ';
1366
+ break;
1367
+ case CRYPT_BLOWFISH_MODE_OFB:
1368
+ $encrypt = '
1369
+ $ciphertext = "";
1370
+ $plaintext_len = strlen($text);
1371
+ $xor = $self->encryptIV;
1372
+ $buffer = &$self->enbuffer;
1373
+
1374
+ if (strlen($buffer["xor"])) {
1375
+ for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') {
1376
+ $block = substr($text, $i, '.$block_size.');
1377
+ if (strlen($block) > strlen($buffer["xor"])) {
1378
+ $in = $xor;
1379
+ '.$_encryptBlock.'
1380
+ $xor = $in;
1381
+ $buffer["xor"].= $xor;
1382
+ }
1383
+ $key = $self->_string_shift($buffer["xor"]);
1384
+ $ciphertext.= $block ^ $key;
1385
+ }
1386
+ } else {
1387
+ for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') {
1388
+ $in = $xor;
1389
+ '.$_encryptBlock.'
1390
+ $xor = $in;
1391
+ $ciphertext.= substr($text, $i, '.$block_size.') ^ $xor;
1392
+ }
1393
+ $key = $xor;
1394
+ }
1395
+ if ($self->continuousBuffer) {
1396
+ $self->encryptIV = $xor;
1397
+ if ($start = $plaintext_len % '.$block_size.') {
1398
+ $buffer["xor"] = substr($key, $start) . $buffer["xor"];
1399
+ }
1400
+ }
1401
+ return $ciphertext;
1402
+ ';
1403
+
1404
+ $decrypt = '
1405
+ $plaintext = "";
1406
+ $ciphertext_len = strlen($text);
1407
+ $xor = $self->decryptIV;
1408
+ $buffer = &$self->debuffer;
1409
+
1410
+ if (strlen($buffer["xor"])) {
1411
+ for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') {
1412
+ $block = substr($text, $i, '.$block_size.');
1413
+ if (strlen($block) > strlen($buffer["xor"])) {
1414
+ $in = $xor;
1415
+ '.$_encryptBlock.'
1416
+ $xor = $in;
1417
+ $buffer["xor"].= $xor;
1418
+ }
1419
+ $key = $self->_string_shift($buffer["xor"]);
1420
+ $plaintext.= $block ^ $key;
1421
+ }
1422
+ } else {
1423
+ for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') {
1424
+ $in = $xor;
1425
+ '.$_encryptBlock.'
1426
+ $xor = $in;
1427
+ $plaintext.= substr($text, $i, '.$block_size.') ^ $xor;
1428
+ }
1429
+ $key = $xor;
1430
+ }
1431
+ if ($self->continuousBuffer) {
1432
+ $self->decryptIV = $xor;
1433
+ if ($start = $ciphertext_len % '.$block_size.') {
1434
+ $buffer["xor"] = substr($key, $start) . $buffer["xor"];
1435
+ }
1436
+ }
1437
+ return $plaintext;
1438
+ ';
1439
+ break;
1440
+ }
1441
+ $fnc_head = '$action, &$self, $text';
1442
+ $fnc_body = $init_cryptBlock . 'if ($action == "encrypt") { ' . $encrypt . ' } else { ' . $decrypt . ' }';
1443
+
1444
+ if (function_exists('create_function') && is_callable('create_function')) {
1445
+ $lambda_functions[$code_hash] = create_function($fnc_head, $fnc_body);
1446
+ } else {
1447
+ eval('function ' . ($lambda_functions[$code_hash] = 'f' . md5(microtime())) . '(' . $fnc_head . ') { ' . $fnc_body . ' }');
1448
+ }
1449
+ }
1450
+ $this->inline_crypt = $lambda_functions[$code_hash];
1451
+ }/*}}}*/
1452
+
1453
+ /**
1454
+ * Holds the lambda_functions table (classwide)
1455
+ *
1456
+ * @see inline_crypt_setup()
1457
+ * @return Array
1458
+ * @access private
1459
+ */
1460
+ function &get_lambda_functions()
1461
+ {
1462
+ static $functions = array();
1463
+ return $functions;
1464
+ }
1465
+ }
1466
+
1467
+ // vim: ts=4:sw=4:et:
1468
+ // vim6: fdl=1:
modules/phpseclib/Crypt/DES.php ADDED
@@ -0,0 +1,2536 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3
+
4
+ /**
5
+ * Pure-PHP implementation of DES.
6
+ *
7
+ * Uses mcrypt, if available, and an internal implementation, otherwise.
8
+ *
9
+ * PHP versions 4 and 5
10
+ *
11
+ * Useful resources are as follows:
12
+ *
13
+ * - {@link http://en.wikipedia.org/wiki/DES_supplementary_material Wikipedia: DES supplementary material}
14
+ * - {@link http://www.itl.nist.gov/fipspubs/fip46-2.htm FIPS 46-2 - (DES), Data Encryption Standard}
15
+ * - {@link http://www.cs.eku.edu/faculty/styer/460/Encrypt/JS-DES.html JavaScript DES Example}
16
+ *
17
+ * Here's a short example of how to use this library:
18
+ * <code>
19
+ * <?php
20
+ * include('Crypt/DES.php');
21
+ *
22
+ * $des = new Crypt_DES();
23
+ *
24
+ * $des->setKey('abcdefgh');
25
+ *
26
+ * $size = 10 * 1024;
27
+ * $plaintext = '';
28
+ * for ($i = 0; $i < $size; $i++) {
29
+ * $plaintext.= 'a';
30
+ * }
31
+ *
32
+ * echo $des->decrypt($des->encrypt($plaintext));
33
+ * ?>
34
+ * </code>
35
+ *
36
+ * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
37
+ * of this software and associated documentation files (the "Software"), to deal
38
+ * in the Software without restriction, including without limitation the rights
39
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
40
+ * copies of the Software, and to permit persons to whom the Software is
41
+ * furnished to do so, subject to the following conditions:
42
+ *
43
+ * The above copyright notice and this permission notice shall be included in
44
+ * all copies or substantial portions of the Software.
45
+ *
46
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
47
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
48
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
49
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
50
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
51
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
52
+ * THE SOFTWARE.
53
+ *
54
+ * @category Crypt
55
+ * @package Crypt_DES
56
+ * @author Jim Wigginton <terrafrost@php.net>
57
+ * @copyright MMVII Jim Wigginton
58
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
59
+ * @link http://phpseclib.sourceforge.net
60
+ */
61
+
62
+ /**#@+
63
+ * @access private
64
+ * @see Crypt_DES::_prepareKey()
65
+ * @see Crypt_DES::_processBlock()
66
+ */
67
+ /**
68
+ * Contains array_reverse($keys[CRYPT_DES_DECRYPT])
69
+ */
70
+ define('CRYPT_DES_ENCRYPT', 0);
71
+ /**
72
+ * Contains array_reverse($keys[CRYPT_DES_ENCRYPT])
73
+ */
74
+ define('CRYPT_DES_DECRYPT', 1);
75
+ /**
76
+ * Contains $keys[CRYPT_DES_ENCRYPT] as 1-dim array
77
+ */
78
+ define('CRYPT_DES_ENCRYPT_1DIM', 2);
79
+ /**
80
+ * Contains $keys[CRYPT_DES_DECRYPT] as 1-dim array
81
+ */
82
+ define('CRYPT_DES_DECRYPT_1DIM', 3);
83
+ /**#@-*/
84
+
85
+ /**#@+
86
+ * @access public
87
+ * @see Crypt_DES::encrypt()
88
+ * @see Crypt_DES::decrypt()
89
+ */
90
+ /**
91
+ * Encrypt / decrypt using the Counter mode.
92
+ *
93
+ * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
94
+ *
95
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
96
+ */
97
+ define('CRYPT_DES_MODE_CTR', -1);
98
+ /**
99
+ * Encrypt / decrypt using the Electronic Code Book mode.
100
+ *
101
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
102
+ */
103
+ define('CRYPT_DES_MODE_ECB', 1);
104
+ /**
105
+ * Encrypt / decrypt using the Code Book Chaining mode.
106
+ *
107
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
108
+ */
109
+ define('CRYPT_DES_MODE_CBC', 2);
110
+ /**
111
+ * Encrypt / decrypt using the Cipher Feedback mode.
112
+ *
113
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
114
+ */
115
+ define('CRYPT_DES_MODE_CFB', 3);
116
+ /**
117
+ * Encrypt / decrypt using the Cipher Feedback mode.
118
+ *
119
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
120
+ */
121
+ define('CRYPT_DES_MODE_OFB', 4);
122
+ /**#@-*/
123
+
124
+ /**#@+
125
+ * @access private
126
+ * @see Crypt_DES::Crypt_DES()
127
+ */
128
+ /**
129
+ * Toggles the internal implementation
130
+ */
131
+ define('CRYPT_DES_MODE_INTERNAL', 1);
132
+ /**
133
+ * Toggles the mcrypt implementation
134
+ */
135
+ define('CRYPT_DES_MODE_MCRYPT', 2);
136
+ /**#@-*/
137
+
138
+ /**
139
+ * Pure-PHP implementation of DES.
140
+ *
141
+ * @author Jim Wigginton <terrafrost@php.net>
142
+ * @version 0.1.0
143
+ * @access public
144
+ * @package Crypt_DES
145
+ */
146
+ class Crypt_DES {
147
+ /**
148
+ * The Key Schedule
149
+ *
150
+ * @see Crypt_DES::setKey()
151
+ * @var Array
152
+ * @access private
153
+ */
154
+ var $keys = "\0\0\0\0\0\0\0\0";
155
+
156
+ /**
157
+ * The Encryption Mode
158
+ *
159
+ * @see Crypt_DES::Crypt_DES()
160
+ * @var Integer
161
+ * @access private
162
+ */
163
+ var $mode;
164
+
165
+ /**
166
+ * Continuous Buffer status
167
+ *
168
+ * @see Crypt_DES::enableContinuousBuffer()
169
+ * @var Boolean
170
+ * @access private
171
+ */
172
+ var $continuousBuffer = false;
173
+
174
+ /**
175
+ * Padding status
176
+ *
177
+ * @see Crypt_DES::enablePadding()
178
+ * @var Boolean
179
+ * @access private
180
+ */
181
+ var $padding = true;
182
+
183
+ /**
184
+ * The Initialization Vector
185
+ *
186
+ * @see Crypt_DES::setIV()
187
+ * @var String
188
+ * @access private
189
+ */
190
+ var $iv = "\0\0\0\0\0\0\0\0";
191
+
192
+ /**
193
+ * A "sliding" Initialization Vector
194
+ *
195
+ * @see Crypt_DES::enableContinuousBuffer()
196
+ * @var String
197
+ * @access private
198
+ */
199
+ var $encryptIV = "\0\0\0\0\0\0\0\0";
200
+
201
+ /**
202
+ * A "sliding" Initialization Vector
203
+ *
204
+ * @see Crypt_DES::enableContinuousBuffer()
205
+ * @var String
206
+ * @access private
207
+ */
208
+ var $decryptIV = "\0\0\0\0\0\0\0\0";
209
+
210
+ /**
211
+ * mcrypt resource for encryption
212
+ *
213
+ * The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
214
+ * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
215
+ *
216
+ * @see Crypt_DES::encrypt()
217
+ * @var String
218
+ * @access private
219
+ */
220
+ var $enmcrypt;
221
+
222
+ /**
223
+ * mcrypt resource for decryption
224
+ *
225
+ * The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
226
+ * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
227
+ *
228
+ * @see Crypt_DES::decrypt()
229
+ * @var String
230
+ * @access private
231
+ */
232
+ var $demcrypt;
233
+
234
+ /**
235
+ * Does the enmcrypt resource need to be (re)initialized?
236
+ *
237
+ * @see Crypt_DES::setKey()
238
+ * @see Crypt_DES::setIV()
239
+ * @var Boolean
240
+ * @access private
241
+ */
242
+ var $enchanged = true;
243
+
244
+ /**
245
+ * Does the demcrypt resource need to be (re)initialized?
246
+ *
247
+ * @see Crypt_DES::setKey()
248
+ * @see Crypt_DES::setIV()
249
+ * @var Boolean
250
+ * @access private
251
+ */
252
+ var $dechanged = true;
253
+
254
+ /**
255
+ * Is the mode one that is paddable?
256
+ *
257
+ * @see Crypt_DES::Crypt_DES()
258
+ * @var Boolean
259
+ * @access private
260
+ */
261
+ var $paddable = false;
262
+
263
+ /**
264
+ * Encryption buffer for CTR, OFB and CFB modes
265
+ *
266
+ * @see Crypt_DES::encrypt()
267
+ * @var Array
268
+ * @access private
269
+ */
270
+ var $enbuffer = array('encrypted' => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true);
271
+
272
+ /**
273
+ * Decryption buffer for CTR, OFB and CFB modes
274
+ *
275
+ * @see Crypt_DES::decrypt()
276
+ * @var Array
277
+ * @access private
278
+ */
279
+ var $debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0, 'demcrypt_init' => true);
280
+
281
+ /**
282
+ * mcrypt resource for CFB mode
283
+ *
284
+ * @see Crypt_DES::encrypt()
285
+ * @see Crypt_DES::decrypt()
286
+ * @var String
287
+ * @access private
288
+ */
289
+ var $ecb;
290
+
291
+ /**
292
+ * Performance-optimized callback function for en/decrypt()
293
+ *
294
+ * @var Callback
295
+ * @access private
296
+ */
297
+ var $inline_crypt;
298
+
299
+ /**
300
+ * Holds whether performance-optimized $inline_crypt should be used or not.
301
+ *
302
+ * @var Boolean
303
+ * @access private
304
+ */
305
+ var $use_inline_crypt = false;
306
+
307
+ /**
308
+ * Shuffle table.
309
+ *
310
+ * For each byte value index, the entry holds an 8-byte string
311
+ * with each byte containing all bits in the same state as the
312
+ * corresponding bit in the index value.
313
+ *
314
+ * @see Crypt_DES::_processBlock()
315
+ * @see Crypt_DES::_prepareKey()
316
+ * @var Array
317
+ * @access private
318
+ */
319
+ var $shuffle = array(
320
+ "\x00\x00\x00\x00\x00\x00\x00\x00", "\x00\x00\x00\x00\x00\x00\x00\xFF",
321
+ "\x00\x00\x00\x00\x00\x00\xFF\x00", "\x00\x00\x00\x00\x00\x00\xFF\xFF",
322
+ "\x00\x00\x00\x00\x00\xFF\x00\x00", "\x00\x00\x00\x00\x00\xFF\x00\xFF",
323
+ "\x00\x00\x00\x00\x00\xFF\xFF\x00", "\x00\x00\x00\x00\x00\xFF\xFF\xFF",
324
+ "\x00\x00\x00\x00\xFF\x00\x00\x00", "\x00\x00\x00\x00\xFF\x00\x00\xFF",
325
+ "\x00\x00\x00\x00\xFF\x00\xFF\x00", "\x00\x00\x00\x00\xFF\x00\xFF\xFF",
326
+ "\x00\x00\x00\x00\xFF\xFF\x00\x00", "\x00\x00\x00\x00\xFF\xFF\x00\xFF",
327
+ "\x00\x00\x00\x00\xFF\xFF\xFF\x00", "\x00\x00\x00\x00\xFF\xFF\xFF\xFF",
328
+ "\x00\x00\x00\xFF\x00\x00\x00\x00", "\x00\x00\x00\xFF\x00\x00\x00\xFF",
329
+ "\x00\x00\x00\xFF\x00\x00\xFF\x00", "\x00\x00\x00\xFF\x00\x00\xFF\xFF",
330
+ "\x00\x00\x00\xFF\x00\xFF\x00\x00", "\x00\x00\x00\xFF\x00\xFF\x00\xFF",
331
+ "\x00\x00\x00\xFF\x00\xFF\xFF\x00", "\x00\x00\x00\xFF\x00\xFF\xFF\xFF",
332
+ "\x00\x00\x00\xFF\xFF\x00\x00\x00", "\x00\x00\x00\xFF\xFF\x00\x00\xFF",
333
+ "\x00\x00\x00\xFF\xFF\x00\xFF\x00", "\x00\x00\x00\xFF\xFF\x00\xFF\xFF",
334
+ "\x00\x00\x00\xFF\xFF\xFF\x00\x00", "\x00\x00\x00\xFF\xFF\xFF\x00\xFF",
335
+ "\x00\x00\x00\xFF\xFF\xFF\xFF\x00", "\x00\x00\x00\xFF\xFF\xFF\xFF\xFF",
336
+ "\x00\x00\xFF\x00\x00\x00\x00\x00", "\x00\x00\xFF\x00\x00\x00\x00\xFF",
337
+ "\x00\x00\xFF\x00\x00\x00\xFF\x00", "\x00\x00\xFF\x00\x00\x00\xFF\xFF",
338
+ "\x00\x00\xFF\x00\x00\xFF\x00\x00", "\x00\x00\xFF\x00\x00\xFF\x00\xFF",
339
+ "\x00\x00\xFF\x00\x00\xFF\xFF\x00", "\x00\x00\xFF\x00\x00\xFF\xFF\xFF",
340
+ "\x00\x00\xFF\x00\xFF\x00\x00\x00", "\x00\x00\xFF\x00\xFF\x00\x00\xFF",
341
+ "\x00\x00\xFF\x00\xFF\x00\xFF\x00", "\x00\x00\xFF\x00\xFF\x00\xFF\xFF",
342
+ "\x00\x00\xFF\x00\xFF\xFF\x00\x00", "\x00\x00\xFF\x00\xFF\xFF\x00\xFF",
343
+ "\x00\x00\xFF\x00\xFF\xFF\xFF\x00", "\x00\x00\xFF\x00\xFF\xFF\xFF\xFF",
344
+ "\x00\x00\xFF\xFF\x00\x00\x00\x00", "\x00\x00\xFF\xFF\x00\x00\x00\xFF",
345
+ "\x00\x00\xFF\xFF\x00\x00\xFF\x00", "\x00\x00\xFF\xFF\x00\x00\xFF\xFF",
346
+ "\x00\x00\xFF\xFF\x00\xFF\x00\x00", "\x00\x00\xFF\xFF\x00\xFF\x00\xFF",
347
+ "\x00\x00\xFF\xFF\x00\xFF\xFF\x00", "\x00\x00\xFF\xFF\x00\xFF\xFF\xFF",
348
+ "\x00\x00\xFF\xFF\xFF\x00\x00\x00", "\x00\x00\xFF\xFF\xFF\x00\x00\xFF",
349
+ "\x00\x00\xFF\xFF\xFF\x00\xFF\x00", "\x00\x00\xFF\xFF\xFF\x00\xFF\xFF",
350
+ "\x00\x00\xFF\xFF\xFF\xFF\x00\x00", "\x00\x00\xFF\xFF\xFF\xFF\x00\xFF",
351
+ "\x00\x00\xFF\xFF\xFF\xFF\xFF\x00", "\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF",
352
+ "\x00\xFF\x00\x00\x00\x00\x00\x00", "\x00\xFF\x00\x00\x00\x00\x00\xFF",
353
+ "\x00\xFF\x00\x00\x00\x00\xFF\x00", "\x00\xFF\x00\x00\x00\x00\xFF\xFF",
354
+ "\x00\xFF\x00\x00\x00\xFF\x00\x00", "\x00\xFF\x00\x00\x00\xFF\x00\xFF",
355
+ "\x00\xFF\x00\x00\x00\xFF\xFF\x00", "\x00\xFF\x00\x00\x00\xFF\xFF\xFF",
356
+ "\x00\xFF\x00\x00\xFF\x00\x00\x00", "\x00\xFF\x00\x00\xFF\x00\x00\xFF",
357
+ "\x00\xFF\x00\x00\xFF\x00\xFF\x00", "\x00\xFF\x00\x00\xFF\x00\xFF\xFF",
358
+ "\x00\xFF\x00\x00\xFF\xFF\x00\x00", "\x00\xFF\x00\x00\xFF\xFF\x00\xFF",
359
+ "\x00\xFF\x00\x00\xFF\xFF\xFF\x00", "\x00\xFF\x00\x00\xFF\xFF\xFF\xFF",
360
+ "\x00\xFF\x00\xFF\x00\x00\x00\x00", "\x00\xFF\x00\xFF\x00\x00\x00\xFF",
361
+ "\x00\xFF\x00\xFF\x00\x00\xFF\x00", "\x00\xFF\x00\xFF\x00\x00\xFF\xFF",
362
+ "\x00\xFF\x00\xFF\x00\xFF\x00\x00", "\x00\xFF\x00\xFF\x00\xFF\x00\xFF",
363
+ "\x00\xFF\x00\xFF\x00\xFF\xFF\x00", "\x00\xFF\x00\xFF\x00\xFF\xFF\xFF",
364
+ "\x00\xFF\x00\xFF\xFF\x00\x00\x00", "\x00\xFF\x00\xFF\xFF\x00\x00\xFF",
365
+ "\x00\xFF\x00\xFF\xFF\x00\xFF\x00", "\x00\xFF\x00\xFF\xFF\x00\xFF\xFF",
366
+ "\x00\xFF\x00\xFF\xFF\xFF\x00\x00", "\x00\xFF\x00\xFF\xFF\xFF\x00\xFF",
367
+ "\x00\xFF\x00\xFF\xFF\xFF\xFF\x00", "\x00\xFF\x00\xFF\xFF\xFF\xFF\xFF",
368
+ "\x00\xFF\xFF\x00\x00\x00\x00\x00", "\x00\xFF\xFF\x00\x00\x00\x00\xFF",
369
+ "\x00\xFF\xFF\x00\x00\x00\xFF\x00", "\x00\xFF\xFF\x00\x00\x00\xFF\xFF",
370
+ "\x00\xFF\xFF\x00\x00\xFF\x00\x00", "\x00\xFF\xFF\x00\x00\xFF\x00\xFF",
371
+ "\x00\xFF\xFF\x00\x00\xFF\xFF\x00", "\x00\xFF\xFF\x00\x00\xFF\xFF\xFF",
372
+ "\x00\xFF\xFF\x00\xFF\x00\x00\x00", "\x00\xFF\xFF\x00\xFF\x00\x00\xFF",
373
+ "\x00\xFF\xFF\x00\xFF\x00\xFF\x00", "\x00\xFF\xFF\x00\xFF\x00\xFF\xFF",
374
+ "\x00\xFF\xFF\x00\xFF\xFF\x00\x00", "\x00\xFF\xFF\x00\xFF\xFF\x00\xFF",
375
+ "\x00\xFF\xFF\x00\xFF\xFF\xFF\x00", "\x00\xFF\xFF\x00\xFF\xFF\xFF\xFF",
376
+ "\x00\xFF\xFF\xFF\x00\x00\x00\x00", "\x00\xFF\xFF\xFF\x00\x00\x00\xFF",
377
+ "\x00\xFF\xFF\xFF\x00\x00\xFF\x00", "\x00\xFF\xFF\xFF\x00\x00\xFF\xFF",
378
+ "\x00\xFF\xFF\xFF\x00\xFF\x00\x00", "\x00\xFF\xFF\xFF\x00\xFF\x00\xFF",
379
+ "\x00\xFF\xFF\xFF\x00\xFF\xFF\x00", "\x00\xFF\xFF\xFF\x00\xFF\xFF\xFF",
380
+ "\x00\xFF\xFF\xFF\xFF\x00\x00\x00", "\x00\xFF\xFF\xFF\xFF\x00\x00\xFF",
381
+ "\x00\xFF\xFF\xFF\xFF\x00\xFF\x00", "\x00\xFF\xFF\xFF\xFF\x00\xFF\xFF",
382
+ "\x00\xFF\xFF\xFF\xFF\xFF\x00\x00", "\x00\xFF\xFF\xFF\xFF\xFF\x00\xFF",
383
+ "\x00\xFF\xFF\xFF\xFF\xFF\xFF\x00", "\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF",
384
+ "\xFF\x00\x00\x00\x00\x00\x00\x00", "\xFF\x00\x00\x00\x00\x00\x00\xFF",
385
+ "\xFF\x00\x00\x00\x00\x00\xFF\x00", "\xFF\x00\x00\x00\x00\x00\xFF\xFF",
386
+ "\xFF\x00\x00\x00\x00\xFF\x00\x00", "\xFF\x00\x00\x00\x00\xFF\x00\xFF",
387
+ "\xFF\x00\x00\x00\x00\xFF\xFF\x00", "\xFF\x00\x00\x00\x00\xFF\xFF\xFF",
388
+ "\xFF\x00\x00\x00\xFF\x00\x00\x00", "\xFF\x00\x00\x00\xFF\x00\x00\xFF",
389
+ "\xFF\x00\x00\x00\xFF\x00\xFF\x00", "\xFF\x00\x00\x00\xFF\x00\xFF\xFF",
390
+ "\xFF\x00\x00\x00\xFF\xFF\x00\x00", "\xFF\x00\x00\x00\xFF\xFF\x00\xFF",
391
+ "\xFF\x00\x00\x00\xFF\xFF\xFF\x00", "\xFF\x00\x00\x00\xFF\xFF\xFF\xFF",
392
+ "\xFF\x00\x00\xFF\x00\x00\x00\x00", "\xFF\x00\x00\xFF\x00\x00\x00\xFF",
393
+ "\xFF\x00\x00\xFF\x00\x00\xFF\x00", "\xFF\x00\x00\xFF\x00\x00\xFF\xFF",
394
+ "\xFF\x00\x00\xFF\x00\xFF\x00\x00", "\xFF\x00\x00\xFF\x00\xFF\x00\xFF",
395
+ "\xFF\x00\x00\xFF\x00\xFF\xFF\x00", "\xFF\x00\x00\xFF\x00\xFF\xFF\xFF",
396
+ "\xFF\x00\x00\xFF\xFF\x00\x00\x00", "\xFF\x00\x00\xFF\xFF\x00\x00\xFF",
397
+ "\xFF\x00\x00\xFF\xFF\x00\xFF\x00", "\xFF\x00\x00\xFF\xFF\x00\xFF\xFF",
398
+ "\xFF\x00\x00\xFF\xFF\xFF\x00\x00", "\xFF\x00\x00\xFF\xFF\xFF\x00\xFF",
399
+ "\xFF\x00\x00\xFF\xFF\xFF\xFF\x00", "\xFF\x00\x00\xFF\xFF\xFF\xFF\xFF",
400
+ "\xFF\x00\xFF\x00\x00\x00\x00\x00", "\xFF\x00\xFF\x00\x00\x00\x00\xFF",
401
+ "\xFF\x00\xFF\x00\x00\x00\xFF\x00", "\xFF\x00\xFF\x00\x00\x00\xFF\xFF",
402
+ "\xFF\x00\xFF\x00\x00\xFF\x00\x00", "\xFF\x00\xFF\x00\x00\xFF\x00\xFF",
403
+ "\xFF\x00\xFF\x00\x00\xFF\xFF\x00", "\xFF\x00\xFF\x00\x00\xFF\xFF\xFF",
404
+ "\xFF\x00\xFF\x00\xFF\x00\x00\x00", "\xFF\x00\xFF\x00\xFF\x00\x00\xFF",
405
+ "\xFF\x00\xFF\x00\xFF\x00\xFF\x00", "\xFF\x00\xFF\x00\xFF\x00\xFF\xFF",
406
+ "\xFF\x00\xFF\x00\xFF\xFF\x00\x00", "\xFF\x00\xFF\x00\xFF\xFF\x00\xFF",
407
+ "\xFF\x00\xFF\x00\xFF\xFF\xFF\x00", "\xFF\x00\xFF\x00\xFF\xFF\xFF\xFF",
408
+ "\xFF\x00\xFF\xFF\x00\x00\x00\x00", "\xFF\x00\xFF\xFF\x00\x00\x00\xFF",
409
+ "\xFF\x00\xFF\xFF\x00\x00\xFF\x00", "\xFF\x00\xFF\xFF\x00\x00\xFF\xFF",
410
+ "\xFF\x00\xFF\xFF\x00\xFF\x00\x00", "\xFF\x00\xFF\xFF\x00\xFF\x00\xFF",
411
+ "\xFF\x00\xFF\xFF\x00\xFF\xFF\x00", "\xFF\x00\xFF\xFF\x00\xFF\xFF\xFF",
412
+ "\xFF\x00\xFF\xFF\xFF\x00\x00\x00", "\xFF\x00\xFF\xFF\xFF\x00\x00\xFF",
413
+ "\xFF\x00\xFF\xFF\xFF\x00\xFF\x00", "\xFF\x00\xFF\xFF\xFF\x00\xFF\xFF",
414
+ "\xFF\x00\xFF\xFF\xFF\xFF\x00\x00", "\xFF\x00\xFF\xFF\xFF\xFF\x00\xFF",
415
+ "\xFF\x00\xFF\xFF\xFF\xFF\xFF\x00", "\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF",
416
+ "\xFF\xFF\x00\x00\x00\x00\x00\x00", "\xFF\xFF\x00\x00\x00\x00\x00\xFF",
417
+ "\xFF\xFF\x00\x00\x00\x00\xFF\x00", "\xFF\xFF\x00\x00\x00\x00\xFF\xFF",
418
+ "\xFF\xFF\x00\x00\x00\xFF\x00\x00", "\xFF\xFF\x00\x00\x00\xFF\x00\xFF",
419
+ "\xFF\xFF\x00\x00\x00\xFF\xFF\x00", "\xFF\xFF\x00\x00\x00\xFF\xFF\xFF",
420
+ "\xFF\xFF\x00\x00\xFF\x00\x00\x00", "\xFF\xFF\x00\x00\xFF\x00\x00\xFF",
421
+ "\xFF\xFF\x00\x00\xFF\x00\xFF\x00", "\xFF\xFF\x00\x00\xFF\x00\xFF\xFF",
422
+ "\xFF\xFF\x00\x00\xFF\xFF\x00\x00", "\xFF\xFF\x00\x00\xFF\xFF\x00\xFF",
423
+ "\xFF\xFF\x00\x00\xFF\xFF\xFF\x00", "\xFF\xFF\x00\x00\xFF\xFF\xFF\xFF",
424
+ "\xFF\xFF\x00\xFF\x00\x00\x00\x00", "\xFF\xFF\x00\xFF\x00\x00\x00\xFF",
425
+ "\xFF\xFF\x00\xFF\x00\x00\xFF\x00", "\xFF\xFF\x00\xFF\x00\x00\xFF\xFF",
426
+ "\xFF\xFF\x00\xFF\x00\xFF\x00\x00", "\xFF\xFF\x00\xFF\x00\xFF\x00\xFF",
427
+ "\xFF\xFF\x00\xFF\x00\xFF\xFF\x00", "\xFF\xFF\x00\xFF\x00\xFF\xFF\xFF",
428
+ "\xFF\xFF\x00\xFF\xFF\x00\x00\x00", "\xFF\xFF\x00\xFF\xFF\x00\x00\xFF",
429
+ "\xFF\xFF\x00\xFF\xFF\x00\xFF\x00", "\xFF\xFF\x00\xFF\xFF\x00\xFF\xFF",
430
+ "\xFF\xFF\x00\xFF\xFF\xFF\x00\x00", "\xFF\xFF\x00\xFF\xFF\xFF\x00\xFF",
431
+ "\xFF\xFF\x00\xFF\xFF\xFF\xFF\x00", "\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF",
432
+ "\xFF\xFF\xFF\x00\x00\x00\x00\x00", "\xFF\xFF\xFF\x00\x00\x00\x00\xFF",
433
+ "\xFF\xFF\xFF\x00\x00\x00\xFF\x00", "\xFF\xFF\xFF\x00\x00\x00\xFF\xFF",
434
+ "\xFF\xFF\xFF\x00\x00\xFF\x00\x00", "\xFF\xFF\xFF\x00\x00\xFF\x00\xFF",
435
+ "\xFF\xFF\xFF\x00\x00\xFF\xFF\x00", "\xFF\xFF\xFF\x00\x00\xFF\xFF\xFF",
436
+ "\xFF\xFF\xFF\x00\xFF\x00\x00\x00", "\xFF\xFF\xFF\x00\xFF\x00\x00\xFF",
437
+ "\xFF\xFF\xFF\x00\xFF\x00\xFF\x00", "\xFF\xFF\xFF\x00\xFF\x00\xFF\xFF",
438
+ "\xFF\xFF\xFF\x00\xFF\xFF\x00\x00", "\xFF\xFF\xFF\x00\xFF\xFF\x00\xFF",
439
+ "\xFF\xFF\xFF\x00\xFF\xFF\xFF\x00", "\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF",
440
+ "\xFF\xFF\xFF\xFF\x00\x00\x00\x00", "\xFF\xFF\xFF\xFF\x00\x00\x00\xFF",
441
+ "\xFF\xFF\xFF\xFF\x00\x00\xFF\x00", "\xFF\xFF\xFF\xFF\x00\x00\xFF\xFF",
442
+ "\xFF\xFF\xFF\xFF\x00\xFF\x00\x00", "\xFF\xFF\xFF\xFF\x00\xFF\x00\xFF",
443
+ "\xFF\xFF\xFF\xFF\x00\xFF\xFF\x00", "\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF",
444
+ "\xFF\xFF\xFF\xFF\xFF\x00\x00\x00", "\xFF\xFF\xFF\xFF\xFF\x00\x00\xFF",
445
+ "\xFF\xFF\xFF\xFF\xFF\x00\xFF\x00", "\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF",
446
+ "\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00", "\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF",
447
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00", "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
448
+ );
449
+
450
+ /**
451
+ * IP mapping helper table.
452
+ *
453
+ * Indexing this table with each source byte performs the initial bit permutation.
454
+ *
455
+ * @var Array
456
+ * @access private
457
+ */
458
+ var $ipmap = array(
459
+ 0x00, 0x10, 0x01, 0x11, 0x20, 0x30, 0x21, 0x31,
460
+ 0x02, 0x12, 0x03, 0x13, 0x22, 0x32, 0x23, 0x33,
461
+ 0x40, 0x50, 0x41, 0x51, 0x60, 0x70, 0x61, 0x71,
462
+ 0x42, 0x52, 0x43, 0x53, 0x62, 0x72, 0x63, 0x73,
463
+ 0x04, 0x14, 0x05, 0x15, 0x24, 0x34, 0x25, 0x35,
464
+ 0x06, 0x16, 0x07, 0x17, 0x26, 0x36, 0x27, 0x37,
465
+ 0x44, 0x54, 0x45, 0x55, 0x64, 0x74, 0x65, 0x75,
466
+ 0x46, 0x56, 0x47, 0x57, 0x66, 0x76, 0x67, 0x77,
467
+ 0x80, 0x90, 0x81, 0x91, 0xA0, 0xB0, 0xA1, 0xB1,
468
+ 0x82, 0x92, 0x83, 0x93, 0xA2, 0xB2, 0xA3, 0xB3,
469
+ 0xC0, 0xD0, 0xC1, 0xD1, 0xE0, 0xF0, 0xE1, 0xF1,
470
+ 0xC2, 0xD2, 0xC3, 0xD3, 0xE2, 0xF2, 0xE3, 0xF3,
471
+ 0x84, 0x94, 0x85, 0x95, 0xA4, 0xB4, 0xA5, 0xB5,
472
+ 0x86, 0x96, 0x87, 0x97, 0xA6, 0xB6, 0xA7, 0xB7,
473
+ 0xC4, 0xD4, 0xC5, 0xD5, 0xE4, 0xF4, 0xE5, 0xF5,
474
+ 0xC6, 0xD6, 0xC7, 0xD7, 0xE6, 0xF6, 0xE7, 0xF7,
475
+ 0x08, 0x18, 0x09, 0x19, 0x28, 0x38, 0x29, 0x39,
476
+ 0x0A, 0x1A, 0x0B, 0x1B, 0x2A, 0x3A, 0x2B, 0x3B,
477
+ 0x48, 0x58, 0x49, 0x59, 0x68, 0x78, 0x69, 0x79,
478
+ 0x4A, 0x5A, 0x4B, 0x5B, 0x6A, 0x7A, 0x6B, 0x7B,
479
+ 0x0C, 0x1C, 0x0D, 0x1D, 0x2C, 0x3C, 0x2D, 0x3D,
480
+ 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
481
+ 0x4C, 0x5C, 0x4D, 0x5D, 0x6C, 0x7C, 0x6D, 0x7D,
482
+ 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
483
+ 0x88, 0x98, 0x89, 0x99, 0xA8, 0xB8, 0xA9, 0xB9,
484
+ 0x8A, 0x9A, 0x8B, 0x9B, 0xAA, 0xBA, 0xAB, 0xBB,
485
+ 0xC8, 0xD8, 0xC9, 0xD9, 0xE8, 0xF8, 0xE9, 0xF9,
486
+ 0xCA, 0xDA, 0xCB, 0xDB, 0xEA, 0xFA, 0xEB, 0xFB,
487
+ 0x8C, 0x9C, 0x8D, 0x9D, 0xAC, 0xBC, 0xAD, 0xBD,
488
+ 0x8E, 0x9E, 0x8F, 0x9F, 0xAE, 0xBE, 0xAF, 0xBF,
489
+ 0xCC, 0xDC, 0xCD, 0xDD, 0xEC, 0xFC, 0xED, 0xFD,
490
+ 0xCE, 0xDE, 0xCF, 0xDF, 0xEE, 0xFE, 0xEF, 0xFF
491
+ );
492
+
493
+ /**
494
+ * Inverse IP mapping helper table.
495
+ * Indexing this table with a byte value reverses the bit order.
496
+ *
497
+ * @var Array
498
+ * @access private
499
+ */
500
+ var $invipmap = array(
501
+ 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0,
502
+ 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
503
+ 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,
504
+ 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
505
+ 0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4,
506
+ 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
507
+ 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC,
508
+ 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
509
+ 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2,
510
+ 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
511
+ 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA,
512
+ 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
513
+ 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6,
514
+ 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
515
+ 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE,
516
+ 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
517
+ 0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1,
518
+ 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
519
+ 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9,
520
+ 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
521
+ 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5,
522
+ 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
523
+ 0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED,
524
+ 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
525
+ 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3,
526
+ 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
527
+ 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB,
528
+ 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
529
+ 0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7,
530
+ 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
531
+ 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF,
532
+ 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
533
+ );
534
+
535
+ /**
536
+ * Pre-permuted S-box1
537
+ *
538
+ * Each box ($sbox1-$sbox8) has been vectorized, then each value pre-permuted using the
539
+ * P table: concatenation can then be replaced by exclusive ORs.
540
+ *
541
+ * @var Array
542
+ * @access private
543
+ */
544
+ var $sbox1 = array(
545
+ 0x00808200, 0x00000000, 0x00008000, 0x00808202,
546
+ 0x00808002, 0x00008202, 0x00000002, 0x00008000,
547
+ 0x00000200, 0x00808200, 0x00808202, 0x00000200,
548
+ 0x00800202, 0x00808002, 0x00800000, 0x00000002,
549
+ 0x00000202, 0x00800200, 0x00800200, 0x00008200,
550
+ 0x00008200, 0x00808000, 0x00808000, 0x00800202,
551
+ 0x00008002, 0x00800002, 0x00800002, 0x00008002,
552
+ 0x00000000, 0x00000202, 0x00008202, 0x00800000,
553
+ 0x00008000, 0x00808202, 0x00000002, 0x00808000,
554
+ 0x00808200, 0x00800000, 0x00800000, 0x00000200,
555
+ 0x00808002, 0x00008000, 0x00008200, 0x00800002,
556
+ 0x00000200, 0x00000002, 0x00800202, 0x00008202,
557
+ 0x00808202, 0x00008002, 0x00808000, 0x00800202,
558
+ 0x00800002, 0x00000202, 0x00008202, 0x00808200,
559
+ 0x00000202, 0x00800200, 0x00800200, 0x00000000,
560
+ 0x00008002, 0x00008200, 0x00000000, 0x00808002
561
+ );
562
+
563
+ /**
564
+ * Pre-permuted S-box2
565
+ *
566
+ * @var Array
567
+ * @access private
568
+ */
569
+ var $sbox2 = array(
570
+ 0x40084010, 0x40004000, 0x00004000, 0x00084010,
571
+ 0x00080000, 0x00000010, 0x40080010, 0x40004010,
572
+ 0x40000010, 0x40084010, 0x40084000, 0x40000000,
573
+ 0x40004000, 0x00080000, 0x00000010, 0x40080010,
574
+ 0x00084000, 0x00080010, 0x40004010, 0x00000000,
575
+ 0x40000000, 0x00004000, 0x00084010, 0x40080000,
576
+ 0x00080010, 0x40000010, 0x00000000, 0x00084000,
577
+ 0x00004010, 0x40084000, 0x40080000, 0x00004010,
578
+ 0x00000000, 0x00084010, 0x40080010, 0x00080000,
579
+ 0x40004010, 0x40080000, 0x40084000, 0x00004000,
580
+ 0x40080000, 0x40004000, 0x00000010, 0x40084010,
581
+ 0x00084010, 0x00000010, 0x00004000, 0x40000000,
582
+ 0x00004010, 0x40084000, 0x00080000, 0x40000010,
583
+ 0x00080010, 0x40004010, 0x40000010, 0x00080010,
584
+ 0x00084000, 0x00000000, 0x40004000, 0x00004010,
585
+ 0x40000000, 0x40080010, 0x40084010, 0x00084000
586
+ );
587
+
588
+ /**
589
+ * Pre-permuted S-box3
590
+ *
591
+ * @var Array
592
+ * @access private
593
+ */
594
+ var $sbox3 = array(
595
+ 0x00000104, 0x04010100, 0x00000000, 0x04010004,
596
+ 0x04000100, 0x00000000, 0x00010104, 0x04000100,
597
+ 0x00010004, 0x04000004, 0x04000004, 0x00010000,
598
+ 0x04010104, 0x00010004, 0x04010000, 0x00000104,
599
+ 0x04000000, 0x00000004, 0x04010100, 0x00000100,
600
+ 0x00010100, 0x04010000, 0x04010004, 0x00010104,
601
+ 0x04000104, 0x00010100, 0x00010000, 0x04000104,
602
+ 0x00000004, 0x04010104, 0x00000100, 0x04000000,
603
+ 0x04010100, 0x04000000, 0x00010004, 0x00000104,
604
+ 0x00010000, 0x04010100, 0x04000100, 0x00000000,
605
+ 0x00000100, 0x00010004, 0x04010104, 0x04000100,
606
+ 0x04000004, 0x00000100, 0x00000000, 0x04010004,
607
+ 0x04000104, 0x00010000, 0x04000000, 0x04010104,
608
+ 0x00000004, 0x00010104, 0x00010100, 0x04000004,
609
+ 0x04010000, 0x04000104, 0x00000104, 0x04010000,
610
+ 0x00010104, 0x00000004, 0x04010004, 0x00010100
611
+ );
612
+
613
+ /**
614
+ * Pre-permuted S-box4
615
+ *
616
+ * @var Array
617
+ * @access private
618
+ */
619
+ var $sbox4 = array(
620
+ 0x80401000, 0x80001040, 0x80001040, 0x00000040,
621
+ 0x00401040, 0x80400040, 0x80400000, 0x80001000,
622
+ 0x00000000, 0x00401000, 0x00401000, 0x80401040,
623
+ 0x80000040, 0x00000000, 0x00400040, 0x80400000,
624
+ 0x80000000, 0x00001000, 0x00400000, 0x80401000,
625
+ 0x00000040, 0x00400000, 0x80001000, 0x00001040,
626
+ 0x80400040, 0x80000000, 0x00001040, 0x00400040,
627
+ 0x00001000, 0x00401040, 0x80401040, 0x80000040,
628
+ 0x00400040, 0x80400000, 0x00401000, 0x80401040,
629
+ 0x80000040, 0x00000000, 0x00000000, 0x00401000,
630
+ 0x00001040, 0x00400040, 0x80400040, 0x80000000,
631
+ 0x80401000, 0x80001040, 0x80001040, 0x00000040,
632
+ 0x80401040, 0x80000040, 0x80000000, 0x00001000,
633
+ 0x80400000, 0x80001000, 0x00401040, 0x80400040,
634
+ 0x80001000, 0x00001040, 0x00400000, 0x80401000,
635
+ 0x00000040, 0x00400000, 0x00001000, 0x00401040
636
+ );
637
+
638
+ /**
639
+ * Pre-permuted S-box5
640
+ *
641
+ * @var Array
642
+ * @access private
643
+ */
644
+ var $sbox5 = array(
645
+ 0x00000080, 0x01040080, 0x01040000, 0x21000080,
646
+ 0x00040000, 0x00000080, 0x20000000, 0x01040000,
647
+ 0x20040080, 0x00040000, 0x01000080, 0x20040080,
648
+ 0x21000080, 0x21040000, 0x00040080, 0x20000000,
649
+ 0x01000000, 0x20040000, 0x20040000, 0x00000000,
650
+ 0x20000080, 0x21040080, 0x21040080, 0x01000080,
651
+ 0x21040000, 0x20000080, 0x00000000, 0x21000000,
652
+ 0x01040080, 0x01000000, 0x21000000, 0x00040080,
653
+ 0x00040000, 0x21000080, 0x00000080, 0x01000000,
654
+ 0x20000000, 0x01040000, 0x21000080, 0x20040080,
655
+ 0x01000080, 0x20000000, 0x21040000, 0x01040080,
656
+ 0x20040080, 0x00000080, 0x01000000, 0x21040000,
657
+ 0x21040080, 0x00040080, 0x21000000, 0x21040080,
658
+ 0x01040000, 0x00000000, 0x20040000, 0x21000000,
659
+ 0x00040080, 0x01000080, 0x20000080, 0x00040000,
660
+ 0x00000000, 0x20040000, 0x01040080, 0x20000080
661
+ );
662
+
663
+ /**
664
+ * Pre-permuted S-box6
665
+ *
666
+ * @var Array
667
+ * @access private
668
+ */
669
+ var $sbox6 = array(
670
+ 0x10000008, 0x10200000, 0x00002000, 0x10202008,
671
+ 0x10200000, 0x00000008, 0x10202008, 0x00200000,
672
+ 0x10002000, 0x00202008, 0x00200000, 0x10000008,
673
+ 0x00200008, 0x10002000, 0x10000000, 0x00002008,
674
+ 0x00000000, 0x00200008, 0x10002008, 0x00002000,
675
+ 0x00202000, 0x10002008, 0x00000008, 0x10200008,
676
+ 0x10200008, 0x00000000, 0x00202008, 0x10202000,
677
+ 0x00002008, 0x00202000, 0x10202000, 0x10000000,
678
+ 0x10002000, 0x00000008, 0x10200008, 0x00202000,
679
+ 0x10202008, 0x00200000, 0x00002008, 0x10000008,
680
+ 0x00200000, 0x10002000, 0x10000000, 0x00002008,
681
+ 0x10000008, 0x10202008, 0x00202000, 0x10200000,
682
+ 0x00202008, 0x10202000, 0x00000000, 0x10200008,
683
+ 0x00000008, 0x00002000, 0x10200000, 0x00202008,
684
+ 0x00002000, 0x00200008, 0x10002008, 0x00000000,
685
+ 0x10202000, 0x10000000, 0x00200008, 0x10002008
686
+ );
687
+
688
+ /**
689
+ * Pre-permuted S-box7
690
+ *
691
+ * @var Array
692
+ * @access private
693
+ */
694
+ var $sbox7 = array(
695
+ 0x00100000, 0x02100001, 0x02000401, 0x00000000,
696
+ 0x00000400, 0x02000401, 0x00100401, 0x02100400,
697
+ 0x02100401, 0x00100000, 0x00000000, 0x02000001,
698
+ 0x00000001, 0x02000000, 0x02100001, 0x00000401,
699
+ 0x02000400, 0x00100401, 0x00100001, 0x02000400,
700
+ 0x02000001, 0x02100000, 0x02100400, 0x00100001,
701
+ 0x02100000, 0x00000400, 0x00000401, 0x02100401,
702
+ 0x00100400, 0x00000001, 0x02000000, 0x00100400,
703
+ 0x02000000, 0x00100400, 0x00100000, 0x02000401,
704
+ 0x02000401, 0x02100001, 0x02100001, 0x00000001,
705
+ 0x00100001, 0x02000000, 0x02000400, 0x00100000,
706
+ 0x02100400, 0x00000401, 0x00100401, 0x02100400,
707
+ 0x00000401, 0x02000001, 0x02100401, 0x02100000,
708
+ 0x00100400, 0x00000000, 0x00000001, 0x02100401,
709
+ 0x00000000, 0x00100401, 0x02100000, 0x00000400,
710
+ 0x02000001, 0x02000400, 0x00000400, 0x00100001
711
+ );
712
+
713
+ /**
714
+ * Pre-permuted S-box8
715
+ *
716
+ * @var Array
717
+ * @access private
718
+ */
719
+ var $sbox8 = array(
720
+ 0x08000820, 0x00000800, 0x00020000, 0x08020820,
721
+ 0x08000000, 0x08000820, 0x00000020, 0x08000000,
722
+ 0x00020020, 0x08020000, 0x08020820, 0x00020800,
723
+ 0x08020800, 0x00020820, 0x00000800, 0x00000020,
724
+ 0x08020000, 0x08000020, 0x08000800, 0x00000820,
725
+ 0x00020800, 0x00020020, 0x08020020, 0x08020800,
726
+ 0x00000820, 0x00000000, 0x00000000, 0x08020020,
727
+ 0x08000020, 0x08000800, 0x00020820, 0x00020000,
728
+ 0x00020820, 0x00020000, 0x08020800, 0x00000800,
729
+ 0x00000020, 0x08020020, 0x00000800, 0x00020820,
730
+ 0x08000800, 0x00000020, 0x08000020, 0x08020000,
731
+ 0x08020020, 0x08000000, 0x00020000, 0x08000820,
732
+ 0x00000000, 0x08020820, 0x00020020, 0x08000020,
733
+ 0x08020000, 0x08000800, 0x08000820, 0x00000000,
734
+ 0x08020820, 0x00020800, 0x00020800, 0x00000820,
735
+ 0x00000820, 0x00020020, 0x08000000, 0x08020800
736
+ );
737
+
738
+ /**
739
+ * Default Constructor.
740
+ *
741
+ * Determines whether or not the mcrypt extension should be used. $mode should only, at present, be
742
+ * CRYPT_DES_MODE_ECB or CRYPT_DES_MODE_CBC. If not explictly set, CRYPT_DES_MODE_CBC will be used.
743
+ *
744
+ * @param optional Integer $mode
745
+ * @return Crypt_DES
746
+ * @access public
747
+ */
748
+ function Crypt_DES($mode = CRYPT_DES_MODE_CBC)
749
+ {
750
+ if ( !defined('CRYPT_DES_MODE') ) {
751
+ switch (true) {
752
+ case extension_loaded('mcrypt') && in_array('des', mcrypt_list_algorithms()):
753
+ define('CRYPT_DES_MODE', CRYPT_DES_MODE_MCRYPT);
754
+ break;
755
+ default:
756
+ define('CRYPT_DES_MODE', CRYPT_DES_MODE_INTERNAL);
757
+ }
758
+ }
759
+
760
+ switch ( CRYPT_DES_MODE ) {
761
+ case CRYPT_DES_MODE_MCRYPT:
762
+ switch ($mode) {
763
+ case CRYPT_DES_MODE_ECB:
764
+ $this->paddable = true;
765
+ $this->mode = MCRYPT_MODE_ECB;
766
+ break;
767
+ case CRYPT_DES_MODE_CTR:
768
+ $this->mode = 'ctr';
769
+ //$this->mode = in_array('ctr', mcrypt_list_modes()) ? 'ctr' : CRYPT_DES_MODE_CTR;
770
+ break;
771
+ case CRYPT_DES_MODE_CFB:
772
+ $this->mode = 'ncfb';
773
+ $this->ecb = mcrypt_module_open(MCRYPT_DES, '', MCRYPT_MODE_ECB, '');
774
+ break;
775
+ case CRYPT_DES_MODE_OFB:
776
+ $this->mode = MCRYPT_MODE_NOFB;
777
+ break;
778
+ case CRYPT_DES_MODE_CBC:
779
+ default:
780
+ $this->paddable = true;
781
+ $this->mode = MCRYPT_MODE_CBC;
782
+ }
783
+ $this->enmcrypt = mcrypt_module_open(MCRYPT_DES, '', $this->mode, '');
784
+ $this->demcrypt = mcrypt_module_open(MCRYPT_DES, '', $this->mode, '');
785
+
786
+ break;
787
+ default:
788
+ switch ($mode) {
789
+ case CRYPT_DES_MODE_ECB:
790
+ case CRYPT_DES_MODE_CBC:
791
+ $this->paddable = true;
792
+ $this->mode = $mode;
793
+ break;
794
+ case CRYPT_DES_MODE_CTR:
795
+ case CRYPT_DES_MODE_CFB:
796
+ case CRYPT_DES_MODE_OFB:
797
+ $this->mode = $mode;
798
+ break;
799
+ default:
800
+ $this->paddable = true;
801
+ $this->mode = CRYPT_DES_MODE_CBC;
802
+ }
803
+ if (function_exists('create_function') && is_callable('create_function')) {
804
+ $this->inline_crypt_setup();
805
+ $this->use_inline_crypt = true;
806
+ }
807
+ }
808
+ }
809
+
810
+ /**
811
+ * Sets the key.
812
+ *
813
+ * Keys can be of any length. DES, itself, uses 64-bit keys (eg. strlen($key) == 8), however, we
814
+ * only use the first eight, if $key has more then eight characters in it, and pad $key with the
815
+ * null byte if it is less then eight characters long.
816
+ *
817
+ * DES also requires that every eighth bit be a parity bit, however, we'll ignore that.
818
+ *
819
+ * If the key is not explicitly set, it'll be assumed to be all zero's.
820
+ *
821
+ * @access public
822
+ * @param String $key
823
+ */
824
+ function setKey($key)
825
+ {
826
+ $this->keys = ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) ? str_pad(substr($key, 0, 8), 8, chr(0)) : $this->_prepareKey($key);
827
+ $this->enchanged = true;
828
+ $this->dechanged = true;
829
+ }
830
+
831
+ /**
832
+ * Sets the password.
833
+ *
834
+ * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows:
835
+ * {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2}:
836
+ * $hash, $salt, $count
837
+ *
838
+ * @param String $password
839
+ * @param optional String $method
840
+ * @access public
841
+ */
842
+ function setPassword($password, $method = 'pbkdf2')
843
+ {
844
+ $key = '';
845
+
846
+ switch ($method) {
847
+ default: // 'pbkdf2'
848
+ list(, , $hash, $salt, $count) = func_get_args();
849
+ if (!isset($hash)) {
850
+ $hash = 'sha1';
851
+ }
852
+ // WPA and WPA2 use the SSID as the salt
853
+ if (!isset($salt)) {
854
+ $salt = 'phpseclib/salt';
855
+ }
856
+ // RFC2898#section-4.2 uses 1,000 iterations by default
857
+ // WPA and WPA2 use 4,096.
858
+ if (!isset($count)) {
859
+ $count = 1000;
860
+ }
861
+
862
+ if (!class_exists('Crypt_Hash')) {
863
+ require_once('Crypt/Hash.php');
864
+ }
865
+
866
+ $i = 1;
867
+ while (strlen($key) < 8) { // $dkLen == 8
868
+ //$dk.= $this->_pbkdf($password, $salt, $count, $i++);
869
+ $hmac = new Crypt_Hash();
870
+ $hmac->setHash($hash);
871
+ $hmac->setKey($password);
872
+ $f = $u = $hmac->hash($salt . pack('N', $i++));
873
+ for ($j = 2; $j <= $count; $j++) {
874
+ $u = $hmac->hash($u);
875
+ $f^= $u;
876
+ }
877
+ $key.= $f;
878
+ }
879
+ }
880
+
881
+ $this->setKey($key);
882
+ }
883
+
884
+ /**
885
+ * Sets the initialization vector. (optional)
886
+ *
887
+ * SetIV is not required when CRYPT_DES_MODE_ECB is being used. If not explictly set, it'll be assumed
888
+ * to be all zero's.
889
+ *
890
+ * @access public
891
+ * @param String $iv
892
+ */
893
+ function setIV($iv)
894
+ {
895
+ $this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($iv, 0, 8), 8, chr(0));
896
+ $this->enchanged = true;
897
+ $this->dechanged = true;
898
+ }
899
+
900
+ /**
901
+ * Generate CTR XOR encryption key
902
+ *
903
+ * Encrypt the output of this and XOR it against the ciphertext / plaintext to get the
904
+ * plaintext / ciphertext in CTR mode.
905
+ *
906
+ * @see Crypt_DES::decrypt()
907
+ * @see Crypt_DES::encrypt()
908
+ * @access public
909
+ * @param String $iv
910
+ */
911
+ function _generate_xor(&$iv)
912
+ {
913
+ $xor = $iv;
914
+ for ($j = 4; $j <= 8; $j+=4) {
915
+ $temp = substr($iv, -$j, 4);
916
+ switch ($temp) {
917
+ case "\xFF\xFF\xFF\xFF":
918
+ $iv = substr_replace($iv, "\x00\x00\x00\x00", -$j, 4);
919
+ break;
920
+ case "\x7F\xFF\xFF\xFF":
921
+ $iv = substr_replace($iv, "\x80\x00\x00\x00", -$j, 4);
922
+ break 2;
923
+ default:
924
+ extract(unpack('Ncount', $temp));
925
+ $iv = substr_replace($iv, pack('N', $count + 1), -$j, 4);
926
+ break 2;
927
+ }
928
+ }
929
+
930
+ return $xor;
931
+ }
932
+
933
+ /**
934
+ * Encrypts a message.
935
+ *
936
+ * $plaintext will be padded with up to 8 additional bytes. Other DES implementations may or may not pad in the
937
+ * same manner. Other common approaches to padding and the reasons why it's necessary are discussed in the following
938
+ * URL:
939
+ *
940
+ * {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html}
941
+ *
942
+ * An alternative to padding is to, separately, send the length of the file. This is what SSH, in fact, does.
943
+ * strlen($plaintext) will still need to be a multiple of 8, however, arbitrary values can be added to make it that
944
+ * length.
945
+ *
946
+ * @see Crypt_DES::decrypt()
947
+ * @access public
948
+ * @param String $plaintext
949
+ */
950
+ function encrypt($plaintext)
951
+ {
952
+ if ($this->paddable) {
953
+ $plaintext = $this->_pad($plaintext);
954
+ }
955
+
956
+ if ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) {
957
+ if ($this->enchanged) {
958
+ mcrypt_generic_init($this->enmcrypt, $this->keys, $this->encryptIV);
959
+ if ($this->mode == 'ncfb') {
960
+ mcrypt_generic_init($this->ecb, $this->keys, "\0\0\0\0\0\0\0\0");
961
+ }
962
+ $this->enchanged = false;
963
+ }
964
+
965
+ if ($this->mode != 'ncfb' || !$this->continuousBuffer) {
966
+ $ciphertext = mcrypt_generic($this->enmcrypt, $plaintext);
967
+ } else {
968
+ $iv = &$this->encryptIV;
969
+ $pos = &$this->enbuffer['pos'];
970
+ $len = strlen($plaintext);
971
+ $ciphertext = '';
972
+ $i = 0;
973
+ if ($pos) {
974
+ $orig_pos = $pos;
975
+ $max = 8 - $pos;
976
+ if ($len >= $max) {
977
+ $i = $max;
978
+ $len-= $max;
979
+ $pos = 0;
980
+ } else {
981
+ $i = $len;
982
+ $pos+= $len;
983
+ $len = 0;
984
+ }
985
+ $ciphertext = substr($iv, $orig_pos) ^ $plaintext;
986
+ $iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
987
+ $this->enbuffer['enmcrypt_init'] = true;
988
+ }
989
+ if ($len >= 8) {
990
+ if ($this->enbuffer['enmcrypt_init'] === false || $len > 600) {
991
+ if ($this->enbuffer['enmcrypt_init'] === true) {
992
+ mcrypt_generic_init($this->enmcrypt, $this->keys, $iv);
993
+ $this->enbuffer['enmcrypt_init'] = false;
994
+ }
995
+ $ciphertext.= mcrypt_generic($this->enmcrypt, substr($plaintext, $i, $len - $len % 8));
996
+ $iv = substr($ciphertext, -8);
997
+ $len%= 8;
998
+ } else {
999
+ while ($len >= 8) {
1000
+ $iv = mcrypt_generic($this->ecb, $iv) ^ substr($plaintext, $i, 8);
1001
+ $ciphertext.= $iv;
1002
+ $len-= 8;
1003
+ $i+= 8;
1004
+ }
1005
+ }
1006
+ }
1007
+ if ($len) {
1008
+ $iv = mcrypt_generic($this->ecb, $iv);
1009
+ $block = $iv ^ substr($plaintext, -$len);
1010
+ $iv = substr_replace($iv, $block, 0, $len);
1011
+ $ciphertext.= $block;
1012
+ $pos = $len;
1013
+ }
1014
+ return $ciphertext;
1015
+ }
1016
+
1017
+ if (!$this->continuousBuffer) {
1018
+ mcrypt_generic_init($this->enmcrypt, $this->keys, $this->encryptIV);
1019
+ }
1020
+
1021
+ return $ciphertext;
1022
+ }
1023
+
1024
+ if (!is_array($this->keys)) {
1025
+ $this->keys = $this->_prepareKey("\0\0\0\0\0\0\0\0");
1026
+ }
1027
+
1028
+ if ($this->use_inline_crypt) {
1029
+ $inline = $this->inline_crypt;
1030
+ return $inline('encrypt', $this, $plaintext);
1031
+ }
1032
+
1033
+ $buffer = &$this->enbuffer;
1034
+ $continuousBuffer = $this->continuousBuffer;
1035
+ $ciphertext = '';
1036
+ switch ($this->mode) {
1037
+ case CRYPT_DES_MODE_ECB:
1038
+ for ($i = 0; $i < strlen($plaintext); $i+=8) {
1039
+ $ciphertext.= $this->_processBlock(substr($plaintext, $i, 8), CRYPT_DES_ENCRYPT);
1040
+ }
1041
+ break;
1042
+ case CRYPT_DES_MODE_CBC:
1043
+ $xor = $this->encryptIV;
1044
+ for ($i = 0; $i < strlen($plaintext); $i+=8) {
1045
+ $block = substr($plaintext, $i, 8);
1046
+ $block = $this->_processBlock($block ^ $xor, CRYPT_DES_ENCRYPT);
1047
+ $xor = $block;
1048
+ $ciphertext.= $block;
1049
+ }
1050
+ if ($this->continuousBuffer) {
1051
+ $this->encryptIV = $xor;
1052
+ }
1053
+ break;
1054
+ case CRYPT_DES_MODE_CTR:
1055
+ $xor = $this->encryptIV;
1056
+ if (strlen($buffer['encrypted'])) {
1057
+ for ($i = 0; $i < strlen($plaintext); $i+=8) {
1058
+ $block = substr($plaintext, $i, 8);
1059
+ if (strlen($block) > strlen($buffer['encrypted'])) {
1060
+ $buffer['encrypted'].= $this->_processBlock($this->_generate_xor($xor), CRYPT_DES_ENCRYPT);
1061
+ }
1062
+ $key = $this->_string_shift($buffer['encrypted']);
1063
+ $ciphertext.= $block ^ $key;
1064
+ }
1065
+ } else {
1066
+ for ($i = 0; $i < strlen($plaintext); $i+=8) {
1067
+ $block = substr($plaintext, $i, 8);
1068
+ $key = $this->_processBlock($this->_generate_xor($xor), CRYPT_DES_ENCRYPT);
1069
+ $ciphertext.= $block ^ $key;
1070
+ }
1071
+ }
1072
+ if ($this->continuousBuffer) {
1073
+ $this->encryptIV = $xor;
1074
+ if ($start = strlen($plaintext) & 7) {
1075
+ $buffer['encrypted'] = substr($key, $start) . $buffer['encrypted'];
1076
+ }
1077
+ }
1078
+ break;
1079
+ case CRYPT_DES_MODE_CFB:
1080
+ if ($this->continuousBuffer) {
1081
+ $iv = &$this->encryptIV;
1082
+ $pos = &$buffer['pos'];
1083
+ } else {
1084
+ $iv = $this->encryptIV;
1085
+ $pos = 0;
1086
+ }
1087
+ $len = strlen($plaintext);
1088
+ $i = 0;
1089
+ if ($pos) {
1090
+ $orig_pos = $pos;
1091
+ $max = 8 - $pos;
1092
+ if ($len >= $max) {
1093
+ $i = $max;
1094
+ $len-= $max;
1095
+ $pos = 0;
1096
+ } else {
1097
+ $i = $len;
1098
+ $pos+= $len;
1099
+ $len = 0;
1100
+ }
1101
+ $ciphertext = substr($iv, $orig_pos) ^ $plaintext;
1102
+ $iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
1103
+ }
1104
+ while ($len >= 8) {
1105
+ $iv = $this->_processBlock($iv, CRYPT_DES_ENCRYPT) ^ substr($plaintext, $i, 8);
1106
+ $ciphertext.= $iv;
1107
+ $len-= 8;
1108
+ $i+= 8;
1109
+ }
1110
+ if ($len) {
1111
+ $iv = $this->_processBlock($iv, CRYPT_DES_ENCRYPT);
1112
+ $block = $iv ^ substr($plaintext, $i);
1113
+ $iv = substr_replace($iv, $block, 0, $len);
1114
+ $ciphertext.= $block;
1115
+ $pos = $len;
1116
+ }
1117
+ return $ciphertext;
1118
+ case CRYPT_DES_MODE_OFB:
1119
+ $xor = $this->encryptIV;
1120
+ if (strlen($buffer['xor'])) {
1121
+ for ($i = 0; $i < strlen($plaintext); $i+=8) {
1122
+ $block = substr($plaintext, $i, 8);
1123
+ if (strlen($block) > strlen($buffer['xor'])) {
1124
+ $xor = $this->_processBlock($xor, CRYPT_DES_ENCRYPT);
1125
+ $buffer['xor'].= $xor;
1126
+ }
1127
+ $key = $this->_string_shift($buffer['xor']);
1128
+ $ciphertext.= $block ^ $key;
1129
+ }
1130
+ } else {
1131
+ for ($i = 0; $i < strlen($plaintext); $i+=8) {
1132
+ $xor = $this->_processBlock($xor, CRYPT_DES_ENCRYPT);
1133
+ $ciphertext.= substr($plaintext, $i, 8) ^ $xor;
1134
+ }
1135
+ $key = $xor;
1136
+ }
1137
+ if ($this->continuousBuffer) {
1138
+ $this->encryptIV = $xor;
1139
+ if ($start = strlen($plaintext) & 7) {
1140
+ $buffer['xor'] = substr($key, $start) . $buffer['xor'];
1141
+ }
1142
+ }
1143
+ }
1144
+
1145
+ return $ciphertext;
1146
+ }
1147
+
1148
+ /**
1149
+ * Decrypts a message.
1150
+ *
1151
+ * If strlen($ciphertext) is not a multiple of 8, null bytes will be added to the end of the string until it is.
1152
+ *
1153
+ * @see Crypt_DES::encrypt()
1154
+ * @access public
1155
+ * @param String $ciphertext
1156
+ */
1157
+ function decrypt($ciphertext)
1158
+ {
1159
+ if ($this->paddable) {
1160
+ // we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic :
1161
+ // "The data is padded with "\0" to make sure the length of the data is n * blocksize."
1162
+ $ciphertext = str_pad($ciphertext, (strlen($ciphertext) + 7) & 0xFFFFFFF8, chr(0));
1163
+ }
1164
+
1165
+ if ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) {
1166
+ if ($this->dechanged) {
1167
+ mcrypt_generic_init($this->demcrypt, $this->keys, $this->decryptIV);
1168
+ if ($this->mode == 'ncfb') {
1169
+ mcrypt_generic_init($this->ecb, $this->keys, "\0\0\0\0\0\0\0\0");
1170
+ }
1171
+ $this->dechanged = false;
1172
+ }
1173
+
1174
+ if ($this->mode != 'ncfb' || !$this->continuousBuffer) {
1175
+ $plaintext = mdecrypt_generic($this->demcrypt, $ciphertext);
1176
+ } else {
1177
+ $iv = &$this->decryptIV;
1178
+ $pos = &$this->debuffer['pos'];
1179
+ $len = strlen($ciphertext);
1180
+ $plaintext = '';
1181
+ $i = 0;
1182
+ if ($pos) {
1183
+ $orig_pos = $pos;
1184
+ $max = 8 - $pos;
1185
+ if ($len >= $max) {
1186
+ $i = $max;
1187
+ $len-= $max;
1188
+ $pos = 0;
1189
+ } else {
1190
+ $i = $len;
1191
+ $pos+= $len;
1192
+ $len = 0;
1193
+ }
1194
+ $plaintext = substr($iv, $orig_pos) ^ $ciphertext;
1195
+ $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
1196
+ }
1197
+ if ($len >= 8) {
1198
+ $cb = substr($ciphertext, $i, $len - $len % 8);
1199
+ $plaintext.= mcrypt_generic($this->ecb, $iv . $cb) ^ $cb;
1200
+ $iv = substr($cb, -8);
1201
+ $len%= 8;
1202
+ }
1203
+ if ($len) {
1204
+ $iv = mcrypt_generic($this->ecb, $iv);
1205
+ $plaintext.= $iv ^ substr($ciphertext, -$len);
1206
+ $iv = substr_replace($iv, substr($ciphertext, -$len), 0, $len);
1207
+ $pos = $len;
1208
+ }
1209
+ return $plaintext;
1210
+ }
1211
+
1212
+ if (!$this->continuousBuffer) {
1213
+ mcrypt_generic_init($this->demcrypt, $this->keys, $this->decryptIV);
1214
+ }
1215
+
1216
+ return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
1217
+ }
1218
+
1219
+ if (!is_array($this->keys)) {
1220
+ $this->keys = $this->_prepareKey("\0\0\0\0\0\0\0\0");
1221
+ }
1222
+
1223
+ if ($this->use_inline_crypt) {
1224
+ $inline = $this->inline_crypt;
1225
+ return $inline('decrypt', $this, $ciphertext);
1226
+ }
1227
+
1228
+ $buffer = &$this->debuffer;
1229
+ $continuousBuffer = $this->continuousBuffer;
1230
+ $plaintext = '';
1231
+ switch ($this->mode) {
1232
+ case CRYPT_DES_MODE_ECB:
1233
+ for ($i = 0; $i < strlen($ciphertext); $i+=8) {
1234
+ $plaintext.= $this->_processBlock(substr($ciphertext, $i, 8), CRYPT_DES_DECRYPT);
1235
+ }
1236
+ break;
1237
+ case CRYPT_DES_MODE_CBC:
1238
+ $xor = $this->decryptIV;
1239
+ for ($i = 0; $i < strlen($ciphertext); $i+=8) {
1240
+ $block = substr($ciphertext, $i, 8);
1241
+ $plaintext.= $this->_processBlock($block, CRYPT_DES_DECRYPT) ^ $xor;
1242
+ $xor = $block;
1243
+ }
1244
+ if ($this->continuousBuffer) {
1245
+ $this->decryptIV = $xor;
1246
+ }
1247
+ break;
1248
+ case CRYPT_DES_MODE_CTR:
1249
+ $xor = $this->decryptIV;
1250
+ if (strlen($buffer['ciphertext'])) {
1251
+ for ($i = 0; $i < strlen($ciphertext); $i+=8) {
1252
+ $block = substr($ciphertext, $i, 8);
1253
+ if (strlen($block) > strlen($buffer['ciphertext'])) {
1254
+ $buffer['ciphertext'].= $this->_processBlock($this->_generate_xor($xor), CRYPT_DES_ENCRYPT);
1255
+ }
1256
+ $key = $this->_string_shift($buffer['ciphertext']);
1257
+ $plaintext.= $block ^ $key;
1258
+ }
1259
+ } else {
1260
+ for ($i = 0; $i < strlen($ciphertext); $i+=8) {
1261
+ $block = substr($ciphertext, $i, 8);
1262
+ $key = $this->_processBlock($this->_generate_xor($xor), CRYPT_DES_ENCRYPT);
1263
+ $plaintext.= $block ^ $key;
1264
+ }
1265
+ }
1266
+ if ($this->continuousBuffer) {
1267
+ $this->decryptIV = $xor;
1268
+ if ($start = strlen($ciphertext) % 8) {
1269
+ $buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext'];
1270
+ }
1271
+ }
1272
+ break;
1273
+ case CRYPT_DES_MODE_CFB:
1274
+ if ($this->continuousBuffer) {
1275
+ $iv = &$this->decryptIV;
1276
+ $pos = &$buffer['pos'];
1277
+ } else {
1278
+ $iv = $this->decryptIV;
1279
+ $pos = 0;
1280
+ }
1281
+ $len = strlen($ciphertext);
1282
+ $i = 0;
1283
+ if ($pos) {
1284
+ $orig_pos = $pos;
1285
+ $max = 8 - $pos;
1286
+ if ($len >= $max) {
1287
+ $i = $max;
1288
+ $len-= $max;
1289
+ $pos = 0;
1290
+ } else {
1291
+ $i = $len;
1292
+ $pos+= $len;
1293
+ $len = 0;
1294
+ }
1295
+ $plaintext = substr($iv, $orig_pos) ^ $ciphertext;
1296
+ $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
1297
+ }
1298
+ while ($len >= 8) {
1299
+ $iv = $this->_processBlock($iv, CRYPT_DES_ENCRYPT);
1300
+ $cb = substr($ciphertext, $i, 8);
1301
+ $plaintext.= $iv ^ $cb;
1302
+ $iv = $cb;
1303
+ $len-= 8;
1304
+ $i+= 8;
1305
+ }
1306
+ if ($len) {
1307
+ $iv = $this->_processBlock($iv, CRYPT_DES_ENCRYPT);
1308
+ $plaintext.= $iv ^ substr($ciphertext, $i);
1309
+ $iv = substr_replace($iv, substr($ciphertext, $i), 0, $len);
1310
+ $pos = $len;
1311
+ }
1312
+ return $plaintext;
1313
+ case CRYPT_DES_MODE_OFB:
1314
+ $xor = $this->decryptIV;
1315
+ if (strlen($buffer['xor'])) {
1316
+ for ($i = 0; $i < strlen($ciphertext); $i+=8) {
1317
+ $block = substr($ciphertext, $i, 8);
1318
+ if (strlen($block) > strlen($buffer['xor'])) {
1319
+ $xor = $this->_processBlock($xor, CRYPT_DES_ENCRYPT);
1320
+ $buffer['xor'].= $xor;
1321
+ }
1322
+ $key = $this->_string_shift($buffer['xor']);
1323
+ $plaintext.= $block ^ $key;
1324
+ }
1325
+ } else {
1326
+ for ($i = 0; $i < strlen($ciphertext); $i+=8) {
1327
+ $xor = $this->_processBlock($xor, CRYPT_DES_ENCRYPT);
1328
+ $plaintext.= substr($ciphertext, $i, 8) ^ $xor;
1329
+ }
1330
+ $key = $xor;
1331
+ }
1332
+ if ($this->continuousBuffer) {
1333
+ $this->decryptIV = $xor;
1334
+ if ($start = strlen($ciphertext) % 8) {
1335
+ $buffer['xor'] = substr($key, $start) . $buffer['xor'];
1336
+ }
1337
+ }
1338
+ }
1339
+
1340
+ return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
1341
+ }
1342
+
1343
+ /**
1344
+ * Treat consecutive "packets" as if they are a continuous buffer.
1345
+ *
1346
+ * Say you have a 16-byte plaintext $plaintext. Using the default behavior, the two following code snippets
1347
+ * will yield different outputs:
1348
+ *
1349
+ * <code>
1350
+ * echo $des->encrypt(substr($plaintext, 0, 8));
1351
+ * echo $des->encrypt(substr($plaintext, 8, 8));
1352
+ * </code>
1353
+ * <code>
1354
+ * echo $des->encrypt($plaintext);
1355
+ * </code>
1356
+ *
1357
+ * The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates
1358
+ * another, as demonstrated with the following:
1359
+ *
1360
+ * <code>
1361
+ * $des->encrypt(substr($plaintext, 0, 8));
1362
+ * echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8)));
1363
+ * </code>
1364
+ * <code>
1365
+ * echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8)));
1366
+ * </code>
1367
+ *
1368
+ * With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different
1369
+ * outputs. The reason is due to the fact that the initialization vector's change after every encryption /
1370
+ * decryption round when the continuous buffer is enabled. When it's disabled, they remain constant.
1371
+ *
1372
+ * Put another way, when the continuous buffer is enabled, the state of the Crypt_DES() object changes after each
1373
+ * encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that
1374
+ * continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them),
1375
+ * however, they are also less intuitive and more likely to cause you problems.
1376
+ *
1377
+ * @see Crypt_DES::disableContinuousBuffer()
1378
+ * @access public
1379
+ */
1380
+ function enableContinuousBuffer()
1381
+ {
1382
+ $this->continuousBuffer = true;
1383
+ }
1384
+
1385
+ /**
1386
+ * Treat consecutive packets as if they are a discontinuous buffer.
1387
+ *
1388
+ * The default behavior.
1389
+ *
1390
+ * @see Crypt_DES::enableContinuousBuffer()
1391
+ * @access public
1392
+ */
1393
+ function disableContinuousBuffer()
1394
+ {
1395
+ $this->continuousBuffer = false;
1396
+ $this->encryptIV = $this->iv;
1397
+ $this->decryptIV = $this->iv;
1398
+ $this->enbuffer = array('encrypted' => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true);
1399
+ $this->debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0, 'demcrypt_init' => true);
1400
+
1401
+ if (CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT) {
1402
+ mcrypt_generic_init($this->enmcrypt, $this->keys, $this->iv);
1403
+ mcrypt_generic_init($this->demcrypt, $this->keys, $this->iv);
1404
+ }
1405
+ }
1406
+
1407
+ /**
1408
+ * Pad "packets".
1409
+ *
1410
+ * DES works by encrypting eight bytes at a time. If you ever need to encrypt or decrypt something that's not
1411
+ * a multiple of eight, it becomes necessary to pad the input so that it's length is a multiple of eight.
1412
+ *
1413
+ * Padding is enabled by default. Sometimes, however, it is undesirable to pad strings. Such is the case in SSH1,
1414
+ * where "packets" are padded with random bytes before being encrypted. Unpad these packets and you risk stripping
1415
+ * away characters that shouldn't be stripped away. (SSH knows how many bytes are added because the length is
1416
+ * transmitted separately)
1417
+ *
1418
+ * @see Crypt_DES::disablePadding()
1419
+ * @access public
1420
+ */
1421
+ function enablePadding()
1422
+ {
1423
+ $this->padding = true;
1424
+ }
1425
+
1426
+ /**
1427
+ * Do not pad packets.
1428
+ *
1429
+ * @see Crypt_DES::enablePadding()
1430
+ * @access public
1431
+ */
1432
+ function disablePadding()
1433
+ {
1434
+ $this->padding = false;
1435
+ }
1436
+
1437
+ /**
1438
+ * Pads a string
1439
+ *
1440
+ * Pads a string using the RSA PKCS padding standards so that its length is a multiple of the blocksize (8).
1441
+ * 8 - (strlen($text) & 7) bytes are added, each of which is equal to chr(8 - (strlen($text) & 7)
1442
+ *
1443
+ * If padding is disabled and $text is not a multiple of the blocksize, the string will be padded regardless
1444
+ * and padding will, hence forth, be enabled.
1445
+ *
1446
+ * @see Crypt_DES::_unpad()
1447
+ * @access private
1448
+ */
1449
+ function _pad($text)
1450
+ {
1451
+ $length = strlen($text);
1452
+
1453
+ if (!$this->padding) {
1454
+ if (($length & 7) == 0) {
1455
+ return $text;
1456
+ } else {
1457
+ user_error("The plaintext's length ($length) is not a multiple of the block size (8)");
1458
+ $this->padding = true;
1459
+ }
1460
+ }
1461
+
1462
+ $pad = 8 - ($length & 7);
1463
+ return str_pad($text, $length + $pad, chr($pad));
1464
+ }
1465
+
1466
+ /**
1467
+ * Unpads a string
1468
+ *
1469
+ * If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong
1470
+ * and false will be returned.
1471
+ *
1472
+ * @see Crypt_DES::_pad()
1473
+ * @access private
1474
+ */
1475
+ function _unpad($text)
1476
+ {
1477
+ if (!$this->padding) {
1478
+ return $text;
1479
+ }
1480
+
1481
+ $length = ord($text[strlen($text) - 1]);
1482
+
1483
+ if (!$length || $length > 8) {
1484
+ return false;
1485
+ }
1486
+
1487
+ return substr($text, 0, -$length);
1488
+ }
1489
+
1490
+ /**
1491
+ * Encrypts or decrypts a 64-bit block
1492
+ *
1493
+ * $mode should be either CRYPT_DES_ENCRYPT or CRYPT_DES_DECRYPT. See
1494
+ * {@link http://en.wikipedia.org/wiki/Image:Feistel.png Feistel.png} to get a general
1495
+ * idea of what this function does.
1496
+ *
1497
+ * @access private
1498
+ * @param String $block
1499
+ * @param Integer $mode
1500
+ * @return String
1501
+ */
1502
+ function _processBlock($block, $mode)
1503
+ {
1504
+ $shuffle = $this->shuffle;
1505
+ $invipmap = $this->invipmap;
1506
+ $ipmap = $this->ipmap;
1507
+ $sbox1 = $this->sbox1;
1508
+ $sbox2 = $this->sbox2;
1509
+ $sbox3 = $this->sbox3;
1510
+ $sbox4 = $this->sbox4;
1511
+ $sbox5 = $this->sbox5;
1512
+ $sbox6 = $this->sbox6;
1513
+ $sbox7 = $this->sbox7;
1514
+ $sbox8 = $this->sbox8;
1515
+ $keys = $this->keys[$mode];
1516
+
1517
+ // Do the initial IP permutation.
1518
+ $t = unpack('Nl/Nr', $block);
1519
+ list($l, $r) = array($t['l'], $t['r']);
1520
+ $block = ($shuffle[$ipmap[$r & 0xFF]] & "\x80\x80\x80\x80\x80\x80\x80\x80") |
1521
+ ($shuffle[$ipmap[($r >> 8) & 0xFF]] & "\x40\x40\x40\x40\x40\x40\x40\x40") |
1522
+ ($shuffle[$ipmap[($r >> 16) & 0xFF]] & "\x20\x20\x20\x20\x20\x20\x20\x20") |
1523
+ ($shuffle[$ipmap[($r >> 24) & 0xFF]] & "\x10\x10\x10\x10\x10\x10\x10\x10") |
1524
+ ($shuffle[$ipmap[$l & 0xFF]] & "\x08\x08\x08\x08\x08\x08\x08\x08") |
1525
+ ($shuffle[$ipmap[($l >> 8) & 0xFF]] & "\x04\x04\x04\x04\x04\x04\x04\x04") |
1526
+ ($shuffle[$ipmap[($l >> 16) & 0xFF]] & "\x02\x02\x02\x02\x02\x02\x02\x02") |
1527
+ ($shuffle[$ipmap[($l >> 24) & 0xFF]] & "\x01\x01\x01\x01\x01\x01\x01\x01");
1528
+
1529
+ // Extract L0 and R0.
1530
+ $t = unpack('Nl/Nr', $block);
1531
+ list($l, $r) = array($t['l'], $t['r']);
1532
+
1533
+ // Perform the 16 steps.
1534
+ for ($i = 0; $i < 16; $i++) {
1535
+ // start of "the Feistel (F) function" - see the following URL:
1536
+ // http://en.wikipedia.org/wiki/Image:Data_Encryption_Standard_InfoBox_Diagram.png
1537
+ // Merge key schedule.
1538
+ $b1 = (($r >> 3) & 0x1FFFFFFF) ^ ($r << 29) ^ $keys[$i][0];
1539
+ $b2 = (($r >> 31) & 0x00000001) ^ ($r << 1) ^ $keys[$i][1];
1540
+
1541
+ // S-box indexing.
1542
+ $t = $sbox1[($b1 >> 24) & 0x3F] ^ $sbox2[($b2 >> 24) & 0x3F] ^
1543
+ $sbox3[($b1 >> 16) & 0x3F] ^ $sbox4[($b2 >> 16) & 0x3F] ^
1544
+ $sbox5[($b1 >> 8) & 0x3F] ^ $sbox6[($b2 >> 8) & 0x3F] ^
1545
+ $sbox7[$b1 & 0x3F] ^ $sbox8[$b2 & 0x3F] ^ $l;
1546
+ // end of "the Feistel (F) function"
1547
+
1548
+ $l = $r;
1549
+ $r = $t;
1550
+ }
1551
+
1552
+ // Perform the inverse IP permutation.
1553
+ return ($shuffle[$invipmap[($l >> 24) & 0xFF]] & "\x80\x80\x80\x80\x80\x80\x80\x80") |
1554
+ ($shuffle[$invipmap[($r >> 24) & 0xFF]] & "\x40\x40\x40\x40\x40\x40\x40\x40") |
1555
+ ($shuffle[$invipmap[($l >> 16) & 0xFF]] & "\x20\x20\x20\x20\x20\x20\x20\x20") |
1556
+ ($shuffle[$invipmap[($r >> 16) & 0xFF]] & "\x10\x10\x10\x10\x10\x10\x10\x10") |
1557
+ ($shuffle[$invipmap[($l >> 8) & 0xFF]] & "\x08\x08\x08\x08\x08\x08\x08\x08") |
1558
+ ($shuffle[$invipmap[($r >> 8) & 0xFF]] & "\x04\x04\x04\x04\x04\x04\x04\x04") |
1559
+ ($shuffle[$invipmap[$l & 0xFF]] & "\x02\x02\x02\x02\x02\x02\x02\x02") |
1560
+ ($shuffle[$invipmap[$r & 0xFF]] & "\x01\x01\x01\x01\x01\x01\x01\x01");
1561
+ }
1562
+
1563
+ /**
1564
+ * Creates the key schedule.
1565
+ *
1566
+ * @access private
1567
+ * @param String $key
1568
+ * @return Array
1569
+ */
1570
+ function _prepareKey($key)
1571
+ {
1572
+ static $shifts = array( // number of key bits shifted per round
1573
+ 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
1574
+ );
1575
+
1576
+ static $pc1map = array(
1577
+ 0x00, 0x00, 0x08, 0x08, 0x04, 0x04, 0x0C, 0x0C,
1578
+ 0x02, 0x02, 0x0A, 0x0A, 0x06, 0x06, 0x0E, 0x0E,
1579
+ 0x10, 0x10, 0x18, 0x18, 0x14, 0x14, 0x1C, 0x1C,
1580
+ 0x12, 0x12, 0x1A, 0x1A, 0x16, 0x16, 0x1E, 0x1E,
1581
+ 0x20, 0x20, 0x28, 0x28, 0x24, 0x24, 0x2C, 0x2C,
1582
+ 0x22, 0x22, 0x2A, 0x2A, 0x26, 0x26, 0x2E, 0x2E,
1583
+ 0x30, 0x30, 0x38, 0x38, 0x34, 0x34, 0x3C, 0x3C,
1584
+ 0x32, 0x32, 0x3A, 0x3A, 0x36, 0x36, 0x3E, 0x3E,
1585
+ 0x40, 0x40, 0x48, 0x48, 0x44, 0x44, 0x4C, 0x4C,
1586
+ 0x42, 0x42, 0x4A, 0x4A, 0x46, 0x46, 0x4E, 0x4E,
1587
+ 0x50, 0x50, 0x58, 0x58, 0x54, 0x54, 0x5C, 0x5C,
1588
+ 0x52, 0x52, 0x5A, 0x5A, 0x56, 0x56, 0x5E, 0x5E,
1589
+ 0x60, 0x60, 0x68, 0x68, 0x64, 0x64, 0x6C, 0x6C,
1590
+ 0x62, 0x62, 0x6A, 0x6A, 0x66, 0x66, 0x6E, 0x6E,
1591
+ 0x70, 0x70, 0x78, 0x78, 0x74, 0x74, 0x7C, 0x7C,
1592
+ 0x72, 0x72, 0x7A, 0x7A, 0x76, 0x76, 0x7E, 0x7E,
1593
+ 0x80, 0x80, 0x88, 0x88, 0x84, 0x84, 0x8C, 0x8C,
1594
+ 0x82, 0x82, 0x8A, 0x8A, 0x86, 0x86, 0x8E, 0x8E,
1595
+ 0x90, 0x90, 0x98, 0x98, 0x94, 0x94, 0x9C, 0x9C,
1596
+ 0x92, 0x92, 0x9A, 0x9A, 0x96, 0x96, 0x9E, 0x9E,
1597
+ 0xA0, 0xA0, 0xA8, 0xA8, 0xA4, 0xA4, 0xAC, 0xAC,
1598
+ 0xA2, 0xA2, 0xAA, 0xAA, 0xA6, 0xA6, 0xAE, 0xAE,
1599
+ 0xB0, 0xB0, 0xB8, 0xB8, 0xB4, 0xB4, 0xBC, 0xBC,
1600
+ 0xB2, 0xB2, 0xBA, 0xBA, 0xB6, 0xB6, 0xBE, 0xBE,
1601
+ 0xC0, 0xC0, 0xC8, 0xC8, 0xC4, 0xC4, 0xCC, 0xCC,
1602
+ 0xC2, 0xC2, 0xCA, 0xCA, 0xC6, 0xC6, 0xCE, 0xCE,
1603
+ 0xD0, 0xD0, 0xD8, 0xD8, 0xD4, 0xD4, 0xDC, 0xDC,
1604
+ 0xD2, 0xD2, 0xDA, 0xDA, 0xD6, 0xD6, 0xDE, 0xDE,
1605
+ 0xE0, 0xE0, 0xE8, 0xE8, 0xE4, 0xE4, 0xEC, 0xEC,
1606
+ 0xE2, 0xE2, 0xEA, 0xEA, 0xE6, 0xE6, 0xEE, 0xEE,
1607
+ 0xF0, 0xF0, 0xF8, 0xF8, 0xF4, 0xF4, 0xFC, 0xFC,
1608
+ 0xF2, 0xF2, 0xFA, 0xFA, 0xF6, 0xF6, 0xFE, 0xFE
1609
+ );
1610
+
1611
+ // Mapping tables for the PC-2 transformation.
1612
+ static $pc2mapc1 = array(
1613
+ 0x00000000, 0x00000400, 0x00200000, 0x00200400,
1614
+ 0x00000001, 0x00000401, 0x00200001, 0x00200401,
1615
+ 0x02000000, 0x02000400, 0x02200000, 0x02200400,
1616
+ 0x02000001, 0x02000401, 0x02200001, 0x02200401
1617
+ );
1618
+ static $pc2mapc2 = array(
1619
+ 0x00000000, 0x00000800, 0x08000000, 0x08000800,
1620
+ 0x00010000, 0x00010800, 0x08010000, 0x08010800,
1621
+ 0x00000000, 0x00000800, 0x08000000, 0x08000800,
1622
+ 0x00010000, 0x00010800, 0x08010000, 0x08010800,
1623
+ 0x00000100, 0x00000900, 0x08000100, 0x08000900,
1624
+ 0x00010100, 0x00010900, 0x08010100, 0x08010900,
1625
+ 0x00000100, 0x00000900, 0x08000100, 0x08000900,
1626
+ 0x00010100, 0x00010900, 0x08010100, 0x08010900,
1627
+ 0x00000010, 0x00000810, 0x08000010, 0x08000810,
1628
+ 0x00010010, 0x00010810, 0x08010010, 0x08010810,
1629
+ 0x00000010, 0x00000810, 0x08000010, 0x08000810,
1630
+ 0x00010010, 0x00010810, 0x08010010, 0x08010810,
1631
+ 0x00000110, 0x00000910, 0x08000110, 0x08000910,
1632
+ 0x00010110, 0x00010910, 0x08010110, 0x08010910,
1633
+ 0x00000110, 0x00000910, 0x08000110, 0x08000910,
1634
+ 0x00010110, 0x00010910, 0x08010110, 0x08010910,
1635
+ 0x00040000, 0x00040800, 0x08040000, 0x08040800,
1636
+ 0x00050000, 0x00050800, 0x08050000, 0x08050800,
1637
+ 0x00040000, 0x00040800, 0x08040000, 0x08040800,
1638
+ 0x00050000, 0x00050800, 0x08050000, 0x08050800,
1639
+ 0x00040100, 0x00040900, 0x08040100, 0x08040900,
1640
+ 0x00050100, 0x00050900, 0x08050100, 0x08050900,
1641
+ 0x00040100, 0x00040900, 0x08040100, 0x08040900,
1642
+ 0x00050100, 0x00050900, 0x08050100, 0x08050900,
1643
+ 0x00040010, 0x00040810, 0x08040010, 0x08040810,
1644
+ 0x00050010, 0x00050810, 0x08050010, 0x08050810,
1645
+ 0x00040010, 0x00040810, 0x08040010, 0x08040810,
1646
+ 0x00050010, 0x00050810, 0x08050010, 0x08050810,
1647
+ 0x00040110, 0x00040910, 0x08040110, 0x08040910,
1648
+ 0x00050110, 0x00050910, 0x08050110, 0x08050910,
1649
+ 0x00040110, 0x00040910, 0x08040110, 0x08040910,
1650
+ 0x00050110, 0x00050910, 0x08050110, 0x08050910,
1651
+ 0x01000000, 0x01000800, 0x09000000, 0x09000800,
1652
+ 0x01010000, 0x01010800, 0x09010000, 0x09010800,
1653
+ 0x01000000, 0x01000800, 0x09000000, 0x09000800,
1654
+ 0x01010000, 0x01010800, 0x09010000, 0x09010800,
1655
+ 0x01000100, 0x01000900, 0x09000100, 0x09000900,
1656
+ 0x01010100, 0x01010900, 0x09010100, 0x09010900,
1657
+ 0x01000100, 0x01000900, 0x09000100, 0x09000900,
1658
+ 0x01010100, 0x01010900, 0x09010100, 0x09010900,
1659
+ 0x01000010, 0x01000810, 0x09000010, 0x09000810,
1660
+ 0x01010010, 0x01010810, 0x09010010, 0x09010810,
1661
+ 0x01000010, 0x01000810, 0x09000010, 0x09000810,
1662
+ 0x01010010, 0x01010810, 0x09010010, 0x09010810,
1663
+ 0x01000110, 0x01000910, 0x09000110, 0x09000910,
1664
+ 0x01010110, 0x01010910, 0x09010110, 0x09010910,
1665
+ 0x01000110, 0x01000910, 0x09000110, 0x09000910,
1666
+ 0x01010110, 0x01010910, 0x09010110, 0x09010910,
1667
+ 0x01040000, 0x01040800, 0x09040000, 0x09040800,
1668
+ 0x01050000, 0x01050800, 0x09050000, 0x09050800,
1669
+ 0x01040000, 0x01040800, 0x09040000, 0x09040800,
1670
+ 0x01050000, 0x01050800, 0x09050000, 0x09050800,
1671
+ 0x01040100, 0x01040900, 0x09040100, 0x09040900,
1672
+ 0x01050100, 0x01050900, 0x09050100, 0x09050900,
1673
+ 0x01040100, 0x01040900, 0x09040100, 0x09040900,
1674
+ 0x01050100, 0x01050900, 0x09050100, 0x09050900,
1675
+ 0x01040010, 0x01040810, 0x09040010, 0x09040810,
1676
+ 0x01050010, 0x01050810, 0x09050010, 0x09050810,
1677
+ 0x01040010, 0x01040810, 0x09040010, 0x09040810,
1678
+ 0x01050010, 0x01050810, 0x09050010, 0x09050810,
1679
+ 0x01040110, 0x01040910, 0x09040110, 0x09040910,
1680
+ 0x01050110, 0x01050910, 0x09050110, 0x09050910,
1681
+ 0x01040110, 0x01040910, 0x09040110, 0x09040910,
1682
+ 0x01050110, 0x01050910, 0x09050110, 0x09050910
1683
+ );
1684
+ static $pc2mapc3 = array(
1685
+ 0x00000000, 0x00000004, 0x00001000, 0x00001004,
1686
+ 0x00000000, 0x00000004, 0x00001000, 0x00001004,
1687
+ 0x10000000, 0x10000004, 0x10001000, 0x10001004,
1688
+ 0x10000000, 0x10000004, 0x10001000, 0x10001004,
1689
+ 0x00000020, 0x00000024, 0x00001020, 0x00001024,
1690
+ 0x00000020, 0x00000024, 0x00001020, 0x00001024,
1691
+ 0x10000020, 0x10000024, 0x10001020, 0x10001024,
1692
+ 0x10000020, 0x10000024, 0x10001020, 0x10001024,
1693
+ 0x00080000, 0x00080004, 0x00081000, 0x00081004,
1694
+ 0x00080000, 0x00080004, 0x00081000, 0x00081004,
1695
+ 0x10080000, 0x10080004, 0x10081000, 0x10081004,
1696
+ 0x10080000, 0x10080004, 0x10081000, 0x10081004,
1697
+ 0x00080020, 0x00080024, 0x00081020, 0x00081024,
1698
+ 0x00080020, 0x00080024, 0x00081020, 0x00081024,
1699
+ 0x10080020, 0x10080024, 0x10081020, 0x10081024,
1700
+ 0x10080020, 0x10080024, 0x10081020, 0x10081024,
1701
+ 0x20000000, 0x20000004, 0x20001000, 0x20001004,
1702
+ 0x20000000, 0x20000004, 0x20001000, 0x20001004,
1703
+ 0x30000000, 0x30000004, 0x30001000, 0x30001004,
1704
+ 0x30000000, 0x30000004, 0x30001000, 0x30001004,
1705
+ 0x20000020, 0x20000024, 0x20001020, 0x20001024,
1706
+ 0x20000020, 0x20000024, 0x20001020, 0x20001024,
1707
+ 0x30000020, 0x30000024, 0x30001020, 0x30001024,
1708
+ 0x30000020, 0x30000024, 0x30001020, 0x30001024,
1709
+ 0x20080000, 0x20080004, 0x20081000, 0x20081004,
1710
+ 0x20080000, 0x20080004, 0x20081000, 0x20081004,
1711
+ 0x30080000, 0x30080004, 0x30081000, 0x30081004,
1712
+ 0x30080000, 0x30080004, 0x30081000, 0x30081004,
1713
+ 0x20080020, 0x20080024, 0x20081020, 0x20081024,
1714
+ 0x20080020, 0x20080024, 0x20081020, 0x20081024,
1715
+ 0x30080020, 0x30080024, 0x30081020, 0x30081024,
1716
+ 0x30080020, 0x30080024, 0x30081020, 0x30081024,
1717
+ 0x00000002, 0x00000006, 0x00001002, 0x00001006,
1718
+ 0x00000002, 0x00000006, 0x00001002, 0x00001006,
1719
+ 0x10000002, 0x10000006, 0x10001002, 0x10001006,
1720
+ 0x10000002, 0x10000006, 0x10001002, 0x10001006,
1721
+ 0x00000022, 0x00000026, 0x00001022, 0x00001026,
1722
+ 0x00000022, 0x00000026, 0x00001022, 0x00001026,
1723
+ 0x10000022, 0x10000026, 0x10001022, 0x10001026,
1724
+ 0x10000022, 0x10000026, 0x10001022, 0x10001026,
1725
+ 0x00080002, 0x00080006, 0x00081002, 0x00081006,
1726
+ 0x00080002, 0x00080006, 0x00081002, 0x00081006,
1727
+ 0x10080002, 0x10080006, 0x10081002, 0x10081006,
1728
+ 0x10080002, 0x10080006, 0x10081002, 0x10081006,
1729
+ 0x00080022, 0x00080026, 0x00081022, 0x00081026,
1730
+ 0x00080022, 0x00080026, 0x00081022, 0x00081026,
1731
+ 0x10080022, 0x10080026, 0x10081022, 0x10081026,
1732
+ 0x10080022, 0x10080026, 0x10081022, 0x10081026,
1733
+ 0x20000002, 0x20000006, 0x20001002, 0x20001006,
1734
+ 0x20000002, 0x20000006, 0x20001002, 0x20001006,
1735
+ 0x30000002, 0x30000006, 0x30001002, 0x30001006,
1736
+ 0x30000002, 0x30000006, 0x30001002, 0x30001006,
1737
+ 0x20000022, 0x20000026, 0x20001022, 0x20001026,
1738
+ 0x20000022, 0x20000026, 0x20001022, 0x20001026,
1739
+ 0x30000022, 0x30000026, 0x30001022, 0x30001026,
1740
+ 0x30000022, 0x30000026, 0x30001022, 0x30001026,
1741
+ 0x20080002, 0x20080006, 0x20081002, 0x20081006,
1742
+ 0x20080002, 0x20080006, 0x20081002, 0x20081006,
1743
+ 0x30080002, 0x30080006, 0x30081002, 0x30081006,
1744
+ 0x30080002, 0x30080006, 0x30081002, 0x30081006,
1745
+ 0x20080022, 0x20080026, 0x20081022, 0x20081026,
1746
+ 0x20080022, 0x20080026, 0x20081022, 0x20081026,
1747
+ 0x30080022, 0x30080026, 0x30081022, 0x30081026,
1748
+ 0x30080022, 0x30080026, 0x30081022, 0x30081026
1749
+ );
1750
+ static $pc2mapc4 = array(
1751
+ 0x00000000, 0x00100000, 0x00000008, 0x00100008,
1752
+ 0x00000200, 0x00100200, 0x00000208, 0x00100208,
1753
+ 0x00000000, 0x00100000, 0x00000008, 0x00100008,
1754
+ 0x00000200, 0x00100200, 0x00000208, 0x00100208,
1755
+ 0x04000000, 0x04100000, 0x04000008, 0x04100008,
1756
+ 0x04000200, 0x04100200, 0x04000208, 0x04100208,
1757
+ 0x04000000, 0x04100000, 0x04000008, 0x04100008,
1758
+ 0x04000200, 0x04100200, 0x04000208, 0x04100208,
1759
+ 0x00002000, 0x00102000, 0x00002008, 0x00102008,
1760
+ 0x00002200, 0x00102200, 0x00002208, 0x00102208,
1761
+ 0x00002000, 0x00102000, 0x00002008, 0x00102008,
1762
+ 0x00002200, 0x00102200, 0x00002208, 0x00102208,
1763
+ 0x04002000, 0x04102000, 0x04002008, 0x04102008,
1764
+ 0x04002200, 0x04102200, 0x04002208, 0x04102208,
1765
+ 0x04002000, 0x04102000, 0x04002008, 0x04102008,
1766
+ 0x04002200, 0x04102200, 0x04002208, 0x04102208,
1767
+ 0x00000000, 0x00100000, 0x00000008, 0x00100008,
1768
+ 0x00000200, 0x00100200, 0x00000208, 0x00100208,
1769
+ 0x00000000, 0x00100000, 0x00000008, 0x00100008,
1770
+ 0x00000200, 0x00100200, 0x00000208, 0x00100208,
1771
+ 0x04000000, 0x04100000, 0x04000008, 0x04100008,
1772
+ 0x04000200, 0x04100200, 0x04000208, 0x04100208,
1773
+ 0x04000000, 0x04100000, 0x04000008, 0x04100008,
1774
+ 0x04000200, 0x04100200, 0x04000208, 0x04100208,
1775
+ 0x00002000, 0x00102000, 0x00002008, 0x00102008,
1776
+ 0x00002200, 0x00102200, 0x00002208, 0x00102208,
1777
+ 0x00002000, 0x00102000, 0x00002008, 0x00102008,
1778
+ 0x00002200, 0x00102200, 0x00002208, 0x00102208,
1779
+ 0x04002000, 0x04102000, 0x04002008, 0x04102008,
1780
+ 0x04002200, 0x04102200, 0x04002208, 0x04102208,
1781
+ 0x04002000, 0x04102000, 0x04002008, 0x04102008,
1782
+ 0x04002200, 0x04102200, 0x04002208, 0x04102208,
1783
+ 0x00020000, 0x00120000, 0x00020008, 0x00120008,
1784
+ 0x00020200, 0x00120200, 0x00020208, 0x00120208,
1785
+ 0x00020000, 0x00120000, 0x00020008, 0x00120008,
1786
+ 0x00020200, 0x00120200, 0x00020208, 0x00120208,
1787
+ 0x04020000, 0x04120000, 0x04020008, 0x04120008,
1788
+ 0x04020200, 0x04120200, 0x04020208, 0x04120208,
1789
+ 0x04020000, 0x04120000, 0x04020008, 0x04120008,
1790
+ 0x04020200, 0x04120200, 0x04020208, 0x04120208,
1791
+ 0x00022000, 0x00122000, 0x00022008, 0x00122008,
1792
+ 0x00022200, 0x00122200, 0x00022208, 0x00122208,
1793
+ 0x00022000, 0x00122000, 0x00022008, 0x00122008,
1794
+ 0x00022200, 0x00122200, 0x00022208, 0x00122208,
1795
+ 0x04022000, 0x04122000, 0x04022008, 0x04122008,
1796
+ 0x04022200, 0x04122200, 0x04022208, 0x04122208,
1797
+ 0x04022000, 0x04122000, 0x04022008, 0x04122008,
1798
+ 0x04022200, 0x04122200, 0x04022208, 0x04122208,
1799
+ 0x00020000, 0x00120000, 0x00020008, 0x00120008,
1800
+ 0x00020200, 0x00120200, 0x00020208, 0x00120208,
1801
+ 0x00020000, 0x00120000, 0x00020008, 0x00120008,
1802
+ 0x00020200, 0x00120200, 0x00020208, 0x00120208,
1803
+ 0x04020000, 0x04120000, 0x04020008, 0x04120008,
1804
+ 0x04020200, 0x04120200, 0x04020208, 0x04120208,
1805
+ 0x04020000, 0x04120000, 0x04020008, 0x04120008,
1806
+ 0x04020200, 0x04120200, 0x04020208, 0x04120208,
1807
+ 0x00022000, 0x00122000, 0x00022008, 0x00122008,
1808
+ 0x00022200, 0x00122200, 0x00022208, 0x00122208,
1809
+ 0x00022000, 0x00122000, 0x00022008, 0x00122008,
1810
+ 0x00022200, 0x00122200, 0x00022208, 0x00122208,
1811
+ 0x04022000, 0x04122000, 0x04022008, 0x04122008,
1812
+ 0x04022200, 0x04122200, 0x04022208, 0x04122208,
1813
+ 0x04022000, 0x04122000, 0x04022008, 0x04122008,
1814
+ 0x04022200, 0x04122200, 0x04022208, 0x04122208
1815
+ );
1816
+ static $pc2mapd1 = array(
1817
+ 0x00000000, 0x00000001, 0x08000000, 0x08000001,
1818
+ 0x00200000, 0x00200001, 0x08200000, 0x08200001,
1819
+ 0x00000002, 0x00000003, 0x08000002, 0x08000003,
1820
+ 0x00200002, 0x00200003, 0x08200002, 0x08200003
1821
+ );
1822
+ static $pc2mapd2 = array(
1823
+ 0x00000000, 0x00100000, 0x00000800, 0x00100800,
1824
+ 0x00000000, 0x00100000, 0x00000800, 0x00100800,
1825
+ 0x04000000, 0x04100000, 0x04000800, 0x04100800,
1826
+ 0x04000000, 0x04100000, 0x04000800, 0x04100800,
1827
+ 0x00000004, 0x00100004, 0x00000804, 0x00100804,
1828
+ 0x00000004, 0x00100004, 0x00000804, 0x00100804,
1829
+ 0x04000004, 0x04100004, 0x04000804, 0x04100804,
1830
+ 0x04000004, 0x04100004, 0x04000804, 0x04100804,
1831
+ 0x00000000, 0x00100000, 0x00000800, 0x00100800,
1832
+ 0x00000000, 0x00100000, 0x00000800, 0x00100800,
1833
+ 0x04000000, 0x04100000, 0x04000800, 0x04100800,
1834
+ 0x04000000, 0x04100000, 0x04000800, 0x04100800,
1835
+ 0x00000004, 0x00100004, 0x00000804, 0x00100804,
1836
+ 0x00000004, 0x00100004, 0x00000804, 0x00100804,
1837
+ 0x04000004, 0x04100004, 0x04000804, 0x04100804,
1838
+ 0x04000004, 0x04100004, 0x04000804, 0x04100804,
1839
+ 0x00000200, 0x00100200, 0x00000A00, 0x00100A00,
1840
+ 0x00000200, 0x00100200, 0x00000A00, 0x00100A00,
1841
+ 0x04000200, 0x04100200, 0x04000A00, 0x04100A00,
1842
+ 0x04000200, 0x04100200, 0x04000A00, 0x04100A00,
1843
+ 0x00000204, 0x00100204, 0x00000A04, 0x00100A04,
1844
+ 0x00000204, 0x00100204, 0x00000A04, 0x00100A04,
1845
+ 0x04000204, 0x04100204, 0x04000A04, 0x04100A04,
1846
+ 0x04000204, 0x04100204, 0x04000A04, 0x04100A04,
1847
+ 0x00000200, 0x00100200, 0x00000A00, 0x00100A00,
1848
+ 0x00000200, 0x00100200, 0x00000A00, 0x00100A00,
1849
+ 0x04000200, 0x04100200, 0x04000A00, 0x04100A00,
1850
+ 0x04000200, 0x04100200, 0x04000A00, 0x04100A00,
1851
+ 0x00000204, 0x00100204, 0x00000A04, 0x00100A04,
1852
+ 0x00000204, 0x00100204, 0x00000A04, 0x00100A04,
1853
+ 0x04000204, 0x04100204, 0x04000A04, 0x04100A04,
1854
+ 0x04000204, 0x04100204, 0x04000A04, 0x04100A04,
1855
+ 0x00020000, 0x00120000, 0x00020800, 0x00120800,
1856
+ 0x00020000, 0x00120000, 0x00020800, 0x00120800,
1857
+ 0x04020000, 0x04120000, 0x04020800, 0x04120800,
1858
+ 0x04020000, 0x04120000, 0x04020800, 0x04120800,
1859
+ 0x00020004, 0x00120004, 0x00020804, 0x00120804,
1860
+ 0x00020004, 0x00120004, 0x00020804, 0x00120804,
1861
+ 0x04020004, 0x04120004, 0x04020804, 0x04120804,
1862
+ 0x04020004, 0x04120004, 0x04020804, 0x04120804,
1863
+ 0x00020000, 0x00120000, 0x00020800, 0x00120800,
1864
+ 0x00020000, 0x00120000, 0x00020800, 0x00120800,
1865
+ 0x04020000, 0x04120000, 0x04020800, 0x04120800,
1866
+ 0x04020000, 0x04120000, 0x04020800, 0x04120800,
1867
+ 0x00020004, 0x00120004, 0x00020804, 0x00120804,
1868
+ 0x00020004, 0x00120004, 0x00020804, 0x00120804,
1869
+ 0x04020004, 0x04120004, 0x04020804, 0x04120804,
1870
+ 0x04020004, 0x04120004, 0x04020804, 0x04120804,
1871
+ 0x00020200, 0x00120200, 0x00020A00, 0x00120A00,
1872
+ 0x00020200, 0x00120200, 0x00020A00, 0x00120A00,
1873
+ 0x04020200, 0x04120200, 0x04020A00, 0x04120A00,
1874
+ 0x04020200, 0x04120200, 0x04020A00, 0x04120A00,
1875
+ 0x00020204, 0x00120204, 0x00020A04, 0x00120A04,
1876
+ 0x00020204, 0x00120204, 0x00020A04, 0x00120A04,
1877
+ 0x04020204, 0x04120204, 0x04020A04, 0x04120A04,
1878
+ 0x04020204, 0x04120204, 0x04020A04, 0x04120A04,
1879
+ 0x00020200, 0x00120200, 0x00020A00, 0x00120A00,
1880
+ 0x00020200, 0x00120200, 0x00020A00, 0x00120A00,
1881
+ 0x04020200, 0x04120200, 0x04020A00, 0x04120A00,
1882
+ 0x04020200, 0x04120200, 0x04020A00, 0x04120A00,
1883
+ 0x00020204, 0x00120204, 0x00020A04, 0x00120A04,
1884
+ 0x00020204, 0x00120204, 0x00020A04, 0x00120A04,
1885
+ 0x04020204, 0x04120204, 0x04020A04, 0x04120A04,
1886
+ 0x04020204, 0x04120204, 0x04020A04, 0x04120A04
1887
+ );
1888
+ static $pc2mapd3 = array(
1889
+ 0x00000000, 0x00010000, 0x02000000, 0x02010000,
1890
+ 0x00000020, 0x00010020, 0x02000020, 0x02010020,
1891
+ 0x00040000, 0x00050000, 0x02040000, 0x02050000,
1892
+ 0x00040020, 0x00050020, 0x02040020, 0x02050020,
1893
+ 0x00002000, 0x00012000, 0x02002000, 0x02012000,
1894
+ 0x00002020, 0x00012020, 0x02002020, 0x02012020,
1895
+ 0x00042000, 0x00052000, 0x02042000, 0x02052000,
1896
+ 0x00042020, 0x00052020, 0x02042020, 0x02052020,
1897
+ 0x00000000, 0x00010000, 0x02000000, 0x02010000,
1898
+ 0x00000020, 0x00010020, 0x02000020, 0x02010020,
1899
+ 0x00040000, 0x00050000, 0x02040000, 0x02050000,
1900
+ 0x00040020, 0x00050020, 0x02040020, 0x02050020,
1901
+ 0x00002000, 0x00012000, 0x02002000, 0x02012000,
1902
+ 0x00002020, 0x00012020, 0x02002020, 0x02012020,
1903
+ 0x00042000, 0x00052000, 0x02042000, 0x02052000,
1904
+ 0x00042020, 0x00052020, 0x02042020, 0x02052020,
1905
+ 0x00000010, 0x00010010, 0x02000010, 0x02010010,
1906
+ 0x00000030, 0x00010030, 0x02000030, 0x02010030,
1907
+ 0x00040010, 0x00050010, 0x02040010, 0x02050010,
1908
+ 0x00040030, 0x00050030, 0x02040030, 0x02050030,
1909
+ 0x00002010, 0x00012010, 0x02002010, 0x02012010,
1910
+ 0x00002030, 0x00012030, 0x02002030, 0x02012030,
1911
+ 0x00042010, 0x00052010, 0x02042010, 0x02052010,
1912
+ 0x00042030, 0x00052030, 0x02042030, 0x02052030,
1913
+ 0x00000010, 0x00010010, 0x02000010, 0x02010010,
1914
+ 0x00000030, 0x00010030, 0x02000030, 0x02010030,
1915
+ 0x00040010, 0x00050010, 0x02040010, 0x02050010,
1916
+ 0x00040030, 0x00050030, 0x02040030, 0x02050030,
1917
+ 0x00002010, 0x00012010, 0x02002010, 0x02012010,
1918
+ 0x00002030, 0x00012030, 0x02002030, 0x02012030,
1919
+ 0x00042010, 0x00052010, 0x02042010, 0x02052010,
1920
+ 0x00042030, 0x00052030, 0x02042030, 0x02052030,
1921
+ 0x20000000, 0x20010000, 0x22000000, 0x22010000,
1922
+ 0x20000020, 0x20010020, 0x22000020, 0x22010020,
1923
+ 0x20040000, 0x20050000, 0x22040000, 0x22050000,
1924
+ 0x20040020, 0x20050020, 0x22040020, 0x22050020,
1925
+ 0x20002000, 0x20012000, 0x22002000, 0x22012000,
1926
+ 0x20002020, 0x20012020, 0x22002020, 0x22012020,
1927
+ 0x20042000, 0x20052000, 0x22042000, 0x22052000,
1928
+ 0x20042020, 0x20052020, 0x22042020, 0x22052020,
1929
+ 0x20000000, 0x20010000, 0x22000000, 0x22010000,
1930
+ 0x20000020, 0x20010020, 0x22000020, 0x22010020,
1931
+ 0x20040000, 0x20050000, 0x22040000, 0x22050000,
1932
+ 0x20040020, 0x20050020, 0x22040020, 0x22050020,
1933
+ 0x20002000, 0x20012000, 0x22002000, 0x22012000,
1934
+ 0x20002020, 0x20012020, 0x22002020, 0x22012020,
1935
+ 0x20042000, 0x20052000, 0x22042000, 0x22052000,
1936
+ 0x20042020, 0x20052020, 0x22042020, 0x22052020,
1937
+ 0x20000010, 0x20010010, 0x22000010, 0x22010010,
1938
+ 0x20000030, 0x20010030, 0x22000030, 0x22010030,
1939
+ 0x20040010, 0x20050010, 0x22040010, 0x22050010,
1940
+ 0x20040030, 0x20050030, 0x22040030, 0x22050030,
1941
+ 0x20002010, 0x20012010, 0x22002010, 0x22012010,
1942
+ 0x20002030, 0x20012030, 0x22002030, 0x22012030,
1943
+ 0x20042010, 0x20052010, 0x22042010, 0x22052010,
1944
+ 0x20042030, 0x20052030, 0x22042030, 0x22052030,
1945
+ 0x20000010, 0x20010010, 0x22000010, 0x22010010,
1946
+ 0x20000030, 0x20010030, 0x22000030, 0x22010030,
1947
+ 0x20040010, 0x20050010, 0x22040010, 0x22050010,
1948
+ 0x20040030, 0x20050030, 0x22040030, 0x22050030,
1949
+ 0x20002010, 0x20012010, 0x22002010, 0x22012010,
1950
+ 0x20002030, 0x20012030, 0x22002030, 0x22012030,
1951
+ 0x20042010, 0x20052010, 0x22042010, 0x22052010,
1952
+ 0x20042030, 0x20052030, 0x22042030, 0x22052030
1953
+ );
1954
+ static $pc2mapd4 = array(
1955
+ 0x00000000, 0x00000400, 0x01000000, 0x01000400,
1956
+ 0x00000000, 0x00000400, 0x01000000, 0x01000400,
1957
+ 0x00000100, 0x00000500, 0x01000100, 0x01000500,
1958
+ 0x00000100, 0x00000500, 0x01000100, 0x01000500,
1959
+ 0x10000000, 0x10000400, 0x11000000, 0x11000400,
1960
+ 0x10000000, 0x10000400, 0x11000000, 0x11000400,
1961
+ 0x10000100, 0x10000500, 0x11000100, 0x11000500,
1962
+ 0x10000100, 0x10000500, 0x11000100, 0x11000500,
1963
+ 0x00080000, 0x00080400, 0x01080000, 0x01080400,
1964
+ 0x00080000, 0x00080400, 0x01080000, 0x01080400,
1965
+ 0x00080100, 0x00080500, 0x01080100, 0x01080500,
1966
+ 0x00080100, 0x00080500, 0x01080100, 0x01080500,
1967
+ 0x10080000, 0x10080400, 0x11080000, 0x11080400,
1968
+ 0x10080000, 0x10080400, 0x11080000, 0x11080400,
1969
+ 0x10080100, 0x10080500, 0x11080100, 0x11080500,
1970
+ 0x10080100, 0x10080500, 0x11080100, 0x11080500,
1971
+ 0x00000008, 0x00000408, 0x01000008, 0x01000408,
1972
+ 0x00000008, 0x00000408, 0x01000008, 0x01000408,
1973
+ 0x00000108, 0x00000508, 0x01000108, 0x01000508,
1974
+ 0x00000108, 0x00000508, 0x01000108, 0x01000508,
1975
+ 0x10000008, 0x10000408, 0x11000008, 0x11000408,
1976
+ 0x10000008, 0x10000408, 0x11000008, 0x11000408,
1977
+ 0x10000108, 0x10000508, 0x11000108, 0x11000508,
1978
+ 0x10000108, 0x10000508, 0x11000108, 0x11000508,
1979
+ 0x00080008, 0x00080408, 0x01080008, 0x01080408,
1980
+ 0x00080008, 0x00080408, 0x01080008, 0x01080408,
1981
+ 0x00080108, 0x00080508, 0x01080108, 0x01080508,
1982
+ 0x00080108, 0x00080508, 0x01080108, 0x01080508,
1983
+ 0x10080008, 0x10080408, 0x11080008, 0x11080408,
1984
+ 0x10080008, 0x10080408, 0x11080008, 0x11080408,
1985
+ 0x10080108, 0x10080508, 0x11080108, 0x11080508,
1986
+ 0x10080108, 0x10080508, 0x11080108, 0x11080508,
1987
+ 0x00001000, 0x00001400, 0x01001000, 0x01001400,
1988
+ 0x00001000, 0x00001400, 0x01001000, 0x01001400,
1989
+ 0x00001100, 0x00001500, 0x01001100, 0x01001500,
1990
+ 0x00001100, 0x00001500, 0x01001100, 0x01001500,
1991
+ 0x10001000, 0x10001400, 0x11001000, 0x11001400,
1992
+ 0x10001000, 0x10001400, 0x11001000, 0x11001400,
1993
+ 0x10001100, 0x10001500, 0x11001100, 0x11001500,
1994
+ 0x10001100, 0x10001500, 0x11001100, 0x11001500,
1995
+ 0x00081000, 0x00081400, 0x01081000, 0x01081400,
1996
+ 0x00081000, 0x00081400, 0x01081000, 0x01081400,
1997
+ 0x00081100, 0x00081500, 0x01081100, 0x01081500,
1998
+ 0x00081100, 0x00081500, 0x01081100, 0x01081500,
1999
+ 0x10081000, 0x10081400, 0x11081000, 0x11081400,
2000
+ 0x10081000, 0x10081400, 0x11081000, 0x11081400,
2001
+ 0x10081100, 0x10081500, 0x11081100, 0x11081500,
2002
+ 0x10081100, 0x10081500, 0x11081100, 0x11081500,
2003
+ 0x00001008, 0x00001408, 0x01001008, 0x01001408,
2004
+ 0x00001008, 0x00001408, 0x01001008, 0x01001408,
2005
+ 0x00001108, 0x00001508, 0x01001108, 0x01001508,
2006
+ 0x00001108, 0x00001508, 0x01001108, 0x01001508,
2007
+ 0x10001008, 0x10001408, 0x11001008, 0x11001408,
2008
+ 0x10001008, 0x10001408, 0x11001008, 0x11001408,
2009
+ 0x10001108, 0x10001508, 0x11001108, 0x11001508,
2010
+ 0x10001108, 0x10001508, 0x11001108, 0x11001508,
2011
+ 0x00081008, 0x00081408, 0x01081008, 0x01081408,
2012
+ 0x00081008, 0x00081408, 0x01081008, 0x01081408,
2013
+ 0x00081108, 0x00081508, 0x01081108, 0x01081508,
2014
+ 0x00081108, 0x00081508, 0x01081108, 0x01081508,
2015
+ 0x10081008, 0x10081408, 0x11081008, 0x11081408,
2016
+ 0x10081008, 0x10081408, 0x11081008, 0x11081408,
2017
+ 0x10081108, 0x10081508, 0x11081108, 0x11081508,
2018
+ 0x10081108, 0x10081508, 0x11081108, 0x11081508
2019
+ );
2020
+
2021
+ // pad the key and remove extra characters as appropriate.
2022
+ $key = str_pad(substr($key, 0, 8), 8, chr(0));
2023
+
2024
+ // Perform the PC/1 transformation and compute C and D.
2025
+ $t = unpack('Nl/Nr', $key);
2026
+ list($l, $r) = array($t['l'], $t['r']);
2027
+ $key = ($this->shuffle[$pc1map[$r & 0xFF]] & "\x80\x80\x80\x80\x80\x80\x80\x00") |
2028
+ ($this->shuffle[$pc1map[($r >> 8) & 0xFF]] & "\x40\x40\x40\x40\x40\x40\x40\x00") |
2029
+ ($this->shuffle[$pc1map[($r >> 16) & 0xFF]] & "\x20\x20\x20\x20\x20\x20\x20\x00") |
2030
+ ($this->shuffle[$pc1map[($r >> 24) & 0xFF]] & "\x10\x10\x10\x10\x10\x10\x10\x00") |
2031
+ ($this->shuffle[$pc1map[$l & 0xFF]] & "\x08\x08\x08\x08\x08\x08\x08\x00") |
2032
+ ($this->shuffle[$pc1map[($l >> 8) & 0xFF]] & "\x04\x04\x04\x04\x04\x04\x04\x00") |
2033
+ ($this->shuffle[$pc1map[($l >> 16) & 0xFF]] & "\x02\x02\x02\x02\x02\x02\x02\x00") |
2034
+ ($this->shuffle[$pc1map[($l >> 24) & 0xFF]] & "\x01\x01\x01\x01\x01\x01\x01\x00");
2035
+ $key = unpack('Nc/Nd', $key);
2036
+ $c = ($key['c'] >> 4) & 0x0FFFFFFF;
2037
+ $d = (($key['d'] >> 4) & 0x0FFFFFF0) | ($key['c'] & 0x0F);
2038
+
2039
+ $keys = array();
2040
+ for ($i = 0; $i < 16; $i++) {
2041
+ $c <<= $shifts[$i];
2042
+ $c = ($c | ($c >> 28)) & 0x0FFFFFFF;
2043
+ $d <<= $shifts[$i];
2044
+ $d = ($d | ($d >> 28)) & 0x0FFFFFFF;
2045
+
2046
+ // Perform the PC-2 transformation.
2047
+ $cp = $pc2mapc1[$c >> 24] | $pc2mapc2[($c >> 16) & 0xFF] |
2048
+ $pc2mapc3[($c >> 8) & 0xFF] | $pc2mapc4[$c & 0xFF];
2049
+ $dp = $pc2mapd1[$d >> 24] | $pc2mapd2[($d >> 16) & 0xFF] |
2050
+ $pc2mapd3[($d >> 8) & 0xFF] | $pc2mapd4[$d & 0xFF];
2051
+
2052
+ // Reorder: odd bytes/even bytes. Push the result in key schedule.
2053
+ $keys[] = array(
2054
+ ($cp & 0xFF000000) | (($cp << 8) & 0x00FF0000) |
2055
+ (($dp >> 16) & 0x0000FF00) | (($dp >> 8) & 0x000000FF),
2056
+ (($cp << 8) & 0xFF000000) | (($cp << 16) & 0x00FF0000) |
2057
+ (($dp >> 8) & 0x0000FF00) | ($dp & 0x000000FF)
2058
+ );
2059
+ }
2060
+
2061
+ $keys = array(
2062
+ CRYPT_DES_ENCRYPT => $keys,
2063
+ CRYPT_DES_DECRYPT => array_reverse($keys),
2064
+ CRYPT_DES_ENCRYPT_1DIM => array(),
2065
+ CRYPT_DES_DECRYPT_1DIM => array()
2066
+ );
2067
+
2068
+ // Generate 1-dim arrays for inline en/decrypting
2069
+ for ($i = 0; $i < 16; ++$i) {
2070
+ $keys[CRYPT_DES_ENCRYPT_1DIM][] = $keys[CRYPT_DES_ENCRYPT][$i][0];
2071
+ $keys[CRYPT_DES_ENCRYPT_1DIM][] = $keys[CRYPT_DES_ENCRYPT][$i][1];
2072
+ $keys[CRYPT_DES_DECRYPT_1DIM][] = $keys[CRYPT_DES_DECRYPT][$i][0];
2073
+ $keys[CRYPT_DES_DECRYPT_1DIM][] = $keys[CRYPT_DES_DECRYPT][$i][1];
2074
+ }
2075
+
2076
+ return $keys;
2077
+ }
2078
+
2079
+ /**
2080
+ * String Shift
2081
+ *
2082
+ * Inspired by array_shift
2083
+ *
2084
+ * @param String $string
2085
+ * @return String
2086
+ * @access private
2087
+ */
2088
+ function _string_shift(&$string)
2089
+ {
2090
+ $substr = substr($string, 0, 8);
2091
+ $string = substr($string, 8);
2092
+ return $substr;
2093
+ }
2094
+
2095
+ /**
2096
+ * Creates performance-optimized function for de/encrypt(), storing it in $this->inline_crypt
2097
+ *
2098
+ * @param optional Integer $des_rounds (1 = DES[default], 3 = TribleDES)
2099
+ * @access private
2100
+ */
2101
+ function inline_crypt_setup($des_rounds = 1)
2102
+ {
2103
+ $lambda_functions =& Crypt_DES::get_lambda_functions();
2104
+ $block_size = 8;
2105
+ $mode = $this->mode;
2106
+
2107
+ $code_hash = "$mode,$des_rounds";
2108
+
2109
+ if (!isset($lambda_functions[$code_hash])) {
2110
+ // Generating encrypt code:
2111
+ $ki = -1;
2112
+ $init_cryptBlock = '
2113
+ $shuffle = $self->shuffle;
2114
+ $invipmap = $self->invipmap;
2115
+ $ipmap = $self->ipmap;
2116
+ $sbox1 = $self->sbox1;
2117
+ $sbox2 = $self->sbox2;
2118
+ $sbox3 = $self->sbox3;
2119
+ $sbox4 = $self->sbox4;
2120
+ $sbox5 = $self->sbox5;
2121
+ $sbox6 = $self->sbox6;
2122
+ $sbox7 = $self->sbox7;
2123
+ $sbox8 = $self->sbox8;
2124
+ ';
2125
+
2126
+ $_cryptBlock = '$in = unpack("N*", $in);'."\n";
2127
+ // Do the initial IP permutation.
2128
+ $_cryptBlock .= '
2129
+ $l = $in[1];
2130
+ $r = $in[2];
2131
+ $in = unpack("N*",
2132
+ ($shuffle[$ipmap[ $r & 0xFF]] & "\x80\x80\x80\x80\x80\x80\x80\x80") |
2133
+ ($shuffle[$ipmap[($r >> 8) & 0xFF]] & "\x40\x40\x40\x40\x40\x40\x40\x40") |
2134
+ ($shuffle[$ipmap[($r >> 16) & 0xFF]] & "\x20\x20\x20\x20\x20\x20\x20\x20") |
2135
+ ($shuffle[$ipmap[($r >> 24) & 0xFF]] & "\x10\x10\x10\x10\x10\x10\x10\x10") |
2136
+ ($shuffle[$ipmap[ $l & 0xFF]] & "\x08\x08\x08\x08\x08\x08\x08\x08") |
2137
+ ($shuffle[$ipmap[($l >> 8) & 0xFF]] & "\x04\x04\x04\x04\x04\x04\x04\x04") |
2138
+ ($shuffle[$ipmap[($l >> 16) & 0xFF]] & "\x02\x02\x02\x02\x02\x02\x02\x02") |
2139
+ ($shuffle[$ipmap[($l >> 24) & 0xFF]] & "\x01\x01\x01\x01\x01\x01\x01\x01")
2140
+ );
2141
+
2142
+ '.'' /* Extract L0 and R0 */ .'
2143
+ $l = $in[1];
2144
+ $r = $in[2];
2145
+ ';
2146
+
2147
+ $l = 'l';
2148
+ $r = 'r';
2149
+ for ($des_round = 0; $des_round < $des_rounds; ++$des_round) {
2150
+ // Perform the 16 steps.
2151
+ // start of "the Feistel (F) function" - see the following URL:
2152
+ // http://en.wikipedia.org/wiki/Image:Data_Encryption_Standard_InfoBox_Diagram.png
2153
+ // Merge key schedule.
2154
+ for ($i = 0; $i < 8; ++$i) {
2155
+ $_cryptBlock .= '
2156
+ $b1 = (($' . $r . ' >> 3) & 0x1FFFFFFF) ^ ($' . $r . ' << 29) ^ $k_'.(++$ki).';
2157
+ $b2 = (($' . $r . ' >> 31) & 0x00000001) ^ ($' . $r . ' << 1) ^ $k_'.(++$ki).';
2158
+ $' . $l . ' = $sbox1[($b1 >> 24) & 0x3F] ^ $sbox2[($b2 >> 24) & 0x3F] ^
2159
+ $sbox3[($b1 >> 16) & 0x3F] ^ $sbox4[($b2 >> 16) & 0x3F] ^
2160
+ $sbox5[($b1 >> 8) & 0x3F] ^ $sbox6[($b2 >> 8) & 0x3F] ^
2161
+ $sbox7[ $b1 & 0x3F] ^ $sbox8[ $b2 & 0x3F] ^ $' . $l . ';
2162
+
2163
+ $b1 = (($' . $l . ' >> 3) & 0x1FFFFFFF) ^ ($' . $l . ' << 29) ^ $k_'.(++$ki).';
2164
+ $b2 = (($' . $l . ' >> 31) & 0x00000001) ^ ($' . $l . ' << 1) ^ $k_'.(++$ki).';
2165
+ $' . $r . ' = $sbox1[($b1 >> 24) & 0x3F] ^ $sbox2[($b2 >> 24) & 0x3F] ^
2166
+ $sbox3[($b1 >> 16) & 0x3F] ^ $sbox4[($b2 >> 16) & 0x3F] ^
2167
+ $sbox5[($b1 >> 8) & 0x3F] ^ $sbox6[($b2 >> 8) & 0x3F] ^
2168
+ $sbox7[ $b1 & 0x3F] ^ $sbox8[ $b2 & 0x3F] ^ $' . $r . ';
2169
+ ';
2170
+ }
2171
+
2172
+ // Last step should not permute L & R.
2173
+ $t = $l;
2174
+ $l = $r;
2175
+ $r = $t;
2176
+ }
2177
+
2178
+ // Perform the inverse IP permutation.
2179
+ $_cryptBlock .= '$in = (
2180
+ ($shuffle[$invipmap[($' . $r . ' >> 24) & 0xFF]] & "\x80\x80\x80\x80\x80\x80\x80\x80") |
2181
+ ($shuffle[$invipmap[($' . $l . ' >> 24) & 0xFF]] & "\x40\x40\x40\x40\x40\x40\x40\x40") |
2182
+ ($shuffle[$invipmap[($' . $r . ' >> 16) & 0xFF]] & "\x20\x20\x20\x20\x20\x20\x20\x20") |
2183
+ ($shuffle[$invipmap[($' . $l . ' >> 16) & 0xFF]] & "\x10\x10\x10\x10\x10\x10\x10\x10") |
2184
+ ($shuffle[$invipmap[($' . $r . ' >> 8) & 0xFF]] & "\x08\x08\x08\x08\x08\x08\x08\x08") |
2185
+ ($shuffle[$invipmap[($' . $l . ' >> 8) & 0xFF]] & "\x04\x04\x04\x04\x04\x04\x04\x04") |
2186
+ ($shuffle[$invipmap[ $' . $r . ' & 0xFF]] & "\x02\x02\x02\x02\x02\x02\x02\x02") |
2187
+ ($shuffle[$invipmap[ $' . $l . ' & 0xFF]] & "\x01\x01\x01\x01\x01\x01\x01\x01")
2188
+ );
2189
+ ';
2190
+
2191
+ // Generating mode of operation code:
2192
+ switch ($mode) {
2193
+ case CRYPT_DES_MODE_ECB:
2194
+ $encrypt = $init_cryptBlock . '
2195
+ extract($self->keys[CRYPT_DES_ENCRYPT_1DIM], EXTR_PREFIX_ALL, "k");
2196
+ $ciphertext = "";
2197
+ $plaintext_len = strlen($text);
2198
+
2199
+ for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') {
2200
+ $in = substr($text, $i, '.$block_size.');
2201
+ '.$_cryptBlock.'
2202
+ $ciphertext.= $in;
2203
+ }
2204
+
2205
+ return $ciphertext;
2206
+ ';
2207
+
2208
+ $decrypt = $init_cryptBlock . '
2209
+ extract($self->keys[CRYPT_DES_DECRYPT_1DIM], EXTR_PREFIX_ALL, "k");
2210
+ $plaintext = "";
2211
+ $ciphertext_len = strlen($text);
2212
+
2213
+ for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') {
2214
+ $in = substr($text, $i, '.$block_size.');
2215
+ '.$_cryptBlock.'
2216
+ $plaintext.= $in;
2217
+ }
2218
+
2219
+ return $self->_unpad($plaintext);
2220
+ ';
2221
+ break;
2222
+ case CRYPT_DES_MODE_CBC:
2223
+ $encrypt = $init_cryptBlock . '
2224
+ extract($self->keys[CRYPT_DES_ENCRYPT_1DIM], EXTR_PREFIX_ALL, "k");
2225
+ $ciphertext = "";
2226
+ $plaintext_len = strlen($text);
2227
+
2228
+ $in = $self->encryptIV;
2229
+
2230
+ for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') {
2231
+ $in = substr($text, $i, '.$block_size.') ^ $in;
2232
+ '.$_cryptBlock.'
2233
+ $ciphertext.= $in;
2234
+ }
2235
+
2236
+ if ($self->continuousBuffer) {
2237
+ $self->encryptIV = $in;
2238
+ }
2239
+
2240
+ return $ciphertext;
2241
+ ';
2242
+
2243
+ $decrypt = $init_cryptBlock . '
2244
+ extract($self->keys[CRYPT_DES_DECRYPT_1DIM], EXTR_PREFIX_ALL, "k");
2245
+ $plaintext = "";
2246
+ $ciphertext_len = strlen($text);
2247
+
2248
+ $iv = $self->decryptIV;
2249
+
2250
+ for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') {
2251
+ $in = $block = substr($text, $i, '.$block_size.');
2252
+ '.$_cryptBlock.'
2253
+ $plaintext.= $in ^ $iv;
2254
+ $iv = $block;
2255
+ }
2256
+
2257
+ if ($self->continuousBuffer) {
2258
+ $self->decryptIV = $iv;
2259
+ }
2260
+
2261
+ return $self->_unpad($plaintext);
2262
+ ';
2263
+ break;
2264
+ case CRYPT_DES_MODE_CTR:
2265
+ $encrypt = $init_cryptBlock . '
2266
+ extract($self->keys[CRYPT_DES_ENCRYPT_1DIM], EXTR_PREFIX_ALL, "k");
2267
+ $ciphertext = "";
2268
+ $plaintext_len = strlen($text);
2269
+ $xor = $self->encryptIV;
2270
+ $buffer = &$self->enbuffer;
2271
+
2272
+ if (strlen($buffer["encrypted"])) {
2273
+ for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') {
2274
+ $block = substr($text, $i, '.$block_size.');
2275
+ if (strlen($block) > strlen($buffer["encrypted"])) {
2276
+ $in = $self->_generate_xor($xor);
2277
+ '.$_cryptBlock.'
2278
+ $buffer["encrypted"].= $in;
2279
+ }
2280
+ $key = $self->_string_shift($buffer["encrypted"]);
2281
+ $ciphertext.= $block ^ $key;
2282
+ }
2283
+ } else {
2284
+ for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') {
2285
+ $block = substr($text, $i, '.$block_size.');
2286
+ $in = $self->_generate_xor($xor);
2287
+ '.$_cryptBlock.'
2288
+ $key = $in;
2289
+ $ciphertext.= $block ^ $key;
2290
+ }
2291
+ }
2292
+ if ($self->continuousBuffer) {
2293
+ $self->encryptIV = $xor;
2294
+ if ($start = $plaintext_len % '.$block_size.') {
2295
+ $buffer["encrypted"] = substr($key, $start) . $buffer["encrypted"];
2296
+ }
2297
+ }
2298
+
2299
+ return $ciphertext;
2300
+ ';
2301
+
2302
+ $decrypt = $init_cryptBlock . '
2303
+ extract($self->keys[CRYPT_DES_ENCRYPT_1DIM], EXTR_PREFIX_ALL, "k");
2304
+ $plaintext = "";
2305
+ $ciphertext_len = strlen($text);
2306
+ $xor = $self->decryptIV;
2307
+ $buffer = &$self->debuffer;
2308
+
2309
+ if (strlen($buffer["ciphertext"])) {
2310
+ for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') {
2311
+ $block = substr($text, $i, '.$block_size.');
2312
+ if (strlen($block) > strlen($buffer["ciphertext"])) {
2313
+ $in = $self->_generate_xor($xor);
2314
+ '.$_cryptBlock.'
2315
+ $buffer["ciphertext"].= $in;
2316
+ }
2317
+ $key = $self->_string_shift($buffer["ciphertext"]);
2318
+ $plaintext.= $block ^ $key;
2319
+ }
2320
+ } else {
2321
+ for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') {
2322
+ $block = substr($text, $i, '.$block_size.');
2323
+ $in = $self->_generate_xor($xor);
2324
+ '.$_cryptBlock.'
2325
+ $key = $in;
2326
+ $plaintext.= $block ^ $key;
2327
+ }
2328
+ }
2329
+ if ($self->continuousBuffer) {
2330
+ $self->decryptIV = $xor;
2331
+ if ($start = $ciphertext_len % '.$block_size.') {
2332
+ $buffer["ciphertext"] = substr($key, $start) . $buffer["ciphertext"];
2333
+ }
2334
+ }
2335
+
2336
+ return $plaintext;
2337
+ ';
2338
+ break;
2339
+ case CRYPT_DES_MODE_CFB:
2340
+ $encrypt = $init_cryptBlock . '
2341
+ extract($self->keys[CRYPT_DES_ENCRYPT_1DIM], EXTR_PREFIX_ALL, "k");
2342
+ $ciphertext = "";
2343
+ $buffer = &$self->enbuffer;
2344
+
2345
+ if ($self->continuousBuffer) {
2346
+ $iv = &$self->encryptIV;
2347
+ $pos = &$buffer["pos"];
2348
+ } else {
2349
+ $iv = $self->encryptIV;
2350
+ $pos = 0;
2351
+ }
2352
+ $len = strlen($text);
2353
+ $i = 0;
2354
+ if ($pos) {
2355
+ $orig_pos = $pos;
2356
+ $max = '.$block_size.' - $pos;
2357
+ if ($len >= $max) {
2358
+ $i = $max;
2359
+ $len-= $max;
2360
+ $pos = 0;
2361
+ } else {
2362
+ $i = $len;
2363
+ $pos+= $len;
2364
+ $len = 0;
2365
+ }
2366
+ $ciphertext = substr($iv, $orig_pos) ^ $text;
2367
+ $iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
2368
+ }
2369
+ while ($len >= '.$block_size.') {
2370
+ $in = $iv;
2371
+ '.$_cryptBlock.';
2372
+ $iv = $in ^ substr($text, $i, '.$block_size.');
2373
+ $ciphertext.= $iv;
2374
+ $len-= '.$block_size.';
2375
+ $i+= '.$block_size.';
2376
+ }
2377
+ if ($len) {
2378
+ $in = $iv;
2379
+ '.$_cryptBlock.'
2380
+ $iv = $in;
2381
+ $block = $iv ^ substr($text, $i);
2382
+ $iv = substr_replace($iv, $block, 0, $len);
2383
+ $ciphertext.= $block;
2384
+ $pos = $len;
2385
+ }
2386
+ return $ciphertext;
2387
+ ';
2388
+
2389
+ $decrypt = $init_cryptBlock . '
2390
+ extract($self->keys[CRYPT_DES_ENCRYPT_1DIM], EXTR_PREFIX_ALL, "k");
2391
+ $plaintext = "";
2392
+ $buffer = &$self->debuffer;
2393
+
2394
+ if ($self->continuousBuffer) {
2395
+ $iv = &$self->decryptIV;
2396
+ $pos = &$buffer["pos"];
2397
+ } else {
2398
+ $iv = $self->decryptIV;
2399
+ $pos = 0;
2400
+ }
2401
+ $len = strlen($text);
2402
+ $i = 0;
2403
+ if ($pos) {
2404
+ $orig_pos = $pos;
2405
+ $max = '.$block_size.' - $pos;
2406
+ if ($len >= $max) {
2407
+ $i = $max;
2408
+ $len-= $max;
2409
+ $pos = 0;
2410
+ } else {
2411
+ $i = $len;
2412
+ $pos+= $len;
2413
+ $len = 0;
2414
+ }
2415
+ $plaintext = substr($iv, $orig_pos) ^ $text;
2416
+ $iv = substr_replace($iv, substr($text, 0, $i), $orig_pos, $i);
2417
+ }
2418
+ while ($len >= '.$block_size.') {
2419
+ $in = $iv;
2420
+ '.$_cryptBlock.'
2421
+ $iv = $in;
2422
+ $cb = substr($text, $i, '.$block_size.');
2423
+ $plaintext.= $iv ^ $cb;
2424
+ $iv = $cb;
2425
+ $len-= '.$block_size.';
2426
+ $i+= '.$block_size.';
2427
+ }
2428
+ if ($len) {
2429
+ $in = $iv;
2430
+ '.$_cryptBlock.'
2431
+ $iv = $in;
2432
+ $plaintext.= $iv ^ substr($text, $i);
2433
+ $iv = substr_replace($iv, substr($text, $i), 0, $len);
2434
+ $pos = $len;
2435
+ }
2436
+
2437
+ return $plaintext;
2438
+ ';
2439
+ break;
2440
+ case CRYPT_DES_MODE_OFB:
2441
+ $encrypt = $init_cryptBlock . '
2442
+ extract($self->keys[CRYPT_DES_ENCRYPT_1DIM], EXTR_PREFIX_ALL, "k");
2443
+ $ciphertext = "";
2444
+ $plaintext_len = strlen($text);
2445
+ $xor = $self->encryptIV;
2446
+ $buffer = &$self->enbuffer;
2447
+
2448
+ if (strlen($buffer["xor"])) {
2449
+ for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') {
2450
+ $block = substr($text, $i, '.$block_size.');
2451
+ if (strlen($block) > strlen($buffer["xor"])) {
2452
+ $in = $xor;
2453
+ '.$_cryptBlock.'
2454
+ $xor = $in;
2455
+ $buffer["xor"].= $xor;
2456
+ }
2457
+ $key = $self->_string_shift($buffer["xor"]);
2458
+ $ciphertext.= $block ^ $key;
2459
+ }
2460
+ } else {
2461
+ for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') {
2462
+ $in = $xor;
2463
+ '.$_cryptBlock.'
2464
+ $xor = $in;
2465
+ $ciphertext.= substr($text, $i, '.$block_size.') ^ $xor;
2466
+ }
2467
+ $key = $xor;
2468
+ }
2469
+ if ($self->continuousBuffer) {
2470
+ $self->encryptIV = $xor;
2471
+ if ($start = $plaintext_len % '.$block_size.') {
2472
+ $buffer["xor"] = substr($key, $start) . $buffer["xor"];
2473
+ }
2474
+ }
2475
+ return $ciphertext;
2476
+ ';
2477
+
2478
+ $decrypt = $init_cryptBlock . '
2479
+ extract($self->keys[CRYPT_DES_ENCRYPT_1DIM], EXTR_PREFIX_ALL, "k");
2480
+ $plaintext = "";
2481
+ $ciphertext_len = strlen($text);
2482
+ $xor = $self->decryptIV;
2483
+ $buffer = &$self->debuffer;
2484
+
2485
+ if (strlen($buffer["xor"])) {
2486
+ for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') {
2487
+ $block = substr($text, $i, '.$block_size.');
2488
+ if (strlen($block) > strlen($buffer["xor"])) {
2489
+ $in = $xor;
2490
+ '.$_cryptBlock.'
2491
+ $xor = $in;
2492
+ $buffer["xor"].= $xor;
2493
+ }
2494
+ $key = $self->_string_shift($buffer["xor"]);
2495
+ $plaintext.= $block ^ $key;
2496
+ }
2497
+ } else {
2498
+ for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') {
2499
+ $in = $xor;
2500
+ '.$_cryptBlock.'
2501
+ $xor = $in;
2502
+ $plaintext.= substr($text, $i, '.$block_size.') ^ $xor;
2503
+ }
2504
+ $key = $xor;
2505
+ }
2506
+ if ($self->continuousBuffer) {
2507
+ $self->decryptIV = $xor;
2508
+ if ($start = $ciphertext_len % '.$block_size.') {
2509
+ $buffer["xor"] = substr($key, $start) . $buffer["xor"];
2510
+ }
2511
+ }
2512
+ return $plaintext;
2513
+ ';
2514
+ break;
2515
+ }
2516
+ $lambda_functions[$code_hash] = create_function('$action, &$self, $text', 'if ($action == "encrypt") { '.$encrypt.' } else { '.$decrypt.' }');
2517
+ }
2518
+ $this->inline_crypt = $lambda_functions[$code_hash];
2519
+ }
2520
+
2521
+ /**
2522
+ * Holds the lambda_functions table (classwide)
2523
+ *
2524
+ * @see inline_crypt_setup()
2525
+ * @return Array
2526
+ * @access private
2527
+ */
2528
+ function &get_lambda_functions()
2529
+ {
2530
+ static $functions = array();
2531
+ return $functions;
2532
+ }
2533
+ }
2534
+
2535
+ // vim: ts=4:sw=4:et:
2536
+ // vim6: fdl=1:
modules/phpseclib/Crypt/Hash.php ADDED
@@ -0,0 +1,823 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3
+
4
+ /**
5
+ * Pure-PHP implementations of keyed-hash message authentication codes (HMACs) and various cryptographic hashing functions.
6
+ *
7
+ * Uses hash() or mhash() if available and an internal implementation, otherwise. Currently supports the following:
8
+ *
9
+ * md2, md5, md5-96, sha1, sha1-96, sha256, sha384, and sha512
10
+ *
11
+ * If {@link Crypt_Hash::setKey() setKey()} is called, {@link Crypt_Hash::hash() hash()} will return the HMAC as opposed to
12
+ * the hash. If no valid algorithm is provided, sha1 will be used.
13
+ *
14
+ * PHP versions 4 and 5
15
+ *
16
+ * {@internal The variable names are the same as those in
17
+ * {@link http://tools.ietf.org/html/rfc2104#section-2 RFC2104}.}}
18
+ *
19
+ * Here's a short example of how to use this library:
20
+ * <code>
21
+ * <?php
22
+ * include('Crypt/Hash.php');
23
+ *
24
+ * $hash = new Crypt_Hash('sha1');
25
+ *
26
+ * $hash->setKey('abcdefg');
27
+ *
28
+ * echo base64_encode($hash->hash('abcdefg'));
29
+ * ?>
30
+ * </code>
31
+ *
32
+ * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
33
+ * of this software and associated documentation files (the "Software"), to deal
34
+ * in the Software without restriction, including without limitation the rights
35
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
36
+ * copies of the Software, and to permit persons to whom the Software is
37
+ * furnished to do so, subject to the following conditions:
38
+ *
39
+ * The above copyright notice and this permission notice shall be included in
40
+ * all copies or substantial portions of the Software.
41
+ *
42
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
43
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
44
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
45
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
46
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
47
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
48
+ * THE SOFTWARE.
49
+ *
50
+ * @category Crypt
51
+ * @package Crypt_Hash
52
+ * @author Jim Wigginton <terrafrost@php.net>
53
+ * @copyright MMVII Jim Wigginton
54
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
55
+ * @link http://phpseclib.sourceforge.net
56
+ */
57
+
58
+ /**#@+
59
+ * @access private
60
+ * @see Crypt_Hash::Crypt_Hash()
61
+ */
62
+ /**
63
+ * Toggles the internal implementation
64
+ */
65
+ define('CRYPT_HASH_MODE_INTERNAL', 1);
66
+ /**
67
+ * Toggles the mhash() implementation, which has been deprecated on PHP 5.3.0+.
68
+ */
69
+ define('CRYPT_HASH_MODE_MHASH', 2);
70
+ /**
71
+ * Toggles the hash() implementation, which works on PHP 5.1.2+.
72
+ */
73
+ define('CRYPT_HASH_MODE_HASH', 3);
74
+ /**#@-*/
75
+
76
+ /**
77
+ * Pure-PHP implementations of keyed-hash message authentication codes (HMACs) and various cryptographic hashing functions.
78
+ *
79
+ * @author Jim Wigginton <terrafrost@php.net>
80
+ * @version 0.1.0
81
+ * @access public
82
+ * @package Crypt_Hash
83
+ */
84
+ class Crypt_Hash {
85
+ /**
86
+ * Byte-length of compression blocks / key (Internal HMAC)
87
+ *
88
+ * @see Crypt_Hash::setAlgorithm()
89
+ * @var Integer
90
+ * @access private
91
+ */
92
+ var $b;
93
+
94
+ /**
95
+ * Byte-length of hash output (Internal HMAC)
96
+ *
97
+ * @see Crypt_Hash::setHash()
98
+ * @var Integer
99
+ * @access private
100
+ */
101
+ var $l = false;
102
+
103
+ /**
104
+ * Hash Algorithm
105
+ *
106
+ * @see Crypt_Hash::setHash()
107
+ * @var String
108
+ * @access private
109
+ */
110
+ var $hash;
111
+
112
+ /**
113
+ * Key
114
+ *
115
+ * @see Crypt_Hash::setKey()
116
+ * @var String
117
+ * @access private
118
+ */
119
+ var $key = false;
120
+
121
+ /**
122
+ * Outer XOR (Internal HMAC)
123
+ *
124
+ * @see Crypt_Hash::setKey()
125
+ * @var String
126
+ * @access private
127
+ */
128
+ var $opad;
129
+
130
+ /**
131
+ * Inner XOR (Internal HMAC)
132
+ *
133
+ * @see Crypt_Hash::setKey()
134
+ * @var String
135
+ * @access private
136
+ */
137
+ var $ipad;
138
+
139
+ /**
140
+ * Default Constructor.
141
+ *
142
+ * @param optional String $hash
143
+ * @return Crypt_Hash
144
+ * @access public
145
+ */
146
+ function Crypt_Hash($hash = 'sha1')
147
+ {
148
+ if ( !defined('CRYPT_HASH_MODE') ) {
149
+ switch (true) {
150
+ case extension_loaded('hash'):
151
+ define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_HASH);
152
+ break;
153
+ case extension_loaded('mhash'):
154
+ define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_MHASH);
155
+ break;
156
+ default:
157
+ define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_INTERNAL);
158
+ }
159
+ }
160
+
161
+ $this->setHash($hash);
162
+ }
163
+
164
+ /**
165
+ * Sets the key for HMACs
166
+ *
167
+ * Keys can be of any length.
168
+ *
169
+ * @access public
170
+ * @param optional String $key
171
+ */
172
+ function setKey($key = false)
173
+ {
174
+ $this->key = $key;
175
+ }
176
+
177
+ /**
178
+ * Sets the hash function.
179
+ *
180
+ * @access public
181
+ * @param String $hash
182
+ */
183
+ function setHash($hash)
184
+ {
185
+ $hash = strtolower($hash);
186
+ switch ($hash) {
187
+ case 'md5-96':
188
+ case 'sha1-96':
189
+ $this->l = 12; // 96 / 8 = 12
190
+ break;
191
+ case 'md2':
192
+ case 'md5':
193
+ $this->l = 16;
194
+ break;
195
+ case 'sha1':
196
+ $this->l = 20;
197
+ break;
198
+ case 'sha256':
199
+ $this->l = 32;
200
+ break;
201
+ case 'sha384':
202
+ $this->l = 48;
203
+ break;
204
+ case 'sha512':
205
+ $this->l = 64;
206
+ }
207
+
208
+ switch ($hash) {
209
+ case 'md2':
210
+ $mode = CRYPT_HASH_MODE == CRYPT_HASH_MODE_HASH && in_array('md2', hash_algos()) ?
211
+ CRYPT_HASH_MODE_HASH : CRYPT_HASH_MODE_INTERNAL;
212
+ break;
213
+ case 'sha384':
214
+ case 'sha512':
215
+ $mode = CRYPT_HASH_MODE == CRYPT_HASH_MODE_MHASH ? CRYPT_HASH_MODE_INTERNAL : CRYPT_HASH_MODE;
216
+ break;
217
+ default:
218
+ $mode = CRYPT_HASH_MODE;
219
+ }
220
+
221
+ switch ( $mode ) {
222
+ case CRYPT_HASH_MODE_MHASH:
223
+ switch ($hash) {
224
+ case 'md5':
225
+ case 'md5-96':
226
+ $this->hash = MHASH_MD5;
227
+ break;
228
+ case 'sha256':
229
+ $this->hash = MHASH_SHA256;
230
+ break;
231
+ case 'sha1':
232
+ case 'sha1-96':
233
+ default:
234
+ $this->hash = MHASH_SHA1;
235
+ }
236
+ return;
237
+ case CRYPT_HASH_MODE_HASH:
238
+ switch ($hash) {
239
+ case 'md5':
240
+ case 'md5-96':
241
+ $this->hash = 'md5';
242
+ return;
243
+ case 'md2':
244
+ case 'sha256':
245
+ case 'sha384':
246
+ case 'sha512':
247
+ $this->hash = $hash;
248
+ return;
249
+ case 'sha1':
250
+ case 'sha1-96':
251
+ default:
252
+ $this->hash = 'sha1';
253
+ }
254
+ return;
255
+ }
256
+
257
+ switch ($hash) {
258
+ case 'md2':
259
+ $this->b = 16;
260
+ $this->hash = array($this, '_md2');
261
+ break;
262
+ case 'md5':
263
+ case 'md5-96':
264
+ $this->b = 64;
265
+ $this->hash = array($this, '_md5');
266
+ break;
267
+ case 'sha256':
268
+ $this->b = 64;
269
+ $this->hash = array($this, '_sha256');
270
+ break;
271
+ case 'sha384':
272
+ case 'sha512':
273
+ $this->b = 128;
274
+ $this->hash = array($this, '_sha512');
275
+ break;
276
+ case 'sha1':
277
+ case 'sha1-96':
278
+ default:
279
+ $this->b = 64;
280
+ $this->hash = array($this, '_sha1');
281
+ }
282
+
283
+ $this->ipad = str_repeat(chr(0x36), $this->b);
284
+ $this->opad = str_repeat(chr(0x5C), $this->b);
285
+ }
286
+
287
+ /**
288
+ * Compute the HMAC.
289
+ *
290
+ * @access public
291
+ * @param String $text
292
+ * @return String
293
+ */
294
+ function hash($text)
295
+ {
296
+ $mode = is_array($this->hash) ? CRYPT_HASH_MODE_INTERNAL : CRYPT_HASH_MODE;
297
+
298
+ if (!empty($this->key) || is_string($this->key)) {
299
+ switch ( $mode ) {
300
+ case CRYPT_HASH_MODE_MHASH:
301
+ $output = mhash($this->hash, $text, $this->key);
302
+ break;
303
+ case CRYPT_HASH_MODE_HASH:
304
+ $output = hash_hmac($this->hash, $text, $this->key, true);
305
+ break;
306
+ case CRYPT_HASH_MODE_INTERNAL:
307
+ /* "Applications that use keys longer than B bytes will first hash the key using H and then use the
308
+ resultant L byte string as the actual key to HMAC."
309
+
310
+ -- http://tools.ietf.org/html/rfc2104#section-2 */
311
+ $key = strlen($this->key) > $this->b ? call_user_func($this->hash, $this->key) : $this->key;
312
+
313
+ $key = str_pad($key, $this->b, chr(0)); // step 1
314
+ $temp = $this->ipad ^ $key; // step 2
315
+ $temp .= $text; // step 3
316
+ $temp = call_user_func($this->hash, $temp); // step 4
317
+ $output = $this->opad ^ $key; // step 5
318
+ $output.= $temp; // step 6
319
+ $output = call_user_func($this->hash, $output); // step 7
320
+ }
321
+ } else {
322
+ switch ( $mode ) {
323
+ case CRYPT_HASH_MODE_MHASH:
324
+ $output = mhash($this->hash, $text);
325
+ break;
326
+ case CRYPT_HASH_MODE_HASH:
327
+ $output = hash($this->hash, $text, true);
328
+ break;
329
+ case CRYPT_HASH_MODE_INTERNAL:
330
+ $output = call_user_func($this->hash, $text);
331
+ }
332
+ }
333
+
334
+ return substr($output, 0, $this->l);
335
+ }
336
+
337
+ /**
338
+ * Returns the hash length (in bytes)
339
+ *
340
+ * @access public
341
+ * @return Integer
342
+ */
343
+ function getLength()
344
+ {
345
+ return $this->l;
346
+ }
347
+
348
+ /**
349
+ * Wrapper for MD5
350
+ *
351
+ * @access private
352
+ * @param String $m
353
+ */
354
+ function _md5($m)
355
+ {
356
+ return pack('H*', md5($m));
357
+ }
358
+
359
+ /**
360
+ * Wrapper for SHA1
361
+ *
362
+ * @access private
363
+ * @param String $m
364
+ */
365
+ function _sha1($m)
366
+ {
367
+ return pack('H*', sha1($m));
368
+ }
369
+
370
+ /**
371
+ * Pure-PHP implementation of MD2
372
+ *
373
+ * See {@link http://tools.ietf.org/html/rfc1319 RFC1319}.
374
+ *
375
+ * @access private
376
+ * @param String $m
377
+ */
378
+ function _md2($m)
379
+ {
380
+ static $s = array(
381
+ 41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6,
382
+ 19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188,
383
+ 76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24,
384
+ 138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251,
385
+ 245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63,
386
+ 148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50,
387
+ 39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165,
388
+ 181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210,
389
+ 150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157,
390
+ 112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27,
391
+ 96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15,
392
+ 85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197,
393
+ 234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65,
394
+ 129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123,
395
+ 8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233,
396
+ 203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228,
397
+ 166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237,
398
+ 31, 26, 219, 153, 141, 51, 159, 17, 131, 20
399
+ );
400
+
401
+ // Step 1. Append Padding Bytes
402
+ $pad = 16 - (strlen($m) & 0xF);
403
+ $m.= str_repeat(chr($pad), $pad);
404
+
405
+ $length = strlen($m);
406
+
407
+ // Step 2. Append Checksum
408
+ $c = str_repeat(chr(0), 16);
409
+ $l = chr(0);
410
+ for ($i = 0; $i < $length; $i+= 16) {
411
+ for ($j = 0; $j < 16; $j++) {
412
+ // RFC1319 incorrectly states that C[j] should be set to S[c xor L]
413
+ //$c[$j] = chr($s[ord($m[$i + $j] ^ $l)]);
414
+ // per <http://www.rfc-editor.org/errata_search.php?rfc=1319>, however, C[j] should be set to S[c xor L] xor C[j]
415
+ $c[$j] = chr($s[ord($m[$i + $j] ^ $l)] ^ ord($c[$j]));
416
+ $l = $c[$j];
417
+ }
418
+ }
419
+ $m.= $c;
420
+
421
+ $length+= 16;
422
+
423
+ // Step 3. Initialize MD Buffer
424
+ $x = str_repeat(chr(0), 48);
425
+
426
+ // Step 4. Process Message in 16-Byte Blocks
427
+ for ($i = 0; $i < $length; $i+= 16) {
428
+ for ($j = 0; $j < 16; $j++) {
429
+ $x[$j + 16] = $m[$i + $j];
430
+ $x[$j + 32] = $x[$j + 16] ^ $x[$j];
431
+ }
432
+ $t = chr(0);
433
+ for ($j = 0; $j < 18; $j++) {
434
+ for ($k = 0; $k < 48; $k++) {
435
+ $x[$k] = $t = $x[$k] ^ chr($s[ord($t)]);
436
+ //$t = $x[$k] = $x[$k] ^ chr($s[ord($t)]);
437
+ }
438
+ $t = chr(ord($t) + $j);
439
+ }
440
+ }
441
+
442
+ // Step 5. Output
443
+ return substr($x, 0, 16);
444
+ }
445
+
446
+ /**
447
+ * Pure-PHP implementation of SHA256
448
+ *
449
+ * See {@link http://en.wikipedia.org/wiki/SHA_hash_functions#SHA-256_.28a_SHA-2_variant.29_pseudocode SHA-256 (a SHA-2 variant) pseudocode - Wikipedia}.
450
+ *
451
+ * @access private
452
+ * @param String $m
453
+ */
454
+ function _sha256($m)
455
+ {
456
+ if (extension_loaded('suhosin')) {
457
+ return pack('H*', sha256($m));
458
+ }
459
+
460
+ // Initialize variables
461
+ $hash = array(
462
+ 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
463
+ );
464
+ // Initialize table of round constants
465
+ // (first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311)
466
+ static $k = array(
467
+ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
468
+ 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
469
+ 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
470
+ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
471
+ 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
472
+ 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
473
+ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
474
+ 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
475
+ );
476
+
477
+ // Pre-processing
478
+ $length = strlen($m);
479
+ // to round to nearest 56 mod 64, we'll add 64 - (length + (64 - 56)) % 64
480
+ $m.= str_repeat(chr(0), 64 - (($length + 8) & 0x3F));
481
+ $m[$length] = chr(0x80);
482
+ // we don't support hashing strings 512MB long
483
+ $m.= pack('N2', 0, $length << 3);
484
+
485
+ // Process the message in successive 512-bit chunks
486
+ $chunks = str_split($m, 64);
487
+ foreach ($chunks as $chunk) {
488
+ $w = array();
489
+ for ($i = 0; $i < 16; $i++) {
490
+ extract(unpack('Ntemp', $this->_string_shift($chunk, 4)));
491
+ $w[] = $temp;
492
+ }
493
+
494
+ // Extend the sixteen 32-bit words into sixty-four 32-bit words
495
+ for ($i = 16; $i < 64; $i++) {
496
+ $s0 = $this->_rightRotate($w[$i - 15], 7) ^
497
+ $this->_rightRotate($w[$i - 15], 18) ^
498
+ $this->_rightShift( $w[$i - 15], 3);
499
+ $s1 = $this->_rightRotate($w[$i - 2], 17) ^
500
+ $this->_rightRotate($w[$i - 2], 19) ^
501
+ $this->_rightShift( $w[$i - 2], 10);
502
+ $w[$i] = $this->_add($w[$i - 16], $s0, $w[$i - 7], $s1);
503
+
504
+ }
505
+
506
+ // Initialize hash value for this chunk
507
+ list($a, $b, $c, $d, $e, $f, $g, $h) = $hash;
508
+
509
+ // Main loop
510
+ for ($i = 0; $i < 64; $i++) {
511
+ $s0 = $this->_rightRotate($a, 2) ^
512
+ $this->_rightRotate($a, 13) ^
513
+ $this->_rightRotate($a, 22);
514
+ $maj = ($a & $b) ^
515
+ ($a & $c) ^
516
+ ($b & $c);
517
+ $t2 = $this->_add($s0, $maj);
518
+
519
+ $s1 = $this->_rightRotate($e, 6) ^
520
+ $this->_rightRotate($e, 11) ^
521
+ $this->_rightRotate($e, 25);
522
+ $ch = ($e & $f) ^
523
+ ($this->_not($e) & $g);
524
+ $t1 = $this->_add($h, $s1, $ch, $k[$i], $w[$i]);
525
+
526
+ $h = $g;
527
+ $g = $f;
528
+ $f = $e;
529
+ $e = $this->_add($d, $t1);
530
+ $d = $c;
531
+ $c = $b;
532
+ $b = $a;
533
+ $a = $this->_add($t1, $t2);
534
+ }
535
+
536
+ // Add this chunk's hash to result so far
537
+ $hash = array(
538
+ $this->_add($hash[0], $a),
539
+ $this->_add($hash[1], $b),
540
+ $this->_add($hash[2], $c),
541
+ $this->_add($hash[3], $d),
542
+ $this->_add($hash[4], $e),
543
+ $this->_add($hash[5], $f),
544
+ $this->_add($hash[6], $g),
545
+ $this->_add($hash[7], $h)
546
+ );
547
+ }
548
+
549
+ // Produce the final hash value (big-endian)
550
+ return pack('N8', $hash[0], $hash[1], $hash[2], $hash[3], $hash[4], $hash[5], $hash[6], $hash[7]);
551
+ }
552
+
553
+ /**
554
+ * Pure-PHP implementation of SHA384 and SHA512
555
+ *
556
+ * @access private
557
+ * @param String $m
558
+ */
559
+ function _sha512($m)
560
+ {
561
+ if (!class_exists('Math_BigInteger')) {
562
+ require_once('Math/BigInteger.php');
563
+ }
564
+
565
+ static $init384, $init512, $k;
566
+
567
+ if (!isset($k)) {
568
+ // Initialize variables
569
+ $init384 = array( // initial values for SHA384
570
+ 'cbbb9d5dc1059ed8', '629a292a367cd507', '9159015a3070dd17', '152fecd8f70e5939',
571
+ '67332667ffc00b31', '8eb44a8768581511', 'db0c2e0d64f98fa7', '47b5481dbefa4fa4'
572
+ );
573
+ $init512 = array( // initial values for SHA512
574
+ '6a09e667f3bcc908', 'bb67ae8584caa73b', '3c6ef372fe94f82b', 'a54ff53a5f1d36f1',
575
+ '510e527fade682d1', '9b05688c2b3e6c1f', '1f83d9abfb41bd6b', '5be0cd19137e2179'
576
+ );
577
+
578
+ for ($i = 0; $i < 8; $i++) {
579
+ $init384[$i] = new Math_BigInteger($init384[$i], 16);
580
+ $init384[$i]->setPrecision(64);
581
+ $init512[$i] = new Math_BigInteger($init512[$i], 16);
582
+ $init512[$i]->setPrecision(64);
583
+ }
584
+
585
+ // Initialize table of round constants
586
+ // (first 64 bits of the fractional parts of the cube roots of the first 80 primes 2..409)
587
+ $k = array(
588
+ '428a2f98d728ae22', '7137449123ef65cd', 'b5c0fbcfec4d3b2f', 'e9b5dba58189dbbc',
589
+ '3956c25bf348b538', '59f111f1b605d019', '923f82a4af194f9b', 'ab1c5ed5da6d8118',
590
+ 'd807aa98a3030242', '12835b0145706fbe', '243185be4ee4b28c', '550c7dc3d5ffb4e2',
591
+ '72be5d74f27b896f', '80deb1fe3b1696b1', '9bdc06a725c71235', 'c19bf174cf692694',
592
+ 'e49b69c19ef14ad2', 'efbe4786384f25e3', '0fc19dc68b8cd5b5', '240ca1cc77ac9c65',
593
+ '2de92c6f592b0275', '4a7484aa6ea6e483', '5cb0a9dcbd41fbd4', '76f988da831153b5',
594
+ '983e5152ee66dfab', 'a831c66d2db43210', 'b00327c898fb213f', 'bf597fc7beef0ee4',
595
+ 'c6e00bf33da88fc2', 'd5a79147930aa725', '06ca6351e003826f', '142929670a0e6e70',
596
+ '27b70a8546d22ffc', '2e1b21385c26c926', '4d2c6dfc5ac42aed', '53380d139d95b3df',
597
+ '650a73548baf63de', '766a0abb3c77b2a8', '81c2c92e47edaee6', '92722c851482353b',
598
+ 'a2bfe8a14cf10364', 'a81a664bbc423001', 'c24b8b70d0f89791', 'c76c51a30654be30',
599
+ 'd192e819d6ef5218', 'd69906245565a910', 'f40e35855771202a', '106aa07032bbd1b8',
600
+ '19a4c116b8d2d0c8', '1e376c085141ab53', '2748774cdf8eeb99', '34b0bcb5e19b48a8',
601
+ '391c0cb3c5c95a63', '4ed8aa4ae3418acb', '5b9cca4f7763e373', '682e6ff3d6b2b8a3',
602
+ '748f82ee5defb2fc', '78a5636f43172f60', '84c87814a1f0ab72', '8cc702081a6439ec',
603
+ '90befffa23631e28', 'a4506cebde82bde9', 'bef9a3f7b2c67915', 'c67178f2e372532b',
604
+ 'ca273eceea26619c', 'd186b8c721c0c207', 'eada7dd6cde0eb1e', 'f57d4f7fee6ed178',
605
+ '06f067aa72176fba', '0a637dc5a2c898a6', '113f9804bef90dae', '1b710b35131c471b',
606
+ '28db77f523047d84', '32caab7b40c72493', '3c9ebe0a15c9bebc', '431d67c49c100d4c',
607
+ '4cc5d4becb3e42b6', '597f299cfc657e2a', '5fcb6fab3ad6faec', '6c44198c4a475817'
608
+ );
609
+
610
+ for ($i = 0; $i < 80; $i++) {
611
+ $k[$i] = new Math_BigInteger($k[$i], 16);
612
+ }
613
+ }
614
+
615
+ $hash = $this->l == 48 ? $init384 : $init512;
616
+
617
+ // Pre-processing
618
+ $length = strlen($m);
619
+ // to round to nearest 112 mod 128, we'll add 128 - (length + (128 - 112)) % 128
620
+ $m.= str_repeat(chr(0), 128 - (($length + 16) & 0x7F));
621
+ $m[$length] = chr(0x80);
622
+ // we don't support hashing strings 512MB long
623
+ $m.= pack('N4', 0, 0, 0, $length << 3);
624
+
625
+ // Process the message in successive 1024-bit chunks
626
+ $chunks = str_split($m, 128);
627
+ foreach ($chunks as $chunk) {
628
+ $w = array();
629
+ for ($i = 0; $i < 16; $i++) {
630
+ $temp = new Math_BigInteger($this->_string_shift($chunk, 8), 256);
631
+ $temp->setPrecision(64);
632
+ $w[] = $temp;
633
+ }
634
+
635
+ // Extend the sixteen 32-bit words into eighty 32-bit words
636
+ for ($i = 16; $i < 80; $i++) {
637
+ $temp = array(
638
+ $w[$i - 15]->bitwise_rightRotate(1),
639
+ $w[$i - 15]->bitwise_rightRotate(8),
640
+ $w[$i - 15]->bitwise_rightShift(7)
641
+ );
642
+ $s0 = $temp[0]->bitwise_xor($temp[1]);
643
+ $s0 = $s0->bitwise_xor($temp[2]);
644
+ $temp = array(
645
+ $w[$i - 2]->bitwise_rightRotate(19),
646
+ $w[$i - 2]->bitwise_rightRotate(61),
647
+ $w[$i - 2]->bitwise_rightShift(6)
648
+ );
649
+ $s1 = $temp[0]->bitwise_xor($temp[1]);
650
+ $s1 = $s1->bitwise_xor($temp[2]);
651
+ $w[$i] = $w[$i - 16]->copy();
652
+ $w[$i] = $w[$i]->add($s0);
653
+ $w[$i] = $w[$i]->add($w[$i - 7]);
654
+ $w[$i] = $w[$i]->add($s1);
655
+ }
656
+
657
+ // Initialize hash value for this chunk
658
+ $a = $hash[0]->copy();
659
+ $b = $hash[1]->copy();
660
+ $c = $hash[2]->copy();
661
+ $d = $hash[3]->copy();
662
+ $e = $hash[4]->copy();
663
+ $f = $hash[5]->copy();
664
+ $g = $hash[6]->copy();
665
+ $h = $hash[7]->copy();
666
+
667
+ // Main loop
668
+ for ($i = 0; $i < 80; $i++) {
669
+ $temp = array(
670
+ $a->bitwise_rightRotate(28),
671
+ $a->bitwise_rightRotate(34),
672
+ $a->bitwise_rightRotate(39)
673
+ );
674
+ $s0 = $temp[0]->bitwise_xor($temp[1]);
675
+ $s0 = $s0->bitwise_xor($temp[2]);
676
+ $temp = array(
677
+ $a->bitwise_and($b),
678
+ $a->bitwise_and($c),
679
+ $b->bitwise_and($c)
680
+ );
681
+ $maj = $temp[0]->bitwise_xor($temp[1]);
682
+ $maj = $maj->bitwise_xor($temp[2]);
683
+ $t2 = $s0->add($maj);
684
+
685
+ $temp = array(
686
+ $e->bitwise_rightRotate(14),
687
+ $e->bitwise_rightRotate(18),
688
+ $e->bitwise_rightRotate(41)
689
+ );
690
+ $s1 = $temp[0]->bitwise_xor($temp[1]);
691
+ $s1 = $s1->bitwise_xor($temp[2]);
692
+ $temp = array(
693
+ $e->bitwise_and($f),
694
+ $g->bitwise_and($e->bitwise_not())
695
+ );
696
+ $ch = $temp[0]->bitwise_xor($temp[1]);
697
+ $t1 = $h->add($s1);
698
+ $t1 = $t1->add($ch);
699
+ $t1 = $t1->add($k[$i]);
700
+ $t1 = $t1->add($w[$i]);
701
+
702
+ $h = $g->copy();
703
+ $g = $f->copy();
704
+ $f = $e->copy();
705
+ $e = $d->add($t1);
706
+ $d = $c->copy();
707
+ $c = $b->copy();
708
+ $b = $a->copy();
709
+ $a = $t1->add($t2);
710
+ }
711
+
712
+ // Add this chunk's hash to result so far
713
+ $hash = array(
714
+ $hash[0]->add($a),
715
+ $hash[1]->add($b),
716
+ $hash[2]->add($c),
717
+ $hash[3]->add($d),
718
+ $hash[4]->add($e),
719
+ $hash[5]->add($f),
720
+ $hash[6]->add($g),
721
+ $hash[7]->add($h)
722
+ );
723
+ }
724
+
725
+ // Produce the final hash value (big-endian)
726
+ // (Crypt_Hash::hash() trims the output for hashes but not for HMACs. as such, we trim the output here)
727
+ $temp = $hash[0]->toBytes() . $hash[1]->toBytes() . $hash[2]->toBytes() . $hash[3]->toBytes() .
728
+ $hash[4]->toBytes() . $hash[5]->toBytes();
729
+ if ($this->l != 48) {
730
+ $temp.= $hash[6]->toBytes() . $hash[7]->toBytes();
731
+ }
732
+
733
+ return $temp;
734
+ }
735
+
736
+ /**
737
+ * Right Rotate
738
+ *
739
+ * @access private
740
+ * @param Integer $int
741
+ * @param Integer $amt
742
+ * @see _sha256()
743
+ * @return Integer
744
+ */
745
+ function _rightRotate($int, $amt)
746
+ {
747
+ $invamt = 32 - $amt;
748
+ $mask = (1 << $invamt) - 1;
749
+ return (($int << $invamt) & 0xFFFFFFFF) | (($int >> $amt) & $mask);
750
+ }
751
+
752
+ /**
753
+ * Right Shift
754
+ *
755
+ * @access private
756
+ * @param Integer $int
757
+ * @param Integer $amt
758
+ * @see _sha256()
759
+ * @return Integer
760
+ */
761
+ function _rightShift($int, $amt)
762
+ {
763
+ $mask = (1 << (32 - $amt)) - 1;
764
+ return ($int >> $amt) & $mask;
765
+ }
766
+
767
+ /**
768
+ * Not
769
+ *
770
+ * @access private
771
+ * @param Integer $int
772
+ * @see _sha256()
773
+ * @return Integer
774
+ */
775
+ function _not($int)
776
+ {
777
+ return ~$int & 0xFFFFFFFF;
778
+ }
779
+
780
+ /**
781
+ * Add
782
+ *
783
+ * _sha256() adds multiple unsigned 32-bit integers. Since PHP doesn't support unsigned integers and since the
784
+ * possibility of overflow exists, care has to be taken. Math_BigInteger() could be used but this should be faster.
785
+ *
786
+ * @param Integer $...
787
+ * @return Integer
788
+ * @see _sha256()
789
+ * @access private
790
+ */
791
+ function _add()
792
+ {
793
+ static $mod;
794
+ if (!isset($mod)) {
795
+ $mod = pow(2, 32);
796
+ }
797
+
798
+ $result = 0;
799
+ $arguments = func_get_args();
800
+ foreach ($arguments as $argument) {
801
+ $result+= $argument < 0 ? ($argument & 0x7FFFFFFF) + 0x80000000 : $argument;
802
+ }
803
+
804
+ return fmod($result, $mod);
805
+ }
806
+
807
+ /**
808
+ * String Shift
809
+ *
810
+ * Inspired by array_shift
811
+ *
812
+ * @param String $string
813
+ * @param optional Integer $index
814
+ * @return String
815
+ * @access private
816
+ */
817
+ function _string_shift(&$string, $index = 1)
818
+ {
819
+ $substr = substr($string, 0, $index);
820
+ $string = substr($string, $index);
821
+ return $substr;
822
+ }
823
+ }
modules/phpseclib/Crypt/RC4.php ADDED
@@ -0,0 +1,492 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3
+
4
+ /**
5
+ * Pure-PHP implementation of RC4.
6
+ *
7
+ * Uses mcrypt, if available, and an internal implementation, otherwise.
8
+ *
9
+ * PHP versions 4 and 5
10
+ *
11
+ * Useful resources are as follows:
12
+ *
13
+ * - {@link http://www.mozilla.org/projects/security/pki/nss/draft-kaukonen-cipher-arcfour-03.txt ARCFOUR Algorithm}
14
+ * - {@link http://en.wikipedia.org/wiki/RC4 - Wikipedia: RC4}
15
+ *
16
+ * RC4 is also known as ARCFOUR or ARC4. The reason is elaborated upon at Wikipedia. This class is named RC4 and not
17
+ * ARCFOUR or ARC4 because RC4 is how it is referred to in the SSH1 specification.
18
+ *
19
+ * Here's a short example of how to use this library:
20
+ * <code>
21
+ * <?php
22
+ * include('Crypt/RC4.php');
23
+ *
24
+ * $rc4 = new Crypt_RC4();
25
+ *
26
+ * $rc4->setKey('abcdefgh');
27
+ *
28
+ * $size = 10 * 1024;
29
+ * $plaintext = '';
30
+ * for ($i = 0; $i < $size; $i++) {
31
+ * $plaintext.= 'a';
32
+ * }
33
+ *
34
+ * echo $rc4->decrypt($rc4->encrypt($plaintext));
35
+ * ?>
36
+ * </code>
37
+ *
38
+ * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
39
+ * of this software and associated documentation files (the "Software"), to deal
40
+ * in the Software without restriction, including without limitation the rights
41
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
42
+ * copies of the Software, and to permit persons to whom the Software is
43
+ * furnished to do so, subject to the following conditions:
44
+ *
45
+ * The above copyright notice and this permission notice shall be included in
46
+ * all copies or substantial portions of the Software.
47
+ *
48
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
49
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
50
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
51
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
52
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
53
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
54
+ * THE SOFTWARE.
55
+ *
56
+ * @category Crypt
57
+ * @package Crypt_RC4
58
+ * @author Jim Wigginton <terrafrost@php.net>
59
+ * @copyright MMVII Jim Wigginton
60
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
61
+ * @link http://phpseclib.sourceforge.net
62
+ */
63
+
64
+ /**#@+
65
+ * @access private
66
+ * @see Crypt_RC4::Crypt_RC4()
67
+ */
68
+ /**
69
+ * Toggles the internal implementation
70
+ */
71
+ define('CRYPT_RC4_MODE_INTERNAL', 1);
72
+ /**
73
+ * Toggles the mcrypt implementation
74
+ */
75
+ define('CRYPT_RC4_MODE_MCRYPT', 2);
76
+ /**#@-*/
77
+
78
+ /**#@+
79
+ * @access private
80
+ * @see Crypt_RC4::_crypt()
81
+ */
82
+ define('CRYPT_RC4_ENCRYPT', 0);
83
+ define('CRYPT_RC4_DECRYPT', 1);
84
+ /**#@-*/
85
+
86
+ /**
87
+ * Pure-PHP implementation of RC4.
88
+ *
89
+ * @author Jim Wigginton <terrafrost@php.net>
90
+ * @version 0.1.0
91
+ * @access public
92
+ * @package Crypt_RC4
93
+ */
94
+ class Crypt_RC4 {
95
+ /**
96
+ * The Key
97
+ *
98
+ * @see Crypt_RC4::setKey()
99
+ * @var String
100
+ * @access private
101
+ */
102
+ var $key = "\0";
103
+
104
+ /**
105
+ * The Key Stream for encryption
106
+ *
107
+ * If CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT, this will be equal to the mcrypt object
108
+ *
109
+ * @see Crypt_RC4::setKey()
110
+ * @var Array
111
+ * @access private
112
+ */
113
+ var $encryptStream = false;
114
+
115
+ /**
116
+ * The Key Stream for decryption
117
+ *
118
+ * If CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT, this will be equal to the mcrypt object
119
+ *
120
+ * @see Crypt_RC4::setKey()
121
+ * @var Array
122
+ * @access private
123
+ */
124
+ var $decryptStream = false;
125
+
126
+ /**
127
+ * The $i and $j indexes for encryption
128
+ *
129
+ * @see Crypt_RC4::_crypt()
130
+ * @var Integer
131
+ * @access private
132
+ */
133
+ var $encryptIndex = 0;
134
+
135
+ /**
136
+ * The $i and $j indexes for decryption
137
+ *
138
+ * @see Crypt_RC4::_crypt()
139
+ * @var Integer
140
+ * @access private
141
+ */
142
+ var $decryptIndex = 0;
143
+
144
+ /**
145
+ * The Encryption Algorithm
146
+ *
147
+ * Only used if CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT. Only possible values are MCRYPT_RC4 or MCRYPT_ARCFOUR.
148
+ *
149
+ * @see Crypt_RC4::Crypt_RC4()
150
+ * @var Integer
151
+ * @access private
152
+ */
153
+ var $mode;
154
+
155
+ /**
156
+ * Continuous Buffer status
157
+ *
158
+ * @see Crypt_RC4::enableContinuousBuffer()
159
+ * @var Boolean
160
+ * @access private
161
+ */
162
+ var $continuousBuffer = false;
163
+
164
+ /**
165
+ * Default Constructor.
166
+ *
167
+ * Determines whether or not the mcrypt extension should be used.
168
+ *
169
+ * @return Crypt_RC4
170
+ * @access public
171
+ */
172
+ function Crypt_RC4()
173
+ {
174
+ if ( !defined('CRYPT_RC4_MODE') ) {
175
+ switch (true) {
176
+ case extension_loaded('mcrypt') && (defined('MCRYPT_ARCFOUR') || defined('MCRYPT_RC4')) && in_array('arcfour', mcrypt_list_algorithms()):
177
+ define('CRYPT_RC4_MODE', CRYPT_RC4_MODE_MCRYPT);
178
+ break;
179
+ default:
180
+ define('CRYPT_RC4_MODE', CRYPT_RC4_MODE_INTERNAL);
181
+ }
182
+ }
183
+
184
+ switch ( CRYPT_RC4_MODE ) {
185
+ case CRYPT_RC4_MODE_MCRYPT:
186
+ switch (true) {
187
+ case defined('MCRYPT_ARCFOUR'):
188
+ $this->mode = MCRYPT_ARCFOUR;
189
+ break;
190
+ case defined('MCRYPT_RC4');
191
+ $this->mode = MCRYPT_RC4;
192
+ }
193
+ $this->encryptStream = mcrypt_module_open($this->mode, '', MCRYPT_MODE_STREAM, '');
194
+ $this->decryptStream = mcrypt_module_open($this->mode, '', MCRYPT_MODE_STREAM, '');
195
+
196
+ }
197
+ }
198
+
199
+ /**
200
+ * Sets the key.
201
+ *
202
+ * Keys can be between 1 and 256 bytes long. If they are longer then 256 bytes, the first 256 bytes will
203
+ * be used. If no key is explicitly set, it'll be assumed to be a single null byte.
204
+ *
205
+ * @access public
206
+ * @param String $key
207
+ */
208
+ function setKey($key)
209
+ {
210
+ $this->key = $key;
211
+
212
+ if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) {
213
+ mcrypt_generic_init($this->encryptStream, $this->key, '');
214
+ mcrypt_generic_init($this->decryptStream, $this->key, '');
215
+ return;
216
+ }
217
+
218
+ $keyLength = strlen($key);
219
+ $keyStream = array();
220
+ for ($i = 0; $i < 256; $i++) {
221
+ $keyStream[$i] = $i;
222
+ }
223
+ $j = 0;
224
+ for ($i = 0; $i < 256; $i++) {
225
+ $j = ($j + $keyStream[$i] + ord($key[$i % $keyLength])) & 255;
226
+ $temp = $keyStream[$i];
227
+ $keyStream[$i] = $keyStream[$j];
228
+ $keyStream[$j] = $temp;
229
+ }
230
+
231
+ $this->encryptIndex = $this->decryptIndex = array(0, 0);
232
+ $this->encryptStream = $this->decryptStream = $keyStream;
233
+ }
234
+
235
+ /**
236
+ * Sets the password.
237
+ *
238
+ * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows:
239
+ * {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2}:
240
+ * $hash, $salt, $count, $dkLen
241
+ *
242
+ * @param String $password
243
+ * @param optional String $method
244
+ * @access public
245
+ */
246
+ function setPassword($password, $method = 'pbkdf2')
247
+ {
248
+ $key = '';
249
+
250
+ switch ($method) {
251
+ default: // 'pbkdf2'
252
+ list(, , $hash, $salt, $count) = func_get_args();
253
+ if (!isset($hash)) {
254
+ $hash = 'sha1';
255
+ }
256
+ // WPA and WPA2 use the SSID as the salt
257
+ if (!isset($salt)) {
258
+ $salt = 'phpseclib/salt';
259
+ }
260
+ // RFC2898#section-4.2 uses 1,000 iterations by default
261
+ // WPA and WPA2 use 4,096.
262
+ if (!isset($count)) {
263
+ $count = 1000;
264
+ }
265
+ if (!isset($dkLen)) {
266
+ $dkLen = 128;
267
+ }
268
+
269
+ if (!class_exists('Crypt_Hash')) {
270
+ require_once('Crypt/Hash.php');
271
+ }
272
+
273
+ $i = 1;
274
+ while (strlen($key) < $dkLen) {
275
+ //$dk.= $this->_pbkdf($password, $salt, $count, $i++);
276
+ $hmac = new Crypt_Hash();
277
+ $hmac->setHash($hash);
278
+ $hmac->setKey($password);
279
+ $f = $u = $hmac->hash($salt . pack('N', $i++));
280
+ for ($j = 2; $j <= $count; $j++) {
281
+ $u = $hmac->hash($u);
282
+ $f^= $u;
283
+ }
284
+ $key.= $f;
285
+ }
286
+ }
287
+
288
+ $this->setKey(substr($key, 0, $dkLen));
289
+ }
290
+
291
+ /**
292
+ * Dummy function.
293
+ *
294
+ * Some protocols, such as WEP, prepend an "initialization vector" to the key, effectively creating a new key [1].
295
+ * If you need to use an initialization vector in this manner, feel free to prepend it to the key, yourself, before
296
+ * calling setKey().
297
+ *
298
+ * [1] WEP's initialization vectors (IV's) are used in a somewhat insecure way. Since, in that protocol,
299
+ * the IV's are relatively easy to predict, an attack described by
300
+ * {@link http://www.drizzle.com/~aboba/IEEE/rc4_ksaproc.pdf Scott Fluhrer, Itsik Mantin, and Adi Shamir}
301
+ * can be used to quickly guess at the rest of the key. The following links elaborate:
302
+ *
303
+ * {@link http://www.rsa.com/rsalabs/node.asp?id=2009 http://www.rsa.com/rsalabs/node.asp?id=2009}
304
+ * {@link http://en.wikipedia.org/wiki/Related_key_attack http://en.wikipedia.org/wiki/Related_key_attack}
305
+ *
306
+ * @param String $iv
307
+ * @see Crypt_RC4::setKey()
308
+ * @access public
309
+ */
310
+ function setIV($iv)
311
+ {
312
+ }
313
+
314
+ /**
315
+ * Encrypts a message.
316
+ *
317
+ * @see Crypt_RC4::_crypt()
318
+ * @access public
319
+ * @param String $plaintext
320
+ */
321
+ function encrypt($plaintext)
322
+ {
323
+ return $this->_crypt($plaintext, CRYPT_RC4_ENCRYPT);
324
+ }
325
+
326
+ /**
327
+ * Decrypts a message.
328
+ *
329
+ * $this->decrypt($this->encrypt($plaintext)) == $this->encrypt($this->encrypt($plaintext)).
330
+ * Atleast if the continuous buffer is disabled.
331
+ *
332
+ * @see Crypt_RC4::_crypt()
333
+ * @access public
334
+ * @param String $ciphertext
335
+ */
336
+ function decrypt($ciphertext)
337
+ {
338
+ return $this->_crypt($ciphertext, CRYPT_RC4_DECRYPT);
339
+ }
340
+
341
+ /**
342
+ * Encrypts or decrypts a message.
343
+ *
344
+ * @see Crypt_RC4::encrypt()
345
+ * @see Crypt_RC4::decrypt()
346
+ * @access private
347
+ * @param String $text
348
+ * @param Integer $mode
349
+ */
350
+ function _crypt($text, $mode)
351
+ {
352
+ if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) {
353
+ $keyStream = $mode == CRYPT_RC4_ENCRYPT ? 'encryptStream' : 'decryptStream';
354
+
355
+ if (!$this->continuousBuffer) {
356
+ mcrypt_generic_init($this->$keyStream, $this->key, '');
357
+ }
358
+
359
+ return mcrypt_generic($this->$keyStream, $text);
360
+ }
361
+
362
+ if ($this->encryptStream === false) {
363
+ $this->setKey($this->key);
364
+ }
365
+
366
+ switch ($mode) {
367
+ case CRYPT_RC4_ENCRYPT:
368
+ $keyStream = $this->encryptStream;
369
+ list($i, $j) = $this->encryptIndex;
370
+ break;
371
+ case CRYPT_RC4_DECRYPT:
372
+ $keyStream = $this->decryptStream;
373
+ list($i, $j) = $this->decryptIndex;
374
+ }
375
+
376
+ $newText = '';
377
+ for ($k = 0; $k < strlen($text); $k++) {
378
+ $i = ($i + 1) & 255;
379
+ $j = ($j + $keyStream[$i]) & 255;
380
+ $temp = $keyStream[$i];
381
+ $keyStream[$i] = $keyStream[$j];
382
+ $keyStream[$j] = $temp;
383
+ $temp = $keyStream[($keyStream[$i] + $keyStream[$j]) & 255];
384
+ $newText.= chr(ord($text[$k]) ^ $temp);
385
+ }
386
+
387
+ if ($this->continuousBuffer) {
388
+ switch ($mode) {
389
+ case CRYPT_RC4_ENCRYPT:
390
+ $this->encryptStream = $keyStream;
391
+ $this->encryptIndex = array($i, $j);
392
+ break;
393
+ case CRYPT_RC4_DECRYPT:
394
+ $this->decryptStream = $keyStream;
395
+ $this->decryptIndex = array($i, $j);
396
+ }
397
+ }
398
+
399
+ return $newText;
400
+ }
401
+
402
+ /**
403
+ * Treat consecutive "packets" as if they are a continuous buffer.
404
+ *
405
+ * Say you have a 16-byte plaintext $plaintext. Using the default behavior, the two following code snippets
406
+ * will yield different outputs:
407
+ *
408
+ * <code>
409
+ * echo $rc4->encrypt(substr($plaintext, 0, 8));
410
+ * echo $rc4->encrypt(substr($plaintext, 8, 8));
411
+ * </code>
412
+ * <code>
413
+ * echo $rc4->encrypt($plaintext);
414
+ * </code>
415
+ *
416
+ * The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates
417
+ * another, as demonstrated with the following:
418
+ *
419
+ * <code>
420
+ * $rc4->encrypt(substr($plaintext, 0, 8));
421
+ * echo $rc4->decrypt($des->encrypt(substr($plaintext, 8, 8)));
422
+ * </code>
423
+ * <code>
424
+ * echo $rc4->decrypt($des->encrypt(substr($plaintext, 8, 8)));
425
+ * </code>
426
+ *
427
+ * With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different
428
+ * outputs. The reason is due to the fact that the initialization vector's change after every encryption /
429
+ * decryption round when the continuous buffer is enabled. When it's disabled, they remain constant.
430
+ *
431
+ * Put another way, when the continuous buffer is enabled, the state of the Crypt_DES() object changes after each
432
+ * encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that
433
+ * continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them),
434
+ * however, they are also less intuitive and more likely to cause you problems.
435
+ *
436
+ * @see Crypt_RC4::disableContinuousBuffer()
437
+ * @access public
438
+ */
439
+ function enableContinuousBuffer()
440
+ {
441
+ if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) {
442
+ mcrypt_generic_init($this->encryptStream, $this->key, '');
443
+ mcrypt_generic_init($this->decryptStream, $this->key, '');
444
+ }
445
+
446
+ $this->continuousBuffer = true;
447
+ }
448
+
449
+ /**
450
+ * Treat consecutive packets as if they are a discontinuous buffer.
451
+ *
452
+ * The default behavior.
453
+ *
454
+ * @see Crypt_RC4::enableContinuousBuffer()
455
+ * @access public
456
+ */
457
+ function disableContinuousBuffer()
458
+ {
459
+ if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_INTERNAL ) {
460
+ $this->encryptIndex = $this->decryptIndex = array(0, 0);
461
+ $this->encryptStream = $this->decryptStream = false;
462
+ }
463
+
464
+ $this->continuousBuffer = false;
465
+ }
466
+
467
+ /**
468
+ * Dummy function.
469
+ *
470
+ * Since RC4 is a stream cipher and not a block cipher, no padding is necessary. The only reason this function is
471
+ * included is so that you can switch between a block cipher and a stream cipher transparently.
472
+ *
473
+ * @see Crypt_RC4::disablePadding()
474
+ * @access public
475
+ */
476
+ function enablePadding()
477
+ {
478
+ }
479
+
480
+ /**
481
+ * Dummy function.
482
+ *
483
+ * @see Crypt_RC4::enablePadding()
484
+ * @access public
485
+ */
486
+ function disablePadding()
487
+ {
488
+ }
489
+ }
490
+
491
+ // vim: ts=4:sw=4:et:
492
+ // vim6: fdl=1:
modules/phpseclib/Crypt/RSA.php ADDED
@@ -0,0 +1,2693 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3
+
4
+ /**
5
+ * Pure-PHP PKCS#1 (v2.1) compliant implementation of RSA.
6
+ *
7
+ * PHP versions 4 and 5
8
+ *
9
+ * Here's an example of how to encrypt and decrypt text with this library:
10
+ * <code>
11
+ * <?php
12
+ * include('Crypt/RSA.php');
13
+ *
14
+ * $rsa = new Crypt_RSA();
15
+ * extract($rsa->createKey());
16
+ *
17
+ * $plaintext = 'terrafrost';
18
+ *
19
+ * $rsa->loadKey($privatekey);
20
+ * $ciphertext = $rsa->encrypt($plaintext);
21
+ *
22
+ * $rsa->loadKey($publickey);
23
+ * echo $rsa->decrypt($ciphertext);
24
+ * ?>
25
+ * </code>
26
+ *
27
+ * Here's an example of how to create signatures and verify signatures with this library:
28
+ * <code>
29
+ * <?php
30
+ * include('Crypt/RSA.php');
31
+ *
32
+ * $rsa = new Crypt_RSA();
33
+ * extract($rsa->createKey());
34
+ *
35
+ * $plaintext = 'terrafrost';
36
+ *
37
+ * $rsa->loadKey($privatekey);
38
+ * $signature = $rsa->sign($plaintext);
39
+ *
40
+ * $rsa->loadKey($publickey);
41
+ * echo $rsa->verify($plaintext, $signature) ? 'verified' : 'unverified';
42
+ * ?>
43
+ * </code>
44
+ *
45
+ * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
46
+ * of this software and associated documentation files (the "Software"), to deal
47
+ * in the Software without restriction, including without limitation the rights
48
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
49
+ * copies of the Software, and to permit persons to whom the Software is
50
+ * furnished to do so, subject to the following conditions:
51
+ *
52
+ * The above copyright notice and this permission notice shall be included in
53
+ * all copies or substantial portions of the Software.
54
+ *
55
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
56
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
57
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
58
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
59
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
60
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
61
+ * THE SOFTWARE.
62
+ *
63
+ * @category Crypt
64
+ * @package Crypt_RSA
65
+ * @author Jim Wigginton <terrafrost@php.net>
66
+ * @copyright MMIX Jim Wigginton
67
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
68
+ * @link http://phpseclib.sourceforge.net
69
+ */
70
+
71
+ /**
72
+ * Include Crypt_Random
73
+ */
74
+ // the class_exists() will only be called if the crypt_random_string function hasn't been defined and
75
+ // will trigger a call to __autoload() if you're wanting to auto-load classes
76
+ // call function_exists() a second time to stop the require_once from being called outside
77
+ // of the auto loader
78
+ if (!function_exists('crypt_random_string')) {
79
+ require_once('Random.php');
80
+ }
81
+
82
+ /**
83
+ * Include Crypt_Hash
84
+ */
85
+ if (!class_exists('Crypt_Hash')) {
86
+ require_once('Hash.php');
87
+ }
88
+
89
+ /**#@+
90
+ * @access public
91
+ * @see Crypt_RSA::encrypt()
92
+ * @see Crypt_RSA::decrypt()
93
+ */
94
+ /**
95
+ * Use {@link http://en.wikipedia.org/wiki/Optimal_Asymmetric_Encryption_Padding Optimal Asymmetric Encryption Padding}
96
+ * (OAEP) for encryption / decryption.
97
+ *
98
+ * Uses sha1 by default.
99
+ *
100
+ * @see Crypt_RSA::setHash()
101
+ * @see Crypt_RSA::setMGFHash()
102
+ */
103
+ define('CRYPT_RSA_ENCRYPTION_OAEP', 1);
104
+ /**
105
+ * Use PKCS#1 padding.
106
+ *
107
+ * Although CRYPT_RSA_ENCRYPTION_OAEP offers more security, including PKCS#1 padding is necessary for purposes of backwards
108
+ * compatability with protocols (like SSH-1) written before OAEP's introduction.
109
+ */
110
+ define('CRYPT_RSA_ENCRYPTION_PKCS1', 2);
111
+ /**#@-*/
112
+
113
+ /**#@+
114
+ * @access public
115
+ * @see Crypt_RSA::sign()
116
+ * @see Crypt_RSA::verify()
117
+ * @see Crypt_RSA::setHash()
118
+ */
119
+ /**
120
+ * Use the Probabilistic Signature Scheme for signing
121
+ *
122
+ * Uses sha1 by default.
123
+ *
124
+ * @see Crypt_RSA::setSaltLength()
125
+ * @see Crypt_RSA::setMGFHash()
126
+ */
127
+ define('CRYPT_RSA_SIGNATURE_PSS', 1);
128
+ /**
129
+ * Use the PKCS#1 scheme by default.
130
+ *
131
+ * Although CRYPT_RSA_SIGNATURE_PSS offers more security, including PKCS#1 signing is necessary for purposes of backwards
132
+ * compatability with protocols (like SSH-2) written before PSS's introduction.
133
+ */
134
+ define('CRYPT_RSA_SIGNATURE_PKCS1', 2);
135
+ /**#@-*/
136
+
137
+ /**#@+
138
+ * @access private
139
+ * @see Crypt_RSA::createKey()
140
+ */
141
+ /**
142
+ * ASN1 Integer
143
+ */
144
+ define('CRYPT_RSA_ASN1_INTEGER', 2);
145
+ /**
146
+ * ASN1 Bit String
147
+ */
148
+ define('CRYPT_RSA_ASN1_BITSTRING', 3);
149
+ /**
150
+ * ASN1 Sequence (with the constucted bit set)
151
+ */
152
+ define('CRYPT_RSA_ASN1_SEQUENCE', 48);
153
+ /**#@-*/
154
+
155
+ /**#@+
156
+ * @access private
157
+ * @see Crypt_RSA::Crypt_RSA()
158
+ */
159
+ /**
160
+ * To use the pure-PHP implementation
161
+ */
162
+ define('CRYPT_RSA_MODE_INTERNAL', 1);
163
+ /**
164
+ * To use the OpenSSL library
165
+ *
166
+ * (if enabled; otherwise, the internal implementation will be used)
167
+ */
168
+ define('CRYPT_RSA_MODE_OPENSSL', 2);
169
+ /**#@-*/
170
+
171
+ /**
172
+ * Default openSSL configuration file.
173
+ */
174
+ define('CRYPT_RSA_OPENSSL_CONFIG', dirname(__FILE__) . '/../openssl.cnf');
175
+
176
+
177
+ /**#@+
178
+ * @access public
179
+ * @see Crypt_RSA::createKey()
180
+ * @see Crypt_RSA::setPrivateKeyFormat()
181
+ */
182
+ /**
183
+ * PKCS#1 formatted private key
184
+ *
185
+ * Used by OpenSSH
186
+ */
187
+ define('CRYPT_RSA_PRIVATE_FORMAT_PKCS1', 0);
188
+ /**
189
+ * PuTTY formatted private key
190
+ */
191
+ define('CRYPT_RSA_PRIVATE_FORMAT_PUTTY', 1);
192
+ /**
193
+ * XML formatted private key
194
+ */
195
+ define('CRYPT_RSA_PRIVATE_FORMAT_XML', 2);
196
+ /**#@-*/
197
+
198
+ /**#@+
199
+ * @access public
200
+ * @see Crypt_RSA::createKey()
201
+ * @see Crypt_RSA::setPublicKeyFormat()
202
+ */
203
+ /**
204
+ * Raw public key
205
+ *
206
+ * An array containing two Math_BigInteger objects.
207
+ *
208
+ * The exponent can be indexed with any of the following:
209
+ *
210
+ * 0, e, exponent, publicExponent
211
+ *
212
+ * The modulus can be indexed with any of the following:
213
+ *
214
+ * 1, n, modulo, modulus
215
+ */
216
+ define('CRYPT_RSA_PUBLIC_FORMAT_RAW', 3);
217
+ /**
218
+ * PKCS#1 formatted public key (raw)
219
+ *
220
+ * Used by File/X509.php
221
+ */
222
+ define('CRYPT_RSA_PUBLIC_FORMAT_PKCS1_RAW', 4);
223
+ /**
224
+ * XML formatted public key
225
+ */
226
+ define('CRYPT_RSA_PUBLIC_FORMAT_XML', 5);
227
+ /**
228
+ * OpenSSH formatted public key
229
+ *
230
+ * Place in $HOME/.ssh/authorized_keys
231
+ */
232
+ define('CRYPT_RSA_PUBLIC_FORMAT_OPENSSH', 6);
233
+ /**
234
+ * PKCS#1 formatted public key (encapsulated)
235
+ *
236
+ * Used by PHP's openssl_public_encrypt() and openssl's rsautl (when -pubin is set)
237
+ */
238
+ define('CRYPT_RSA_PUBLIC_FORMAT_PKCS1', 7);
239
+ /**#@-*/
240
+
241
+ /**
242
+ * Pure-PHP PKCS#1 compliant implementation of RSA.
243
+ *
244
+ * @author Jim Wigginton <terrafrost@php.net>
245
+ * @version 0.1.0
246
+ * @access public
247
+ * @package Crypt_RSA
248
+ */
249
+ class Crypt_RSA {
250
+ /**
251
+ * Precomputed Zero
252
+ *
253
+ * @var Array
254
+ * @access private
255
+ */
256
+ var $zero;
257
+
258
+ /**
259
+ * Precomputed One
260
+ *
261
+ * @var Array
262
+ * @access private
263
+ */
264
+ var $one;
265
+
266
+ /**
267
+ * Private Key Format
268
+ *
269
+ * @var Integer
270
+ * @access private
271
+ */
272
+ var $privateKeyFormat = CRYPT_RSA_PRIVATE_FORMAT_PKCS1;
273
+
274
+ /**
275
+ * Public Key Format
276
+ *
277
+ * @var Integer
278
+ * @access public
279
+ */
280
+ var $publicKeyFormat = CRYPT_RSA_PUBLIC_FORMAT_PKCS1;
281
+
282
+ /**
283
+ * Modulus (ie. n)
284
+ *
285
+ * @var Math_BigInteger
286
+ * @access private
287
+ */
288
+ var $modulus;
289
+
290
+ /**
291
+ * Modulus length
292
+ *
293
+ * @var Math_BigInteger
294
+ * @access private
295
+ */
296
+ var $k;
297
+
298
+ /**
299
+ * Exponent (ie. e or d)
300
+ *
301
+ * @var Math_BigInteger
302
+ * @access private
303
+ */
304
+ var $exponent;
305
+
306
+ /**
307
+ * Primes for Chinese Remainder Theorem (ie. p and q)
308
+ *
309
+ * @var Array
310
+ * @access private
311
+ */
312
+ var $primes;
313
+
314
+ /**
315
+ * Exponents for Chinese Remainder Theorem (ie. dP and dQ)
316
+ *
317
+ * @var Array
318
+ * @access private
319
+ */
320
+ var $exponents;
321
+
322
+ /**
323
+ * Coefficients for Chinese Remainder Theorem (ie. qInv)
324
+ *
325
+ * @var Array
326
+ * @access private
327
+ */
328
+ var $coefficients;
329
+
330
+ /**
331
+ * Hash name
332
+ *
333
+ * @var String
334
+ * @access private
335
+ */
336
+ var $hashName;
337
+
338
+ /**
339
+ * Hash function
340
+ *
341
+ * @var Crypt_Hash
342
+ * @access private
343
+ */
344
+ var $hash;
345
+
346
+ /**
347
+ * Length of hash function output
348
+ *
349
+ * @var Integer
350
+ * @access private
351
+ */
352
+ var $hLen;
353
+
354
+ /**
355
+ * Length of salt
356
+ *
357
+ * @var Integer
358
+ * @access private
359
+ */
360
+ var $sLen;
361
+
362
+ /**
363
+ * Hash function for the Mask Generation Function
364
+ *
365
+ * @var Crypt_Hash
366
+ * @access private
367
+ */
368
+ var $mgfHash;
369
+
370
+ /**
371
+ * Length of MGF hash function output
372
+ *
373
+ * @var Integer
374
+ * @access private
375
+ */
376
+ var $mgfHLen;
377
+
378
+ /**
379
+ * Encryption mode
380
+ *
381
+ * @var Integer
382
+ * @access private
383
+ */
384
+ var $encryptionMode = CRYPT_RSA_ENCRYPTION_OAEP;
385
+
386
+ /**
387
+ * Signature mode
388
+ *
389
+ * @var Integer
390
+ * @access private
391
+ */
392
+ var $signatureMode = CRYPT_RSA_SIGNATURE_PSS;
393
+
394
+ /**
395
+ * Public Exponent
396
+ *
397
+ * @var Mixed
398
+ * @access private
399
+ */
400
+ var $publicExponent = false;
401
+
402
+ /**
403
+ * Password
404
+ *
405
+ * @var String
406
+ * @access private
407
+ */
408
+ var $password = false;
409
+
410
+ /**
411
+ * Components
412
+ *
413
+ * For use with parsing XML formatted keys. PHP's XML Parser functions use utilized - instead of PHP's DOM functions -
414
+ * because PHP's XML Parser functions work on PHP4 whereas PHP's DOM functions - although surperior - don't.
415
+ *
416
+ * @see Crypt_RSA::_start_element_handler()
417
+ * @var Array
418
+ * @access private
419
+ */
420
+ var $components = array();
421
+
422
+ /**
423
+ * Current String
424
+ *
425
+ * For use with parsing XML formatted keys.
426
+ *
427
+ * @see Crypt_RSA::_character_handler()
428
+ * @see Crypt_RSA::_stop_element_handler()
429
+ * @var Mixed
430
+ * @access private
431
+ */
432
+ var $current;
433
+
434
+ /**
435
+ * OpenSSL configuration file name.
436
+ *
437
+ * Set to NULL to use system configuration file.
438
+ * @see Crypt_RSA::createKey()
439
+ * @var Mixed
440
+ * @Access public
441
+ */
442
+ var $configFile;
443
+
444
+ /**
445
+ * Public key comment field.
446
+ *
447
+ * @var String
448
+ * @access private
449
+ */
450
+ var $comment = 'phpseclib-generated-key';
451
+
452
+ /**
453
+ * The constructor
454
+ *
455
+ * If you want to make use of the openssl extension, you'll need to set the mode manually, yourself. The reason
456
+ * Crypt_RSA doesn't do it is because OpenSSL doesn't fail gracefully. openssl_pkey_new(), in particular, requires
457
+ * openssl.cnf be present somewhere and, unfortunately, the only real way to find out is too late.
458
+ *
459
+ * @return Crypt_RSA
460
+ * @access public
461
+ */
462
+ function Crypt_RSA()
463
+ {
464
+ if (!class_exists('Math_BigInteger')) {
465
+ require_once('Math/BigInteger.php');
466
+ }
467
+
468
+ $this->configFile = CRYPT_RSA_OPENSSL_CONFIG;
469
+
470
+ if ( !defined('CRYPT_RSA_MODE') ) {
471
+ switch (true) {
472
+ case extension_loaded('openssl') && version_compare(PHP_VERSION, '4.2.0', '>=') && file_exists($this->configFile):
473
+ define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_OPENSSL);
474
+ break;
475
+ default:
476
+ define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL);
477
+ }
478
+ }
479
+
480
+ $this->zero = new Math_BigInteger();
481
+ $this->one = new Math_BigInteger(1);
482
+
483
+ $this->hash = new Crypt_Hash('sha1');
484
+ $this->hLen = $this->hash->getLength();
485
+ $this->hashName = 'sha1';
486
+ $this->mgfHash = new Crypt_Hash('sha1');
487
+ $this->mgfHLen = $this->mgfHash->getLength();
488
+ }
489
+
490
+ /**
491
+ * Create public / private key pair
492
+ *
493
+ * Returns an array with the following three elements:
494
+ * - 'privatekey': The private key.
495
+ * - 'publickey': The public key.
496
+ * - 'partialkey': A partially computed key (if the execution time exceeded $timeout).
497
+ * Will need to be passed back to Crypt_RSA::createKey() as the third parameter for further processing.
498
+ *
499
+ * @access public
500
+ * @param optional Integer $bits
501
+ * @param optional Integer $timeout
502
+ * @param optional Math_BigInteger $p
503
+ */
504
+ function createKey($bits = 1024, $timeout = false, $partial = array())
505
+ {
506
+ if (!defined('CRYPT_RSA_EXPONENT')) {
507
+ // http://en.wikipedia.org/wiki/65537_%28number%29
508
+ define('CRYPT_RSA_EXPONENT', '65537');
509
+ }
510
+ // per <http://cseweb.ucsd.edu/~hovav/dist/survey.pdf#page=5>, this number ought not result in primes smaller
511
+ // than 256 bits. as a consequence if the key you're trying to create is 1024 bits and you've set CRYPT_RSA_SMALLEST_PRIME
512
+ // to 384 bits then you're going to get a 384 bit prime and a 640 bit prime (384 + 1024 % 384). at least if
513
+ // CRYPT_RSA_MODE is set to CRYPT_RSA_MODE_INTERNAL. if CRYPT_RSA_MODE is set to CRYPT_RSA_MODE_OPENSSL then
514
+ // CRYPT_RSA_SMALLEST_PRIME is ignored (ie. multi-prime RSA support is more intended as a way to speed up RSA key
515
+ // generation when there's a chance neither gmp nor OpenSSL are installed)
516
+ if (!defined('CRYPT_RSA_SMALLEST_PRIME')) {
517
+ define('CRYPT_RSA_SMALLEST_PRIME', 4096);
518
+ }
519
+
520
+ // OpenSSL uses 65537 as the exponent and requires RSA keys be 384 bits minimum
521
+ if ( CRYPT_RSA_MODE == CRYPT_RSA_MODE_OPENSSL && $bits >= 384 && CRYPT_RSA_EXPONENT == 65537) {
522
+ $config = array();
523
+ if (isset($this->configFile)) {
524
+ $config['config'] = $this->configFile;
525
+ }
526
+ $rsa = openssl_pkey_new(array('private_key_bits' => $bits) + $config);
527
+ openssl_pkey_export($rsa, $privatekey, NULL, $config);
528
+ $publickey = openssl_pkey_get_details($rsa);
529
+ $publickey = $publickey['key'];
530
+
531
+ $privatekey = call_user_func_array(array($this, '_convertPrivateKey'), array_values($this->_parseKey($privatekey, CRYPT_RSA_PRIVATE_FORMAT_PKCS1)));
532
+ $publickey = call_user_func_array(array($this, '_convertPublicKey'), array_values($this->_parseKey($publickey, CRYPT_RSA_PUBLIC_FORMAT_PKCS1)));
533
+
534
+ // clear the buffer of error strings stemming from a minimalistic openssl.cnf
535
+ while (openssl_error_string() !== false);
536
+
537
+ return array(
538
+ 'privatekey' => $privatekey,
539
+ 'publickey' => $publickey,
540
+ 'partialkey' => false
541
+ );
542
+ }
543
+
544
+ static $e;
545
+ if (!isset($e)) {
546
+ $e = new Math_BigInteger(CRYPT_RSA_EXPONENT);
547
+ }
548
+
549
+ extract($this->_generateMinMax($bits));
550
+ $absoluteMin = $min;
551
+ $temp = $bits >> 1; // divide by two to see how many bits P and Q would be
552
+ if ($temp > CRYPT_RSA_SMALLEST_PRIME) {
553
+ $num_primes = floor($bits / CRYPT_RSA_SMALLEST_PRIME);
554
+ $temp = CRYPT_RSA_SMALLEST_PRIME;
555
+ } else {
556
+ $num_primes = 2;
557
+ }
558
+ extract($this->_generateMinMax($temp + $bits % $temp));
559
+ $finalMax = $max;
560
+ extract($this->_generateMinMax($temp));
561
+
562
+ $generator = new Math_BigInteger();
563
+
564
+ $n = $this->one->copy();
565
+ if (!empty($partial)) {
566
+ extract(unserialize($partial));
567
+ } else {
568
+ $exponents = $coefficients = $primes = array();
569
+ $lcm = array(
570
+ 'top' => $this->one->copy(),
571
+ 'bottom' => false
572
+ );
573
+ }
574
+
575
+ $start = time();
576
+ $i0 = count($primes) + 1;
577
+
578
+ do {
579
+ for ($i = $i0; $i <= $num_primes; $i++) {
580
+ if ($timeout !== false) {
581
+ $timeout-= time() - $start;
582
+ $start = time();
583
+ if ($timeout <= 0) {
584
+ return array(
585
+ 'privatekey' => '',
586
+ 'publickey' => '',
587
+ 'partialkey' => serialize(array(
588
+ 'primes' => $primes,
589
+ 'coefficients' => $coefficients,
590
+ 'lcm' => $lcm,
591
+ 'exponents' => $exponents
592
+ ))
593
+ );
594
+ }
595
+ }
596
+
597
+ if ($i == $num_primes) {
598
+ list($min, $temp) = $absoluteMin->divide($n);
599
+ if (!$temp->equals($this->zero)) {
600
+ $min = $min->add($this->one); // ie. ceil()
601
+ }
602
+ $primes[$i] = $generator->randomPrime($min, $finalMax, $timeout);
603
+ } else {
604
+ $primes[$i] = $generator->randomPrime($min, $max, $timeout);
605
+ }
606
+
607
+ if ($primes[$i] === false) { // if we've reached the timeout
608
+ if (count($primes) > 1) {
609
+ $partialkey = '';
610
+ } else {
611
+ array_pop($primes);
612
+ $partialkey = serialize(array(
613
+ 'primes' => $primes,
614
+ 'coefficients' => $coefficients,
615
+ 'lcm' => $lcm,
616
+ 'exponents' => $exponents
617
+ ));
618
+ }
619
+
620
+ return array(
621
+ 'privatekey' => '',
622
+ 'publickey' => '',
623
+ 'partialkey' => $partialkey
624
+ );
625
+ }
626
+
627
+ // the first coefficient is calculated differently from the rest
628
+ // ie. instead of being $primes[1]->modInverse($primes[2]), it's $primes[2]->modInverse($primes[1])
629
+ if ($i > 2) {
630
+ $coefficients[$i] = $n->modInverse($primes[$i]);
631
+ }
632
+
633
+ $n = $n->multiply($primes[$i]);
634
+
635
+ $temp = $primes[$i]->subtract($this->one);
636
+
637
+ // textbook RSA implementations use Euler's totient function instead of the least common multiple.
638
+ // see http://en.wikipedia.org/wiki/Euler%27s_totient_function
639
+ $lcm['top'] = $lcm['top']->multiply($temp);
640
+ $lcm['bottom'] = $lcm['bottom'] === false ? $temp : $lcm['bottom']->gcd($temp);
641
+
642
+ $exponents[$i] = $e->modInverse($temp);
643
+ }
644
+
645
+ list($lcm) = $lcm['top']->divide($lcm['bottom']);
646
+ $gcd = $lcm->gcd($e);
647
+ $i0 = 1;
648
+ } while (!$gcd->equals($this->one));
649
+
650
+ $d = $e->modInverse($lcm);
651
+
652
+ $coefficients[2] = $primes[2]->modInverse($primes[1]);
653
+
654
+ // from <http://tools.ietf.org/html/rfc3447#appendix-A.1.2>:
655
+ // RSAPrivateKey ::= SEQUENCE {
656
+ // version Version,
657
+ // modulus INTEGER, -- n
658
+ // publicExponent INTEGER, -- e
659
+ // privateExponent INTEGER, -- d
660
+ // prime1 INTEGER, -- p
661
+ // prime2 INTEGER, -- q
662
+ // exponent1 INTEGER, -- d mod (p-1)
663
+ // exponent2 INTEGER, -- d mod (q-1)
664
+ // coefficient INTEGER, -- (inverse of q) mod p
665
+ // otherPrimeInfos OtherPrimeInfos OPTIONAL
666
+ // }
667
+
668
+ return array(
669
+ 'privatekey' => $this->_convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients),
670
+ 'publickey' => $this->_convertPublicKey($n, $e),
671
+ 'partialkey' => false
672
+ );
673
+ }
674
+
675
+ /**
676
+ * Convert a private key to the appropriate format.
677
+ *
678
+ * @access private
679
+ * @see setPrivateKeyFormat()
680
+ * @param String $RSAPrivateKey
681
+ * @return String
682
+ */
683
+ function _convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients)
684
+ {
685
+ $num_primes = count($primes);
686
+ $raw = array(
687
+ 'version' => $num_primes == 2 ? chr(0) : chr(1), // two-prime vs. multi
688
+ 'modulus' => $n->toBytes(true),
689
+ 'publicExponent' => $e->toBytes(true),
690
+ 'privateExponent' => $d->toBytes(true),
691
+ 'prime1' => $primes[1]->toBytes(true),
692
+ 'prime2' => $primes[2]->toBytes(true),
693
+ 'exponent1' => $exponents[1]->toBytes(true),
694
+ 'exponent2' => $exponents[2]->toBytes(true),
695
+ 'coefficient' => $coefficients[2]->toBytes(true)
696
+ );
697
+
698
+ // if the format in question does not support multi-prime rsa and multi-prime rsa was used,
699
+ // call _convertPublicKey() instead.
700
+ switch ($this->privateKeyFormat) {
701
+ case CRYPT_RSA_PRIVATE_FORMAT_XML:
702
+ if ($num_primes != 2) {
703
+ return false;
704
+ }
705
+ return "<RSAKeyValue>\r\n" .
706
+ ' <Modulus>' . base64_encode($raw['modulus']) . "</Modulus>\r\n" .
707
+ ' <Exponent>' . base64_encode($raw['publicExponent']) . "</Exponent>\r\n" .
708
+ ' <P>' . base64_encode($raw['prime1']) . "</P>\r\n" .
709
+ ' <Q>' . base64_encode($raw['prime2']) . "</Q>\r\n" .
710
+ ' <DP>' . base64_encode($raw['exponent1']) . "</DP>\r\n" .
711
+ ' <DQ>' . base64_encode($raw['exponent2']) . "</DQ>\r\n" .
712
+ ' <InverseQ>' . base64_encode($raw['coefficient']) . "</InverseQ>\r\n" .
713
+ ' <D>' . base64_encode($raw['privateExponent']) . "</D>\r\n" .
714
+ '</RSAKeyValue>';
715
+ break;
716
+ case CRYPT_RSA_PRIVATE_FORMAT_PUTTY:
717
+ if ($num_primes != 2) {
718
+ return false;
719
+ }
720
+ $key = "PuTTY-User-Key-File-2: ssh-rsa\r\nEncryption: ";
721
+ $encryption = (!empty($this->password) || is_string($this->password)) ? 'aes256-cbc' : 'none';
722
+ $key.= $encryption;
723
+ $key.= "\r\nComment: " . $this->comment . "\r\n";
724
+ $public = pack('Na*Na*Na*',
725
+ strlen('ssh-rsa'), 'ssh-rsa', strlen($raw['publicExponent']), $raw['publicExponent'], strlen($raw['modulus']), $raw['modulus']
726
+ );
727
+ $source = pack('Na*Na*Na*Na*',
728
+ strlen('ssh-rsa'), 'ssh-rsa', strlen($encryption), $encryption,
729
+ strlen($this->comment), $this->comment, strlen($public), $public
730
+ );
731
+ $public = base64_encode($public);
732
+ $key.= "Public-Lines: " . ((strlen($public) + 32) >> 6) . "\r\n";
733
+ $key.= chunk_split($public, 64);
734
+ $private = pack('Na*Na*Na*Na*',
735
+ strlen($raw['privateExponent']), $raw['privateExponent'], strlen($raw['prime1']), $raw['prime1'],
736
+ strlen($raw['prime2']), $raw['prime2'], strlen($raw['coefficient']), $raw['coefficient']
737
+ );
738
+ if (empty($this->password) && !is_string($this->password)) {
739
+ $source.= pack('Na*', strlen($private), $private);
740
+ $hashkey = 'putty-private-key-file-mac-key';
741
+ } else {
742
+ $private.= crypt_random_string(16 - (strlen($private) & 15));
743
+ $source.= pack('Na*', strlen($private), $private);
744
+ if (!class_exists('Crypt_AES')) {
745
+ require_once('Crypt/AES.php');
746
+ }
747
+ $sequence = 0;
748
+ $symkey = '';
749
+ while (strlen($symkey) < 32) {
750
+ $temp = pack('Na*', $sequence++, $this->password);
751
+ $symkey.= pack('H*', sha1($temp));
752
+ }
753
+ $symkey = substr($symkey, 0, 32);
754
+ $crypto = new Crypt_AES();
755
+
756
+ $crypto->setKey($symkey);
757
+ $crypto->disablePadding();
758
+ $private = $crypto->encrypt($private);
759
+ $hashkey = 'putty-private-key-file-mac-key' . $this->password;
760
+ }
761
+
762
+ $private = base64_encode($private);
763
+ $key.= 'Private-Lines: ' . ((strlen($private) + 32) >> 6) . "\r\n";
764
+ $key.= chunk_split($private, 64);
765
+ if (!class_exists('Crypt_Hash')) {
766
+ require_once('Crypt/Hash.php');
767
+ }
768
+ $hash = new Crypt_Hash('sha1');
769
+ $hash->setKey(pack('H*', sha1($hashkey)));
770
+ $key.= 'Private-MAC: ' . bin2hex($hash->hash($source)) . "\r\n";
771
+
772
+ return $key;
773
+ default: // eg. CRYPT_RSA_PRIVATE_FORMAT_PKCS1
774
+ $components = array();
775
+ foreach ($raw as $name => $value) {
776
+ $components[$name] = pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($value)), $value);
777
+ }
778
+
779
+ $RSAPrivateKey = implode('', $components);
780
+
781
+ if ($num_primes > 2) {
782
+ $OtherPrimeInfos = '';
783
+ for ($i = 3; $i <= $num_primes; $i++) {
784
+ // OtherPrimeInfos ::= SEQUENCE SIZE(1..MAX) OF OtherPrimeInfo
785
+ //
786
+ // OtherPrimeInfo ::= SEQUENCE {
787
+ // prime INTEGER, -- ri
788
+ // exponent INTEGER, -- di
789
+ // coefficient INTEGER -- ti
790
+ // }
791
+ $OtherPrimeInfo = pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($primes[$i]->toBytes(true))), $primes[$i]->toBytes(true));
792
+ $OtherPrimeInfo.= pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($exponents[$i]->toBytes(true))), $exponents[$i]->toBytes(true));
793
+ $OtherPrimeInfo.= pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($coefficients[$i]->toBytes(true))), $coefficients[$i]->toBytes(true));
794
+ $OtherPrimeInfos.= pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($OtherPrimeInfo)), $OtherPrimeInfo);
795
+ }
796
+ $RSAPrivateKey.= pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($OtherPrimeInfos)), $OtherPrimeInfos);
797
+ }
798
+
799
+ $RSAPrivateKey = pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);
800
+
801
+ if (!empty($this->password) || is_string($this->password)) {
802
+ $iv = crypt_random_string(8);
803
+ $symkey = pack('H*', md5($this->password . $iv)); // symkey is short for symmetric key
804
+ $symkey.= substr(pack('H*', md5($symkey . $this->password . $iv)), 0, 8);
805
+ if (!class_exists('Crypt_TripleDES')) {
806
+ require_once('Crypt/TripleDES.php');
807
+ }
808
+ $des = new Crypt_TripleDES();
809
+ $des->setKey($symkey);
810
+ $des->setIV($iv);
811
+ $iv = strtoupper(bin2hex($iv));
812
+ $RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" .
813
+ "Proc-Type: 4,ENCRYPTED\r\n" .
814
+ "DEK-Info: DES-EDE3-CBC,$iv\r\n" .
815
+ "\r\n" .
816
+ chunk_split(base64_encode($des->encrypt($RSAPrivateKey)), 64) .
817
+ '-----END RSA PRIVATE KEY-----';
818
+ } else {
819
+ $RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" .
820
+ chunk_split(base64_encode($RSAPrivateKey), 64) .
821
+ '-----END RSA PRIVATE KEY-----';
822
+ }
823
+
824
+ return $RSAPrivateKey;
825
+ }
826
+ }
827
+
828
+ /**
829
+ * Convert a public key to the appropriate format
830
+ *
831
+ * @access private
832
+ * @see setPublicKeyFormat()
833
+ * @param String $RSAPrivateKey
834
+ * @return String
835
+ */
836
+ function _convertPublicKey($n, $e)
837
+ {
838
+ $modulus = $n->toBytes(true);
839
+ $publicExponent = $e->toBytes(true);
840
+
841
+ switch ($this->publicKeyFormat) {
842
+ case CRYPT_RSA_PUBLIC_FORMAT_RAW:
843
+ return array('e' => $e->copy(), 'n' => $n->copy());
844
+ case CRYPT_RSA_PUBLIC_FORMAT_XML:
845
+ return "<RSAKeyValue>\r\n" .
846
+ ' <Modulus>' . base64_encode($modulus) . "</Modulus>\r\n" .
847
+ ' <Exponent>' . base64_encode($publicExponent) . "</Exponent>\r\n" .
848
+ '</RSAKeyValue>';
849
+ break;
850
+ case CRYPT_RSA_PUBLIC_FORMAT_OPENSSH:
851
+ // from <http://tools.ietf.org/html/rfc4253#page-15>:
852
+ // string "ssh-rsa"
853
+ // mpint e
854
+ // mpint n
855
+ $RSAPublicKey = pack('Na*Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($publicExponent), $publicExponent, strlen($modulus), $modulus);
856
+ $RSAPublicKey = 'ssh-rsa ' . base64_encode($RSAPublicKey) . ' ' . $this->comment;
857
+
858
+ return $RSAPublicKey;
859
+ default: // eg. CRYPT_RSA_PUBLIC_FORMAT_PKCS1_RAW or CRYPT_RSA_PUBLIC_FORMAT_PKCS1
860
+ // from <http://tools.ietf.org/html/rfc3447#appendix-A.1.1>:
861
+ // RSAPublicKey ::= SEQUENCE {
862
+ // modulus INTEGER, -- n
863
+ // publicExponent INTEGER -- e
864
+ // }
865
+ $components = array(
866
+ 'modulus' => pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($modulus)), $modulus),
867
+ 'publicExponent' => pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($publicExponent)), $publicExponent)
868
+ );
869
+
870
+ $RSAPublicKey = pack('Ca*a*a*',
871
+ CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($components['modulus']) + strlen($components['publicExponent'])),
872
+ $components['modulus'], $components['publicExponent']
873
+ );
874
+
875
+ if ($this->publicKeyFormat == CRYPT_RSA_PUBLIC_FORMAT_PKCS1) {
876
+ // sequence(oid(1.2.840.113549.1.1.1), null)) = rsaEncryption.
877
+ $rsaOID = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA
878
+ $RSAPublicKey = chr(0) . $RSAPublicKey;
879
+ $RSAPublicKey = chr(3) . $this->_encodeLength(strlen($RSAPublicKey)) . $RSAPublicKey;
880
+
881
+ $RSAPublicKey = pack('Ca*a*',
882
+ CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($rsaOID . $RSAPublicKey)), $rsaOID . $RSAPublicKey
883
+ );
884
+ }
885
+
886
+ $RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" .
887
+ chunk_split(base64_encode($RSAPublicKey), 64) .
888
+ '-----END PUBLIC KEY-----';
889
+
890
+ return $RSAPublicKey;
891
+ }
892
+ }
893
+
894
+ /**
895
+ * Break a public or private key down into its constituant components
896
+ *
897
+ * @access private
898
+ * @see _convertPublicKey()
899
+ * @see _convertPrivateKey()
900
+ * @param String $key
901
+ * @param Integer $type
902
+ * @return Array
903
+ */
904
+ function _parseKey($key, $type)
905
+ {
906
+ if ($type != CRYPT_RSA_PUBLIC_FORMAT_RAW && !is_string($key)) {
907
+ return false;
908
+ }
909
+
910
+ switch ($type) {
911
+ case CRYPT_RSA_PUBLIC_FORMAT_RAW:
912
+ if (!is_array($key)) {
913
+ return false;
914
+ }
915
+ $components = array();
916
+ switch (true) {
917
+ case isset($key['e']):
918
+ $components['publicExponent'] = $key['e']->copy();
919
+ break;
920
+ case isset($key['exponent']):
921
+ $components['publicExponent'] = $key['exponent']->copy();
922
+ break;
923
+ case isset($key['publicExponent']):
924
+ $components['publicExponent'] = $key['publicExponent']->copy();
925
+ break;
926
+ case isset($key[0]):
927
+ $components['publicExponent'] = $key[0]->copy();
928
+ }
929
+ switch (true) {
930
+ case isset($key['n']):
931
+ $components['modulus'] = $key['n']->copy();
932
+ break;
933
+ case isset($key['modulo']):
934
+ $components['modulus'] = $key['modulo']->copy();
935
+ break;
936
+ case isset($key['modulus']):
937
+ $components['modulus'] = $key['modulus']->copy();
938
+ break;
939
+ case isset($key[1]):
940
+ $components['modulus'] = $key[1]->copy();
941
+ }
942
+ return isset($components['modulus']) && isset($components['publicExponent']) ? $components : false;
943
+ case CRYPT_RSA_PRIVATE_FORMAT_PKCS1:
944
+ case CRYPT_RSA_PUBLIC_FORMAT_PKCS1:
945
+ /* Although PKCS#1 proposes a format that public and private keys can use, encrypting them is
946
+ "outside the scope" of PKCS#1. PKCS#1 then refers you to PKCS#12 and PKCS#15 if you're wanting to
947
+ protect private keys, however, that's not what OpenSSL* does. OpenSSL protects private keys by adding
948
+ two new "fields" to the key - DEK-Info and Proc-Type. These fields are discussed here:
949
+
950
+ http://tools.ietf.org/html/rfc1421#section-4.6.1.1
951
+ http://tools.ietf.org/html/rfc1421#section-4.6.1.3
952
+
953
+ DES-EDE3-CBC as an algorithm, however, is not discussed anywhere, near as I can tell.
954
+ DES-CBC and DES-EDE are discussed in RFC1423, however, DES-EDE3-CBC isn't, nor is its key derivation
955
+ function. As is, the definitive authority on this encoding scheme isn't the IETF but rather OpenSSL's
956
+ own implementation. ie. the implementation *is* the standard and any bugs that may exist in that
957
+ implementation are part of the standard, as well.
958
+
959
+ * OpenSSL is the de facto standard. It's utilized by OpenSSH and other projects */
960
+ if (preg_match('#DEK-Info: (.+),(.+)#', $key, $matches)) {
961
+ $iv = pack('H*', trim($matches[2]));
962
+ $symkey = pack('H*', md5($this->password . substr($iv, 0, 8))); // symkey is short for symmetric key
963
+ $symkey.= pack('H*', md5($symkey . $this->password . substr($iv, 0, 8)));
964
+ $ciphertext = preg_replace('#.+(\r|\n|\r\n)\1|[\r\n]|-.+-| #s', '', $key);
965
+ $ciphertext = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $ciphertext) ? base64_decode($ciphertext) : false;
966
+ if ($ciphertext === false) {
967
+ $ciphertext = $key;
968
+ }
969
+ switch ($matches[1]) {
970
+ case 'AES-256-CBC':
971
+ if (!class_exists('Crypt_AES')) {
972
+ require_once('Crypt/AES.php');
973
+ }
974
+ $crypto = new Crypt_AES();
975
+ break;
976
+ case 'AES-128-CBC':
977
+ if (!class_exists('Crypt_AES')) {
978
+ require_once('Crypt/AES.php');
979
+ }
980
+ $symkey = substr($symkey, 0, 16);
981
+ $crypto = new Crypt_AES();
982
+ break;
983
+ case 'DES-EDE3-CFB':
984
+ if (!class_exists('Crypt_TripleDES')) {
985
+ require_once('Crypt/TripleDES.php');
986
+ }
987
+ $crypto = new Crypt_TripleDES(CRYPT_DES_MODE_CFB);
988
+ break;
989
+ case 'DES-EDE3-CBC':
990
+ if (!class_exists('Crypt_TripleDES')) {
991
+ require_once('Crypt/TripleDES.php');
992
+ }
993
+ $symkey = substr($symkey, 0, 24);
994
+ $crypto = new Crypt_TripleDES();
995
+ break;
996
+ case 'DES-CBC':
997
+ if (!class_exists('Crypt_DES')) {
998
+ require_once('Crypt/DES.php');
999
+ }
1000
+ $crypto = new Crypt_DES();
1001
+ break;
1002
+ default:
1003
+ return false;
1004
+ }
1005
+ $crypto->setKey($symkey);
1006
+ $crypto->setIV($iv);
1007
+ $decoded = $crypto->decrypt($ciphertext);
1008
+ } else {
1009
+ $decoded = preg_replace('#-.+-|[\r\n]| #', '', $key);
1010
+ $decoded = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $decoded) ? base64_decode($decoded) : false;
1011
+ }
1012
+
1013
+ if ($decoded !== false) {
1014
+ $key = $decoded;
1015
+ }
1016
+
1017
+ $components = array();
1018
+
1019
+ if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
1020
+ return false;
1021
+ }
1022
+ if ($this->_decodeLength($key) != strlen($key)) {
1023
+ return false;
1024
+ }
1025
+
1026
+ $tag = ord($this->_string_shift($key));
1027
+ /* intended for keys for which OpenSSL's asn1parse returns the following:
1028
+
1029
+ 0:d=0 hl=4 l= 631 cons: SEQUENCE
1030
+ 4:d=1 hl=2 l= 1 prim: INTEGER :00
1031
+ 7:d=1 hl=2 l= 13 cons: SEQUENCE
1032
+ 9:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption
1033
+ 20:d=2 hl=2 l= 0 prim: NULL
1034
+ 22:d=1 hl=4 l= 609 prim: OCTET STRING */
1035
+
1036
+ if ($tag == CRYPT_RSA_ASN1_INTEGER && substr($key, 0, 3) == "\x01\x00\x30") {
1037
+ $this->_string_shift($key, 3);
1038
+ $tag = CRYPT_RSA_ASN1_SEQUENCE;
1039
+ }
1040
+
1041
+ if ($tag == CRYPT_RSA_ASN1_SEQUENCE) {
1042
+ /* intended for keys for which OpenSSL's asn1parse returns the following:
1043
+
1044
+ 0:d=0 hl=4 l= 290 cons: SEQUENCE
1045
+ 4:d=1 hl=2 l= 13 cons: SEQUENCE
1046
+ 6:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption
1047
+ 17:d=2 hl=2 l= 0 prim: NULL
1048
+ 19:d=1 hl=4 l= 271 prim: BIT STRING */
1049
+ $this->_string_shift($key, $this->_decodeLength($key));
1050
+ $tag = ord($this->_string_shift($key)); // skip over the BIT STRING / OCTET STRING tag
1051
+ $this->_decodeLength($key); // skip over the BIT STRING / OCTET STRING length
1052
+ // "The initial octet shall encode, as an unsigned binary integer wtih bit 1 as the least significant bit, the number of
1053
+ // unused bits in the final subsequent octet. The number shall be in the range zero to seven."
1054
+ // -- http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf (section 8.6.2.2)
1055
+ if ($tag == CRYPT_RSA_ASN1_BITSTRING) {
1056
+ $this->_string_shift($key);
1057
+ }
1058
+ if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
1059
+ return false;
1060
+ }
1061
+ if ($this->_decodeLength($key) != strlen($key)) {
1062
+ return false;
1063
+ }
1064
+ $tag = ord($this->_string_shift($key));
1065
+ }
1066
+ if ($tag != CRYPT_RSA_ASN1_INTEGER) {
1067
+ return false;
1068
+ }
1069
+
1070
+ $length = $this->_decodeLength($key);
1071
+ $temp = $this->_string_shift($key, $length);
1072
+ if (strlen($temp) != 1 || ord($temp) > 2) {
1073
+ $components['modulus'] = new Math_BigInteger($temp, 256);
1074
+ $this->_string_shift($key); // skip over CRYPT_RSA_ASN1_INTEGER
1075
+ $length = $this->_decodeLength($key);
1076
+ $components[$type == CRYPT_RSA_PUBLIC_FORMAT_PKCS1 ? 'publicExponent' : 'privateExponent'] = new Math_BigInteger($this->_string_shift($key, $length), 256);
1077
+
1078
+ return $components;
1079
+ }
1080
+ if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_INTEGER) {
1081
+ return false;
1082
+ }
1083
+ $length = $this->_decodeLength($key);
1084
+ $components['modulus'] = new Math_BigInteger($this->_string_shift($key, $length), 256);
1085
+ $this->_string_shift($key);
1086
+ $length = $this->_decodeLength($key);
1087
+ $components['publicExponent'] = new Math_BigInteger($this->_string_shift($key, $length), 256);
1088
+ $this->_string_shift($key);
1089
+ $length = $this->_decodeLength($key);
1090
+ $components['privateExponent'] = new Math_BigInteger($this->_string_shift($key, $length), 256);
1091
+ $this->_string_shift($key);
1092
+ $length = $this->_decodeLength($key);
1093
+ $components['primes'] = array(1 => new Math_BigInteger($this->_string_shift($key, $length), 256));
1094
+ $this->_string_shift($key);
1095
+ $length = $this->_decodeLength($key);
1096
+ $components['primes'][] = new Math_BigInteger($this->_string_shift($key, $length), 256);
1097
+ $this->_string_shift($key);
1098
+ $length = $this->_decodeLength($key);
1099
+ $components['exponents'] = array(1 => new Math_BigInteger($this->_string_shift($key, $length), 256));
1100
+ $this->_string_shift($key);
1101
+ $length = $this->_decodeLength($key);
1102
+ $components['exponents'][] = new Math_BigInteger($this->_string_shift($key, $length), 256);
1103
+ $this->_string_shift($key);
1104
+ $length = $this->_decodeLength($key);
1105
+ $components['coefficients'] = array(2 => new Math_BigInteger($this->_string_shift($key, $length), 256));
1106
+
1107
+ if (!empty($key)) {
1108
+ if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
1109
+ return false;
1110
+ }
1111
+ $this->_decodeLength($key);
1112
+ while (!empty($key)) {
1113
+ if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
1114
+ return false;
1115
+ }
1116
+ $this->_decodeLength($key);
1117
+ $key = substr($key, 1);
1118
+ $length = $this->_decodeLength($key);
1119
+ $components['primes'][] = new Math_BigInteger($this->_string_shift($key, $length), 256);
1120
+ $this->_string_shift($key);
1121
+ $length = $this->_decodeLength($key);
1122
+ $components['exponents'][] = new Math_BigInteger($this->_string_shift($key, $length), 256);
1123
+ $this->_string_shift($key);
1124
+ $length = $this->_decodeLength($key);
1125
+ $components['coefficients'][] = new Math_BigInteger($this->_string_shift($key, $length), 256);
1126
+ }
1127
+ }
1128
+
1129
+ return $components;
1130
+ case CRYPT_RSA_PUBLIC_FORMAT_OPENSSH:
1131
+ $parts = explode(' ', $key, 3);
1132
+
1133
+ $key = isset($parts[1]) ? base64_decode($parts[1]) : false;
1134
+ if ($key === false) {
1135
+ return false;
1136
+ }
1137
+
1138
+ $comment = isset($parts[2]) ? $parts[2] : false;
1139
+
1140
+ $cleanup = substr($key, 0, 11) == "\0\0\0\7ssh-rsa";
1141
+
1142
+ if (strlen($key) <= 4) {
1143
+ return false;
1144
+ }
1145
+ extract(unpack('Nlength', $this->_string_shift($key, 4)));
1146
+ $publicExponent = new Math_BigInteger($this->_string_shift($key, $length), -256);
1147
+ if (strlen($key) <= 4) {
1148
+ return false;
1149
+ }
1150
+ extract(unpack('Nlength', $this->_string_shift($key, 4)));
1151
+ $modulus = new Math_BigInteger($this->_string_shift($key, $length), -256);
1152
+
1153
+ if ($cleanup && strlen($key)) {
1154
+ if (strlen($key) <= 4) {
1155
+ return false;
1156
+ }
1157
+ extract(unpack('Nlength', $this->_string_shift($key, 4)));
1158
+ $realModulus = new Math_BigInteger($this->_string_shift($key, $length), -256);
1159
+ return strlen($key) ? false : array(
1160
+ 'modulus' => $realModulus,
1161
+ 'publicExponent' => $modulus,
1162
+ 'comment' => $comment
1163
+ );
1164
+ } else {
1165
+ return strlen($key) ? false : array(
1166
+ 'modulus' => $modulus,
1167
+ 'publicExponent' => $publicExponent,
1168
+ 'comment' => $comment
1169
+ );
1170
+ }
1171
+ // http://www.w3.org/TR/xmldsig-core/#sec-RSAKeyValue
1172
+ // http://en.wikipedia.org/wiki/XML_Signature
1173
+ case CRYPT_RSA_PRIVATE_FORMAT_XML:
1174
+ case CRYPT_RSA_PUBLIC_FORMAT_XML:
1175
+ $this->components = array();
1176
+
1177
+ $xml = xml_parser_create('UTF-8');
1178
+ xml_set_object($xml, $this);
1179
+ xml_set_element_handler($xml, '_start_element_handler', '_stop_element_handler');
1180
+ xml_set_character_data_handler($xml, '_data_handler');
1181
+ // add <xml></xml> to account for "dangling" tags like <BitStrength>...</BitStrength> that are sometimes added
1182
+ if (!xml_parse($xml, '<xml>' . $key . '</xml>')) {
1183
+ return false;
1184
+ }
1185
+
1186
+ return isset($this->components['modulus']) && isset($this->components['publicExponent']) ? $this->components : false;
1187
+ // from PuTTY's SSHPUBK.C
1188
+ case CRYPT_RSA_PRIVATE_FORMAT_PUTTY:
1189
+ $components = array();
1190
+ $key = preg_split('#\r\n|\r|\n#', $key);
1191
+ $type = trim(preg_replace('#PuTTY-User-Key-File-2: (.+)#', '$1', $key[0]));
1192
+ if ($type != 'ssh-rsa') {
1193
+ return false;
1194
+ }
1195
+ $encryption = trim(preg_replace('#Encryption: (.+)#', '$1', $key[1]));
1196
+ $comment = trim(preg_replace('#Comment: (.+)#', '$1', $key[2]));
1197
+
1198
+ $publicLength = trim(preg_replace('#Public-Lines: (\d+)#', '$1', $key[3]));
1199
+ $public = base64_decode(implode('', array_map('trim', array_slice($key, 4, $publicLength))));
1200
+ $public = substr($public, 11);
1201
+ extract(unpack('Nlength', $this->_string_shift($public, 4)));
1202
+ $components['publicExponent'] = new Math_BigInteger($this->_string_shift($public, $length), -256);
1203
+ extract(unpack('Nlength', $this->_string_shift($public, 4)));
1204
+ $components['modulus'] = new Math_BigInteger($this->_string_shift($public, $length), -256);
1205
+
1206
+ $privateLength = trim(preg_replace('#Private-Lines: (\d+)#', '$1', $key[$publicLength + 4]));
1207
+ $private = base64_decode(implode('', array_map('trim', array_slice($key, $publicLength + 5, $privateLength))));
1208
+
1209
+ switch ($encryption) {
1210
+ case 'aes256-cbc':
1211
+ if (!class_exists('Crypt_AES')) {
1212
+ require_once('Crypt/AES.php');
1213
+ }
1214
+ $symkey = '';
1215
+ $sequence = 0;
1216
+ while (strlen($symkey) < 32) {
1217
+ $temp = pack('Na*', $sequence++, $this->password);
1218
+ $symkey.= pack('H*', sha1($temp));
1219
+ }
1220
+ $symkey = substr($symkey, 0, 32);
1221
+ $crypto = new Crypt_AES();
1222
+ }
1223
+
1224
+ if ($encryption != 'none') {
1225
+ $crypto->setKey($symkey);
1226
+ $crypto->disablePadding();
1227
+ $private = $crypto->decrypt($private);
1228
+ if ($private === false) {
1229
+ return false;
1230
+ }
1231
+ }
1232
+
1233
+ extract(unpack('Nlength', $this->_string_shift($private, 4)));
1234
+ if (strlen($private) < $length) {
1235
+ return false;
1236
+ }
1237
+ $components['privateExponent'] = new Math_BigInteger($this->_string_shift($private, $length), -256);
1238
+ extract(unpack('Nlength', $this->_string_shift($private, 4)));
1239
+ if (strlen($private) < $length) {
1240
+ return false;
1241
+ }
1242
+ $components['primes'] = array(1 => new Math_BigInteger($this->_string_shift($private, $length), -256));
1243
+ extract(unpack('Nlength', $this->_string_shift($private, 4)));
1244
+ if (strlen($private) < $length) {
1245
+ return false;
1246
+ }
1247
+ $components['primes'][] = new Math_BigInteger($this->_string_shift($private, $length), -256);
1248
+
1249
+ $temp = $components['primes'][1]->subtract($this->one);
1250
+ $components['exponents'] = array(1 => $components['publicExponent']->modInverse($temp));
1251
+ $temp = $components['primes'][2]->subtract($this->one);
1252
+ $components['exponents'][] = $components['publicExponent']->modInverse($temp);
1253
+
1254
+ extract(unpack('Nlength', $this->_string_shift($private, 4)));
1255
+ if (strlen($private) < $length) {
1256
+ return false;
1257
+ }
1258
+ $components['coefficients'] = array(2 => new Math_BigInteger($this->_string_shift($private, $length), -256));
1259
+
1260
+ return $components;
1261
+ }
1262
+ }
1263
+
1264
+ /**
1265
+ * Returns the key size
1266
+ *
1267
+ * More specifically, this returns the size of the modulo in bits.
1268
+ *
1269
+ * @access public
1270
+ * @return Integer
1271
+ */
1272
+ function getSize()
1273
+ {
1274
+ return !isset($this->modulus) ? 0 : strlen($this->modulus->toBits());
1275
+ }
1276
+
1277
+ /**
1278
+ * Start Element Handler
1279
+ *
1280
+ * Called by xml_set_element_handler()
1281
+ *
1282
+ * @access private
1283
+ * @param Resource $parser
1284
+ * @param String $name
1285
+ * @param Array $attribs
1286
+ */
1287
+ function _start_element_handler($parser, $name, $attribs)
1288
+ {
1289
+ //$name = strtoupper($name);
1290
+ switch ($name) {
1291
+ case 'MODULUS':
1292
+ $this->current = &$this->components['modulus'];
1293
+ break;
1294
+ case 'EXPONENT':
1295
+ $this->current = &$this->components['publicExponent'];
1296
+ break;
1297
+ case 'P':
1298
+ $this->current = &$this->components['primes'][1];
1299
+ break;
1300
+ case 'Q':
1301
+ $this->current = &$this->components['primes'][2];
1302
+ break;
1303
+ case 'DP':
1304
+ $this->current = &$this->components['exponents'][1];
1305
+ break;
1306
+ case 'DQ':
1307
+ $this->current = &$this->components['exponents'][2];
1308
+ break;
1309
+ case 'INVERSEQ':
1310
+ $this->current = &$this->components['coefficients'][2];
1311
+ break;
1312
+ case 'D':
1313
+ $this->current = &$this->components['privateExponent'];
1314
+ break;
1315
+ default:
1316
+ unset($this->current);
1317
+ }
1318
+ $this->current = '';
1319
+ }
1320
+
1321
+ /**
1322
+ * Stop Element Handler
1323
+ *
1324
+ * Called by xml_set_element_handler()
1325
+ *
1326
+ * @access private
1327
+ * @param Resource $parser
1328
+ * @param String $name
1329
+ */
1330
+ function _stop_element_handler($parser, $name)
1331
+ {
1332
+ //$name = strtoupper($name);
1333
+ if ($name == 'RSAKEYVALUE') {
1334
+ return;
1335
+ }
1336
+ $this->current = new Math_BigInteger(base64_decode($this->current), 256);
1337
+ }
1338
+
1339
+ /**
1340
+ * Data Handler
1341
+ *
1342
+ * Called by xml_set_character_data_handler()
1343
+ *
1344
+ * @access private
1345
+ * @param Resource $parser
1346
+ * @param String $data
1347
+ */
1348
+ function _data_handler($parser, $data)
1349
+ {
1350
+ if (!isset($this->current) || is_object($this->current)) {
1351
+ return;
1352
+ }
1353
+ $this->current.= trim($data);
1354
+ }
1355
+
1356
+ /**
1357
+ * Loads a public or private key
1358
+ *
1359
+ * Returns true on success and false on failure (ie. an incorrect password was provided or the key was malformed)
1360
+ *
1361
+ * @access public
1362
+ * @param String $key
1363
+ * @param Integer $type optional
1364
+ */
1365
+ function loadKey($key, $type = false)
1366
+ {
1367
+ if ($type === false) {
1368
+ $types = array(
1369
+ CRYPT_RSA_PUBLIC_FORMAT_RAW,
1370
+ CRYPT_RSA_PRIVATE_FORMAT_PKCS1,
1371
+ CRYPT_RSA_PRIVATE_FORMAT_XML,
1372
+ CRYPT_RSA_PRIVATE_FORMAT_PUTTY,
1373
+ CRYPT_RSA_PUBLIC_FORMAT_OPENSSH
1374
+ );
1375
+ foreach ($types as $type) {
1376
+ $components = $this->_parseKey($key, $type);
1377
+ if ($components !== false) {
1378
+ break;
1379
+ }
1380
+ }
1381
+
1382
+ } else {
1383
+ $components = $this->_parseKey($key, $type);
1384
+ }
1385
+
1386
+ if ($components === false) {
1387
+ return false;
1388
+ }
1389
+
1390
+ if (isset($components['comment']) && $components['comment'] !== false) {
1391
+ $this->comment = $components['comment'];
1392
+ }
1393
+ $this->modulus = $components['modulus'];
1394
+ $this->k = strlen($this->modulus->toBytes());
1395
+ $this->exponent = isset($components['privateExponent']) ? $components['privateExponent'] : $components['publicExponent'];
1396
+ if (isset($components['primes'])) {
1397
+ $this->primes = $components['primes'];
1398
+ $this->exponents = $components['exponents'];
1399
+ $this->coefficients = $components['coefficients'];
1400
+ $this->publicExponent = $components['publicExponent'];
1401
+ } else {
1402
+ $this->primes = array();
1403
+ $this->exponents = array();
1404
+ $this->coefficients = array();
1405
+ $this->publicExponent = false;
1406
+ }
1407
+
1408
+ return true;
1409
+ }
1410
+
1411
+ /**
1412
+ * Sets the password
1413
+ *
1414
+ * Private keys can be encrypted with a password. To unset the password, pass in the empty string or false.
1415
+ * Or rather, pass in $password such that empty($password) && !is_string($password) is true.
1416
+ *
1417
+ * @see createKey()
1418
+ * @see loadKey()
1419
+ * @access public
1420
+ * @param String $password
1421
+ */
1422
+ function setPassword($password = false)
1423
+ {
1424
+ $this->password = $password;
1425
+ }
1426
+
1427
+ /**
1428
+ * Defines the public key
1429
+ *
1430
+ * Some private key formats define the public exponent and some don't. Those that don't define it are problematic when
1431
+ * used in certain contexts. For example, in SSH-2, RSA authentication works by sending the public key along with a
1432
+ * message signed by the private key to the server. The SSH-2 server looks the public key up in an index of public keys
1433
+ * and if it's present then proceeds to verify the signature. Problem is, if your private key doesn't include the public
1434
+ * exponent this won't work unless you manually add the public exponent.
1435
+ *
1436
+ * Do note that when a new key is loaded the index will be cleared.
1437
+ *
1438
+ * Returns true on success, false on failure
1439
+ *
1440
+ * @see getPublicKey()
1441
+ * @access public
1442
+ * @param String $key optional
1443
+ * @param Integer $type optional
1444
+ * @return Boolean
1445
+ */
1446
+ function setPublicKey($key = false, $type = false)
1447
+ {
1448
+ if ($key === false && !empty($this->modulus)) {
1449
+ $this->publicExponent = $this->exponent;
1450
+ return true;
1451
+ }
1452
+
1453
+ if ($type === false) {
1454
+ $types = array(
1455
+ CRYPT_RSA_PUBLIC_FORMAT_RAW,
1456
+ CRYPT_RSA_PUBLIC_FORMAT_PKCS1,
1457
+ CRYPT_RSA_PUBLIC_FORMAT_XML,
1458
+ CRYPT_RSA_PUBLIC_FORMAT_OPENSSH
1459
+ );
1460
+ foreach ($types as $type) {
1461
+ $components = $this->_parseKey($key, $type);
1462
+ if ($components !== false) {
1463
+ break;
1464
+ }
1465
+ }
1466
+ } else {
1467
+ $components = $this->_parseKey($key, $type);
1468
+ }
1469
+
1470
+ if ($components === false) {
1471
+ return false;
1472
+ }
1473
+
1474
+ if (empty($this->modulus) || !$this->modulus->equals($components['modulus'])) {
1475
+ $this->modulus = $components['modulus'];
1476
+ $this->exponent = $this->publicExponent = $components['publicExponent'];
1477
+ return true;
1478
+ }
1479
+
1480
+ $this->publicExponent = $components['publicExponent'];
1481
+
1482
+ return true;
1483
+ }
1484
+
1485
+ /**
1486
+ * Returns the public key
1487
+ *
1488
+ * The public key is only returned under two circumstances - if the private key had the public key embedded within it
1489
+ * or if the public key was set via setPublicKey(). If the currently loaded key is supposed to be the public key this
1490
+ * function won't return it since this library, for the most part, doesn't distinguish between public and private keys.
1491
+ *
1492
+ * @see getPublicKey()
1493
+ * @access public
1494
+ * @param String $key
1495
+ * @param Integer $type optional
1496
+ */
1497
+ function getPublicKey($type = CRYPT_RSA_PUBLIC_FORMAT_PKCS1)
1498
+ {
1499
+ if (empty($this->modulus) || empty($this->publicExponent)) {
1500
+ return false;
1501
+ }
1502
+
1503
+ $oldFormat = $this->publicKeyFormat;
1504
+ $this->publicKeyFormat = $type;
1505
+ $temp = $this->_convertPublicKey($this->modulus, $this->publicExponent);
1506
+ $this->publicKeyFormat = $oldFormat;
1507
+ return $temp;
1508
+ }
1509
+
1510
+ /**
1511
+ * Returns the private key
1512
+ *
1513
+ * The private key is only returned if the currently loaded key contains the constituent prime numbers.
1514
+ *
1515
+ * @see getPublicKey()
1516
+ * @access public
1517
+ * @param String $key
1518
+ * @param Integer $type optional
1519
+ */
1520
+ function getPrivateKey($type = CRYPT_RSA_PUBLIC_FORMAT_PKCS1)
1521
+ {
1522
+ if (empty($this->primes)) {
1523
+ return false;
1524
+ }
1525
+
1526
+ $oldFormat = $this->privateKeyFormat;
1527
+ $this->privateKeyFormat = $type;
1528
+ $temp = $this->_convertPrivateKey($this->modulus, $this->publicExponent, $this->exponent, $this->primes, $this->exponents, $this->coefficients);
1529
+ $this->privateKeyFormat = $oldFormat;
1530
+ return $temp;
1531
+ }
1532
+
1533
+ /**
1534
+ * Returns a minimalistic private key
1535
+ *
1536
+ * Returns the private key without the prime number constituants. Structurally identical to a public key that
1537
+ * hasn't been set as the public key
1538
+ *
1539
+ * @see getPrivateKey()
1540
+ * @access private
1541
+ * @param String $key
1542
+ * @param Integer $type optional
1543
+ */
1544
+ function _getPrivatePublicKey($mode = CRYPT_RSA_PUBLIC_FORMAT_PKCS1)
1545
+ {
1546
+ if (empty($this->modulus) || empty($this->exponent)) {
1547
+ return false;
1548
+ }
1549
+
1550
+ $oldFormat = $this->publicKeyFormat;
1551
+ $this->publicKeyFormat = $mode;
1552
+ $temp = $this->_convertPublicKey($this->modulus, $this->exponent);
1553
+ $this->publicKeyFormat = $oldFormat;
1554
+ return $temp;
1555
+ }
1556
+
1557
+ /**
1558
+ * __toString() magic method
1559
+ *
1560
+ * @access public
1561
+ */
1562
+ function __toString()
1563
+ {
1564
+ $key = $this->getPrivateKey($this->privateKeyFormat);
1565
+ if ($key !== false) {
1566
+ return $key;
1567
+ }
1568
+ $key = $this->_getPrivatePublicKey($this->publicKeyFormat);
1569
+ return $key !== false ? $key : '';
1570
+ }
1571
+
1572
+ /**
1573
+ * Generates the smallest and largest numbers requiring $bits bits
1574
+ *
1575
+ * @access private
1576
+ * @param Integer $bits
1577
+ * @return Array
1578
+ */
1579
+ function _generateMinMax($bits)
1580
+ {
1581
+ $bytes = $bits >> 3;
1582
+ $min = str_repeat(chr(0), $bytes);
1583
+ $max = str_repeat(chr(0xFF), $bytes);
1584
+ $msb = $bits & 7;
1585
+ if ($msb) {
1586
+ $min = chr(1 << ($msb - 1)) . $min;
1587
+ $max = chr((1 << $msb) - 1) . $max;
1588
+ } else {
1589
+ $min[0] = chr(0x80);
1590
+ }
1591
+
1592
+ return array(
1593
+ 'min' => new Math_BigInteger($min, 256),
1594
+ 'max' => new Math_BigInteger($max, 256)
1595
+ );
1596
+ }
1597
+
1598
+ /**
1599
+ * DER-decode the length
1600
+ *
1601
+ * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See
1602
+ * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information.
1603
+ *
1604
+ * @access private
1605
+ * @param String $string
1606
+ * @return Integer
1607
+ */
1608
+ function _decodeLength(&$string)
1609
+ {
1610
+ $length = ord($this->_string_shift($string));
1611
+ if ( $length & 0x80 ) { // definite length, long form
1612
+ $length&= 0x7F;
1613
+ $temp = $this->_string_shift($string, $length);
1614
+ list(, $length) = unpack('N', substr(str_pad($temp, 4, chr(0), STR_PAD_LEFT), -4));
1615
+ }
1616
+ return $length;
1617
+ }
1618
+
1619
+ /**
1620
+ * DER-encode the length
1621
+ *
1622
+ * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See
1623
+ * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information.
1624
+ *
1625
+ * @access private
1626
+ * @param Integer $length
1627
+ * @return String
1628
+ */
1629
+ function _encodeLength($length)
1630
+ {
1631
+ if ($length <= 0x7F) {
1632
+ return chr($length);
1633
+ }
1634
+
1635
+ $temp = ltrim(pack('N', $length), chr(0));
1636
+ return pack('Ca*', 0x80 | strlen($temp), $temp);
1637
+ }
1638
+
1639
+ /**
1640
+ * String Shift
1641
+ *
1642
+ * Inspired by array_shift
1643
+ *
1644
+ * @param String $string
1645
+ * @param optional Integer $index
1646
+ * @return String
1647
+ * @access private
1648
+ */
1649
+ function _string_shift(&$string, $index = 1)
1650
+ {
1651
+ $substr = substr($string, 0, $index);
1652
+ $string = substr($string, $index);
1653
+ return $substr;
1654
+ }
1655
+
1656
+ /**
1657
+ * Determines the private key format
1658
+ *
1659
+ * @see createKey()
1660
+ * @access public
1661
+ * @param Integer $format
1662
+ */
1663
+ function setPrivateKeyFormat($format)
1664
+ {
1665
+ $this->privateKeyFormat = $format;
1666
+ }
1667
+
1668
+ /**
1669
+ * Determines the public key format
1670
+ *
1671
+ * @see createKey()
1672
+ * @access public
1673
+ * @param Integer $format
1674
+ */
1675
+ function setPublicKeyFormat($format)
1676
+ {
1677
+ $this->publicKeyFormat = $format;
1678
+ }
1679
+
1680
+ /**
1681
+ * Determines which hashing function should be used
1682
+ *
1683
+ * Used with signature production / verification and (if the encryption mode is CRYPT_RSA_ENCRYPTION_OAEP) encryption and
1684
+ * decryption. If $hash isn't supported, sha1 is used.
1685
+ *
1686
+ * @access public
1687
+ * @param String $hash
1688
+ */
1689
+ function setHash($hash)
1690
+ {
1691
+ // Crypt_Hash supports algorithms that PKCS#1 doesn't support. md5-96 and sha1-96, for example.
1692
+ switch ($hash) {
1693
+ case 'md2':
1694
+ case 'md5':
1695
+ case 'sha1':
1696
+ case 'sha256':
1697
+ case 'sha384':
1698
+ case 'sha512':
1699
+ $this->hash = new Crypt_Hash($hash);
1700
+ $this->hashName = $hash;
1701
+ break;
1702
+ default:
1703
+ $this->hash = new Crypt_Hash('sha1');
1704
+ $this->hashName = 'sha1';
1705
+ }
1706
+ $this->hLen = $this->hash->getLength();
1707
+ }
1708
+
1709
+ /**
1710
+ * Determines which hashing function should be used for the mask generation function
1711
+ *
1712
+ * The mask generation function is used by CRYPT_RSA_ENCRYPTION_OAEP and CRYPT_RSA_SIGNATURE_PSS and although it's
1713
+ * best if Hash and MGFHash are set to the same thing this is not a requirement.
1714
+ *
1715
+ * @access public
1716
+ * @param String $hash
1717
+ */
1718
+ function setMGFHash($hash)
1719
+ {
1720
+ // Crypt_Hash supports algorithms that PKCS#1 doesn't support. md5-96 and sha1-96, for example.
1721
+ switch ($hash) {
1722
+ case 'md2':
1723
+ case 'md5':
1724
+ case 'sha1':
1725
+ case 'sha256':
1726
+ case 'sha384':
1727
+ case 'sha512':
1728
+ $this->mgfHash = new Crypt_Hash($hash);
1729
+ break;
1730
+ default:
1731
+ $this->mgfHash = new Crypt_Hash('sha1');
1732
+ }
1733
+ $this->mgfHLen = $this->mgfHash->getLength();
1734
+ }
1735
+
1736
+ /**
1737
+ * Determines the salt length
1738
+ *
1739
+ * To quote from {@link http://tools.ietf.org/html/rfc3447#page-38 RFC3447#page-38}:
1740
+ *
1741
+ * Typical salt lengths in octets are hLen (the length of the output
1742
+ * of the hash function Hash) and 0.
1743
+ *
1744
+ * @access public
1745
+ * @param Integer $format
1746
+ */
1747
+ function setSaltLength($sLen)
1748
+ {
1749
+ $this->sLen = $sLen;
1750
+ }
1751
+
1752
+ /**
1753
+ * Integer-to-Octet-String primitive
1754
+ *
1755
+ * See {@link http://tools.ietf.org/html/rfc3447#section-4.1 RFC3447#section-4.1}.
1756
+ *
1757
+ * @access private
1758
+ * @param Math_BigInteger $x
1759
+ * @param Integer $xLen
1760
+ * @return String
1761
+ */
1762
+ function _i2osp($x, $xLen)
1763
+ {
1764
+ $x = $x->toBytes();
1765
+ if (strlen($x) > $xLen) {
1766
+ user_error('Integer too large');
1767
+ return false;
1768
+ }
1769
+ return str_pad($x, $xLen, chr(0), STR_PAD_LEFT);
1770
+ }
1771
+
1772
+ /**
1773
+ * Octet-String-to-Integer primitive
1774
+ *
1775
+ * See {@link http://tools.ietf.org/html/rfc3447#section-4.2 RFC3447#section-4.2}.
1776
+ *
1777
+ * @access private
1778
+ * @param String $x
1779
+ * @return Math_BigInteger
1780
+ */
1781
+ function _os2ip($x)
1782
+ {
1783
+ return new Math_BigInteger($x, 256);
1784
+ }
1785
+
1786
+ /**
1787
+ * Exponentiate with or without Chinese Remainder Theorem
1788
+ *
1789
+ * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.1 RFC3447#section-5.1.2}.
1790
+ *
1791
+ * @access private
1792
+ * @param Math_BigInteger $x
1793
+ * @return Math_BigInteger
1794
+ */
1795
+ function _exponentiate($x)
1796
+ {
1797
+ if (empty($this->primes) || empty($this->coefficients) || empty($this->exponents)) {
1798
+ return $x->modPow($this->exponent, $this->modulus);
1799
+ }
1800
+
1801
+ $num_primes = count($this->primes);
1802
+
1803
+ if (defined('CRYPT_RSA_DISABLE_BLINDING')) {
1804
+ $m_i = array(
1805
+ 1 => $x->modPow($this->exponents[1], $this->primes[1]),
1806
+ 2 => $x->modPow($this->exponents[2], $this->primes[2])
1807
+ );
1808
+ $h = $m_i[1]->subtract($m_i[2]);
1809
+ $h = $h->multiply($this->coefficients[2]);
1810
+ list(, $h) = $h->divide($this->primes[1]);
1811
+ $m = $m_i[2]->add($h->multiply($this->primes[2]));
1812
+
1813
+ $r = $this->primes[1];
1814
+ for ($i = 3; $i <= $num_primes; $i++) {
1815
+ $m_i = $x->modPow($this->exponents[$i], $this->primes[$i]);
1816
+
1817
+ $r = $r->multiply($this->primes[$i - 1]);
1818
+
1819
+ $h = $m_i->subtract($m);
1820
+ $h = $h->multiply($this->coefficients[$i]);
1821
+ list(, $h) = $h->divide($this->primes[$i]);
1822
+
1823
+ $m = $m->add($r->multiply($h));
1824
+ }
1825
+ } else {
1826
+ $smallest = $this->primes[1];
1827
+ for ($i = 2; $i <= $num_primes; $i++) {
1828
+ if ($smallest->compare($this->primes[$i]) > 0) {
1829
+ $smallest = $this->primes[$i];
1830
+ }
1831
+ }
1832
+
1833
+ $one = new Math_BigInteger(1);
1834
+
1835
+ $r = $one->random($one, $smallest->subtract($one));
1836
+
1837
+ $m_i = array(
1838
+ 1 => $this->_blind($x, $r, 1),
1839
+ 2 => $this->_blind($x, $r, 2)
1840
+ );
1841
+ $h = $m_i[1]->subtract($m_i[2]);
1842
+ $h = $h->multiply($this->coefficients[2]);
1843
+ list(, $h) = $h->divide($this->primes[1]);
1844
+ $m = $m_i[2]->add($h->multiply($this->primes[2]));
1845
+
1846
+ $r = $this->primes[1];
1847
+ for ($i = 3; $i <= $num_primes; $i++) {
1848
+ $m_i = $this->_blind($x, $r, $i);
1849
+
1850
+ $r = $r->multiply($this->primes[$i - 1]);
1851
+
1852
+ $h = $m_i->subtract($m);
1853
+ $h = $h->multiply($this->coefficients[$i]);
1854
+ list(, $h) = $h->divide($this->primes[$i]);
1855
+
1856
+ $m = $m->add($r->multiply($h));
1857
+ }
1858
+ }
1859
+
1860
+ return $m;
1861
+ }
1862
+
1863
+ /**
1864
+ * Performs RSA Blinding
1865
+ *
1866
+ * Protects against timing attacks by employing RSA Blinding.
1867
+ * Returns $x->modPow($this->exponents[$i], $this->primes[$i])
1868
+ *
1869
+ * @access private
1870
+ * @param Math_BigInteger $x
1871
+ * @param Math_BigInteger $r
1872
+ * @param Integer $i
1873
+ * @return Math_BigInteger
1874
+ */
1875
+ function _blind($x, $r, $i)
1876
+ {
1877
+ $x = $x->multiply($r->modPow($this->publicExponent, $this->primes[$i]));
1878
+ $x = $x->modPow($this->exponents[$i], $this->primes[$i]);
1879
+
1880
+ $r = $r->modInverse($this->primes[$i]);
1881
+ $x = $x->multiply($r);
1882
+ list(, $x) = $x->divide($this->primes[$i]);
1883
+
1884
+ return $x;
1885
+ }
1886
+
1887
+ /**
1888
+ * Performs blinded RSA equality testing
1889
+ *
1890
+ * Protects against a particular type of timing attack described.
1891
+ *
1892
+ * See {@link http://codahale.com/a-lesson-in-timing-attacks/ A Lesson In Timing Attacks (or, Don't use MessageDigest.isEquals)}
1893
+ *
1894
+ * Thanks for the heads up singpolyma!
1895
+ *
1896
+ * @access private
1897
+ * @param String $x
1898
+ * @param String $y
1899
+ * @return Boolean
1900
+ */
1901
+ function _equals($x, $y)
1902
+ {
1903
+ if (strlen($x) != strlen($y)) {
1904
+ return false;
1905
+ }
1906
+
1907
+ $result = 0;
1908
+ for ($i = 0; $i < strlen($x); $i++) {
1909
+ $result |= ord($x[$i]) ^ ord($y[$i]);
1910
+ }
1911
+
1912
+ return $result == 0;
1913
+ }
1914
+
1915
+ /**
1916
+ * RSAEP
1917
+ *
1918
+ * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.1 RFC3447#section-5.1.1}.
1919
+ *
1920
+ * @access private
1921
+ * @param Math_BigInteger $m
1922
+ * @return Math_BigInteger
1923
+ */
1924
+ function _rsaep($m)
1925
+ {
1926
+ if ($m->compare($this->zero) < 0 || $m->compare($this->modulus) > 0) {
1927
+ user_error('Message representative out of range');
1928
+ return false;
1929
+ }
1930
+ return $this->_exponentiate($m);
1931
+ }
1932
+
1933
+ /**
1934
+ * RSADP
1935
+ *
1936
+ * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.2 RFC3447#section-5.1.2}.
1937
+ *
1938
+ * @access private
1939
+ * @param Math_BigInteger $c
1940
+ * @return Math_BigInteger
1941
+ */
1942
+ function _rsadp($c)
1943
+ {
1944
+ if ($c->compare($this->zero) < 0 || $c->compare($this->modulus) > 0) {
1945
+ user_error('Ciphertext representative out of range');
1946
+ return false;
1947
+ }
1948
+ return $this->_exponentiate($c);
1949
+ }
1950
+
1951
+ /**
1952
+ * RSASP1
1953
+ *
1954
+ * See {@link http://tools.ietf.org/html/rfc3447#section-5.2.1 RFC3447#section-5.2.1}.
1955
+ *
1956
+ * @access private
1957
+ * @param Math_BigInteger $m
1958
+ * @return Math_BigInteger
1959
+ */
1960
+ function _rsasp1($m)
1961
+ {
1962
+ if ($m->compare($this->zero) < 0 || $m->compare($this->modulus) > 0) {
1963
+ user_error('Message representative out of range');
1964
+ return false;
1965
+ }
1966
+ return $this->_exponentiate($m);
1967
+ }
1968
+
1969
+ /**
1970
+ * RSAVP1
1971
+ *
1972
+ * See {@link http://tools.ietf.org/html/rfc3447#section-5.2.2 RFC3447#section-5.2.2}.
1973
+ *
1974
+ * @access private
1975
+ * @param Math_BigInteger $s
1976
+ * @return Math_BigInteger
1977
+ */
1978
+ function _rsavp1($s)
1979
+ {
1980
+ if ($s->compare($this->zero) < 0 || $s->compare($this->modulus) > 0) {
1981
+ user_error('Signature representative out of range');
1982
+ return false;
1983
+ }
1984
+ return $this->_exponentiate($s);
1985
+ }
1986
+
1987
+ /**
1988
+ * MGF1
1989
+ *
1990
+ * See {@link http://tools.ietf.org/html/rfc3447#appendix-B.2.1 RFC3447#appendix-B.2.1}.
1991
+ *
1992
+ * @access private
1993
+ * @param String $mgfSeed
1994
+ * @param Integer $mgfLen
1995
+ * @return String
1996
+ */
1997
+ function _mgf1($mgfSeed, $maskLen)
1998
+ {
1999
+ // if $maskLen would yield strings larger than 4GB, PKCS#1 suggests a "Mask too long" error be output.
2000
+
2001
+ $t = '';
2002
+ $count = ceil($maskLen / $this->mgfHLen);
2003
+ for ($i = 0; $i < $count; $i++) {
2004
+ $c = pack('N', $i);
2005
+ $t.= $this->mgfHash->hash($mgfSeed . $c);
2006
+ }
2007
+
2008
+ return substr($t, 0, $maskLen);
2009
+ }
2010
+
2011
+ /**
2012
+ * RSAES-OAEP-ENCRYPT
2013
+ *
2014
+ * See {@link http://tools.ietf.org/html/rfc3447#section-7.1.1 RFC3447#section-7.1.1} and
2015
+ * {http://en.wikipedia.org/wiki/Optimal_Asymmetric_Encryption_Padding OAES}.
2016
+ *
2017
+ * @access private
2018
+ * @param String $m
2019
+ * @param String $l
2020
+ * @return String
2021
+ */
2022
+ function _rsaes_oaep_encrypt($m, $l = '')
2023
+ {
2024
+ $mLen = strlen($m);
2025
+
2026
+ // Length checking
2027
+
2028
+ // if $l is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
2029
+ // be output.
2030
+
2031
+ if ($mLen > $this->k - 2 * $this->hLen - 2) {
2032
+ user_error('Message too long');
2033
+ return false;
2034
+ }
2035
+
2036
+ // EME-OAEP encoding
2037
+
2038
+ $lHash = $this->hash->hash($l);
2039
+ $ps = str_repeat(chr(0), $this->k - $mLen - 2 * $this->hLen - 2);
2040
+ $db = $lHash . $ps . chr(1) . $m;
2041
+ $seed = crypt_random_string($this->hLen);
2042
+ $dbMask = $this->_mgf1($seed, $this->k - $this->hLen - 1);
2043
+ $maskedDB = $db ^ $dbMask;
2044
+ $seedMask = $this->_mgf1($maskedDB, $this->hLen);
2045
+ $maskedSeed = $seed ^ $seedMask;
2046
+ $em = chr(0) . $maskedSeed . $maskedDB;
2047
+
2048
+ // RSA encryption
2049
+
2050
+ $m = $this->_os2ip($em);
2051
+ $c = $this->_rsaep($m);
2052
+ $c = $this->_i2osp($c, $this->k);
2053
+
2054
+ // Output the ciphertext C
2055
+
2056
+ return $c;
2057
+ }
2058
+
2059
+ /**
2060
+ * RSAES-OAEP-DECRYPT
2061
+ *
2062
+ * See {@link http://tools.ietf.org/html/rfc3447#section-7.1.2 RFC3447#section-7.1.2}. The fact that the error
2063
+ * messages aren't distinguishable from one another hinders debugging, but, to quote from RFC3447#section-7.1.2:
2064
+ *
2065
+ * Note. Care must be taken to ensure that an opponent cannot
2066
+ * distinguish the different error conditions in Step 3.g, whether by
2067
+ * error message or timing, or, more generally, learn partial
2068
+ * information about the encoded message EM. Otherwise an opponent may
2069
+ * be able to obtain useful information about the decryption of the
2070
+ * ciphertext C, leading to a chosen-ciphertext attack such as the one
2071
+ * observed by Manger [36].
2072
+ *
2073
+ * As for $l... to quote from {@link http://tools.ietf.org/html/rfc3447#page-17 RFC3447#page-17}:
2074
+ *
2075
+ * Both the encryption and the decryption operations of RSAES-OAEP take
2076
+ * the value of a label L as input. In this version of PKCS #1, L is
2077
+ * the empty string; other uses of the label are outside the scope of
2078
+ * this document.
2079
+ *
2080
+ * @access private
2081
+ * @param String $c
2082
+ * @param String $l
2083
+ * @return String
2084
+ */
2085
+ function _rsaes_oaep_decrypt($c, $l = '')
2086
+ {
2087
+ // Length checking
2088
+
2089
+ // if $l is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
2090
+ // be output.
2091
+
2092
+ if (strlen($c) != $this->k || $this->k < 2 * $this->hLen + 2) {
2093
+ user_error('Decryption error');
2094
+ return false;
2095
+ }
2096
+
2097
+ // RSA decryption
2098
+
2099
+ $c = $this->_os2ip($c);
2100
+ $m = $this->_rsadp($c);
2101
+ if ($m === false) {
2102
+ user_error('Decryption error');
2103
+ return false;
2104
+ }
2105
+ $em = $this->_i2osp($m, $this->k);
2106
+
2107
+ // EME-OAEP decoding
2108
+
2109
+ $lHash = $this->hash->hash($l);
2110
+ $y = ord($em[0]);
2111
+ $maskedSeed = substr($em, 1, $this->hLen);
2112
+ $maskedDB = substr($em, $this->hLen + 1);
2113
+ $seedMask = $this->_mgf1($maskedDB, $this->hLen);
2114
+ $seed = $maskedSeed ^ $seedMask;
2115
+ $dbMask = $this->_mgf1($seed, $this->k - $this->hLen - 1);
2116
+ $db = $maskedDB ^ $dbMask;
2117
+ $lHash2 = substr($db, 0, $this->hLen);
2118
+ $m = substr($db, $this->hLen);
2119
+ if ($lHash != $lHash2) {
2120
+ user_error('Decryption error');
2121
+ return false;
2122
+ }
2123
+ $m = ltrim($m, chr(0));
2124
+ if (ord($m[0]) != 1) {
2125
+ user_error('Decryption error');
2126
+ return false;
2127
+ }
2128
+
2129
+ // Output the message M
2130
+
2131
+ return substr($m, 1);
2132
+ }
2133
+
2134
+ /**
2135
+ * RSAES-PKCS1-V1_5-ENCRYPT
2136
+ *
2137
+ * See {@link http://tools.ietf.org/html/rfc3447#section-7.2.1 RFC3447#section-7.2.1}.
2138
+ *
2139
+ * @access private
2140
+ * @param String $m
2141
+ * @return String
2142
+ */
2143
+ function _rsaes_pkcs1_v1_5_encrypt($m)
2144
+ {
2145
+ $mLen = strlen($m);
2146
+
2147
+ // Length checking
2148
+
2149
+ if ($mLen > $this->k - 11) {
2150
+ user_error('Message too long');
2151
+ return false;
2152
+ }
2153
+
2154
+ // EME-PKCS1-v1_5 encoding
2155
+
2156
+ $psLen = $this->k - $mLen - 3;
2157
+ $ps = '';
2158
+ while (strlen($ps) != $psLen) {
2159
+ $temp = crypt_random_string($psLen - strlen($ps));
2160
+ $temp = str_replace("\x00", '', $temp);
2161
+ $ps.= $temp;
2162
+ }
2163
+ $type = 2;
2164
+ // see the comments of _rsaes_pkcs1_v1_5_decrypt() to understand why this is being done
2165
+ if (defined('CRYPT_RSA_PKCS15_COMPAT') && (!isset($this->publicExponent) || $this->exponent !== $this->publicExponent)) {
2166
+ $type = 1;
2167
+ // "The padding string PS shall consist of k-3-||D|| octets. ... for block type 01, they shall have value FF"
2168
+ $ps = str_repeat("\xFF", $psLen);
2169
+ }
2170
+ $em = chr(0) . chr($type) . $ps . chr(0) . $m;
2171
+
2172
+ // RSA encryption
2173
+ $m = $this->_os2ip($em);
2174
+ $c = $this->_rsaep($m);
2175
+ $c = $this->_i2osp($c, $this->k);
2176
+
2177
+ // Output the ciphertext C
2178
+
2179
+ return $c;
2180
+ }
2181
+
2182
+ /**
2183
+ * RSAES-PKCS1-V1_5-DECRYPT
2184
+ *
2185
+ * See {@link http://tools.ietf.org/html/rfc3447#section-7.2.2 RFC3447#section-7.2.2}.
2186
+ *
2187
+ * For compatability purposes, this function departs slightly from the description given in RFC3447.
2188
+ * The reason being that RFC2313#section-8.1 (PKCS#1 v1.5) states that ciphertext's encrypted by the
2189
+ * private key should have the second byte set to either 0 or 1 and that ciphertext's encrypted by the
2190
+ * public key should have the second byte set to 2. In RFC3447 (PKCS#1 v2.1), the second byte is supposed
2191
+ * to be 2 regardless of which key is used. For compatability purposes, we'll just check to make sure the
2192
+ * second byte is 2 or less. If it is, we'll accept the decrypted string as valid.
2193
+ *
2194
+ * As a consequence of this, a private key encrypted ciphertext produced with Crypt_RSA may not decrypt
2195
+ * with a strictly PKCS#1 v1.5 compliant RSA implementation. Public key encrypted ciphertext's should but
2196
+ * not private key encrypted ciphertext's.
2197
+ *
2198
+ * @access private
2199
+ * @param String $c
2200
+ * @return String
2201
+ */
2202
+ function _rsaes_pkcs1_v1_5_decrypt($c)
2203
+ {
2204
+ // Length checking
2205
+
2206
+ if (strlen($c) != $this->k) { // or if k < 11
2207
+ user_error('Decryption error');
2208
+ return false;
2209
+ }
2210
+
2211
+ // RSA decryption
2212
+
2213
+ $c = $this->_os2ip($c);
2214
+ $m = $this->_rsadp($c);
2215
+
2216
+ if ($m === false) {
2217
+ user_error('Decryption error');
2218
+ return false;
2219
+ }
2220
+ $em = $this->_i2osp($m, $this->k);
2221
+
2222
+ // EME-PKCS1-v1_5 decoding
2223
+
2224
+ if (ord($em[0]) != 0 || ord($em[1]) > 2) {
2225
+ user_error('Decryption error');
2226
+ return false;
2227
+ }
2228
+
2229
+ $ps = substr($em, 2, strpos($em, chr(0), 2) - 2);
2230
+ $m = substr($em, strlen($ps) + 3);
2231
+
2232
+ if (strlen($ps) < 8) {
2233
+ user_error('Decryption error');
2234
+ return false;
2235
+ }
2236
+
2237
+ // Output M
2238
+
2239
+ return $m;
2240
+ }
2241
+
2242
+ /**
2243
+ * EMSA-PSS-ENCODE
2244
+ *
2245
+ * See {@link http://tools.ietf.org/html/rfc3447#section-9.1.1 RFC3447#section-9.1.1}.
2246
+ *
2247
+ * @access private
2248
+ * @param String $m
2249
+ * @param Integer $emBits
2250
+ */
2251
+ function _emsa_pss_encode($m, $emBits)
2252
+ {
2253
+ // if $m is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
2254
+ // be output.
2255
+
2256
+ $emLen = ($emBits + 1) >> 3; // ie. ceil($emBits / 8)
2257
+ $sLen = $this->sLen == false ? $this->hLen : $this->sLen;
2258
+
2259
+ $mHash = $this->hash->hash($m);
2260
+ if ($emLen < $this->hLen + $sLen + 2) {
2261
+ user_error('Encoding error');
2262
+ return false;
2263
+ }
2264
+
2265
+ $salt = crypt_random_string($sLen);
2266
+ $m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt;
2267
+ $h = $this->hash->hash($m2);
2268
+ $ps = str_repeat(chr(0), $emLen - $sLen - $this->hLen - 2);
2269
+ $db = $ps . chr(1) . $salt;
2270
+ $dbMask = $this->_mgf1($h, $emLen - $this->hLen - 1);
2271
+ $maskedDB = $db ^ $dbMask;
2272
+ $maskedDB[0] = ~chr(0xFF << ($emBits & 7)) & $maskedDB[0];
2273
+ $em = $maskedDB . $h . chr(0xBC);
2274
+
2275
+ return $em;
2276
+ }
2277
+
2278
+ /**
2279
+ * EMSA-PSS-VERIFY
2280
+ *
2281
+ * See {@link http://tools.ietf.org/html/rfc3447#section-9.1.2 RFC3447#section-9.1.2}.
2282
+ *
2283
+ * @access private
2284
+ * @param String $m
2285
+ * @param String $em
2286
+ * @param Integer $emBits
2287
+ * @return String
2288
+ */
2289
+ function _emsa_pss_verify($m, $em, $emBits)
2290
+ {
2291
+ // if $m is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
2292
+ // be output.
2293
+
2294
+ $emLen = ($emBits + 1) >> 3; // ie. ceil($emBits / 8);
2295
+ $sLen = $this->sLen == false ? $this->hLen : $this->sLen;
2296
+
2297
+ $mHash = $this->hash->hash($m);
2298
+ if ($emLen < $this->hLen + $sLen + 2) {
2299
+ return false;
2300
+ }
2301
+
2302
+ if ($em[strlen($em) - 1] != chr(0xBC)) {
2303
+ return false;
2304
+ }
2305
+
2306
+ $maskedDB = substr($em, 0, -$this->hLen - 1);
2307
+ $h = substr($em, -$this->hLen - 1, $this->hLen);
2308
+ $temp = chr(0xFF << ($emBits & 7));
2309
+ if ((~$maskedDB[0] & $temp) != $temp) {
2310
+ return false;
2311
+ }
2312
+ $dbMask = $this->_mgf1($h, $emLen - $this->hLen - 1);
2313
+ $db = $maskedDB ^ $dbMask;
2314
+ $db[0] = ~chr(0xFF << ($emBits & 7)) & $db[0];
2315
+ $temp = $emLen - $this->hLen - $sLen - 2;
2316
+ if (substr($db, 0, $temp) != str_repeat(chr(0), $temp) || ord($db[$temp]) != 1) {
2317
+ return false;
2318
+ }
2319
+ $salt = substr($db, $temp + 1); // should be $sLen long
2320
+ $m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt;
2321
+ $h2 = $this->hash->hash($m2);
2322
+ return $this->_equals($h, $h2);
2323
+ }
2324
+
2325
+ /**
2326
+ * RSASSA-PSS-SIGN
2327
+ *
2328
+ * See {@link http://tools.ietf.org/html/rfc3447#section-8.1.1 RFC3447#section-8.1.1}.
2329
+ *
2330
+ * @access private
2331
+ * @param String $m
2332
+ * @return String
2333
+ */
2334
+ function _rsassa_pss_sign($m)
2335
+ {
2336
+ // EMSA-PSS encoding
2337
+
2338
+ $em = $this->_emsa_pss_encode($m, 8 * $this->k - 1);
2339
+
2340
+ // RSA signature
2341
+
2342
+ $m = $this->_os2ip($em);
2343
+ $s = $this->_rsasp1($m);
2344
+ $s = $this->_i2osp($s, $this->k);
2345
+
2346
+ // Output the signature S
2347
+
2348
+ return $s;
2349
+ }
2350
+
2351
+ /**
2352
+ * RSASSA-PSS-VERIFY
2353
+ *
2354
+ * See {@link http://tools.ietf.org/html/rfc3447#section-8.1.2 RFC3447#section-8.1.2}.
2355
+ *
2356
+ * @access private
2357
+ * @param String $m
2358
+ * @param String $s
2359
+ * @return String
2360
+ */
2361
+ function _rsassa_pss_verify($m, $s)
2362
+ {
2363
+ // Length checking
2364
+
2365
+ if (strlen($s) != $this->k) {
2366
+ user_error('Invalid signature');
2367
+ return false;
2368
+ }
2369
+
2370
+ // RSA verification
2371
+
2372
+ $modBits = 8 * $this->k;
2373
+
2374
+ $s2 = $this->_os2ip($s);
2375
+ $m2 = $this->_rsavp1($s2);
2376
+ if ($m2 === false) {
2377
+ user_error('Invalid signature');
2378
+ return false;
2379
+ }
2380
+ $em = $this->_i2osp($m2, $modBits >> 3);
2381
+ if ($em === false) {
2382
+ user_error('Invalid signature');
2383
+ return false;
2384
+ }
2385
+
2386
+ // EMSA-PSS verification
2387
+
2388
+ return $this->_emsa_pss_verify($m, $em, $modBits - 1);
2389
+ }
2390
+
2391
+ /**
2392
+ * EMSA-PKCS1-V1_5-ENCODE
2393
+ *
2394
+ * See {@link http://tools.ietf.org/html/rfc3447#section-9.2 RFC3447#section-9.2}.
2395
+ *
2396
+ * @access private
2397
+ * @param String $m
2398
+ * @param Integer $emLen
2399
+ * @return String
2400
+ */
2401
+ function _emsa_pkcs1_v1_5_encode($m, $emLen)
2402
+ {
2403
+ $h = $this->hash->hash($m);
2404
+ if ($h === false) {
2405
+ return false;
2406
+ }
2407
+
2408
+ // see http://tools.ietf.org/html/rfc3447#page-43
2409
+ switch ($this->hashName) {
2410
+ case 'md2':
2411
+ $t = pack('H*', '3020300c06082a864886f70d020205000410');
2412
+ break;
2413
+ case 'md5':
2414
+ $t = pack('H*', '3020300c06082a864886f70d020505000410');
2415
+ break;
2416
+ case 'sha1':
2417
+ $t = pack('H*', '3021300906052b0e03021a05000414');
2418
+ break;
2419
+ case 'sha256':
2420
+ $t = pack('H*', '3031300d060960864801650304020105000420');
2421
+ break;
2422
+ case 'sha384':
2423
+ $t = pack('H*', '3041300d060960864801650304020205000430');
2424
+ break;
2425
+ case 'sha512':
2426
+ $t = pack('H*', '3051300d060960864801650304020305000440');
2427
+ }
2428
+ $t.= $h;
2429
+ $tLen = strlen($t);
2430
+
2431
+ if ($emLen < $tLen + 11) {
2432
+ user_error('Intended encoded message length too short');
2433
+ return false;
2434
+ }
2435
+
2436
+ $ps = str_repeat(chr(0xFF), $emLen - $tLen - 3);
2437
+
2438
+ $em = "\0\1$ps\0$t";
2439
+
2440
+ return $em;
2441
+ }
2442
+
2443
+ /**
2444
+ * RSASSA-PKCS1-V1_5-SIGN
2445
+ *
2446
+ * See {@link http://tools.ietf.org/html/rfc3447#section-8.2.1 RFC3447#section-8.2.1}.
2447
+ *
2448
+ * @access private
2449
+ * @param String $m
2450
+ * @return String
2451
+ */
2452
+ function _rsassa_pkcs1_v1_5_sign($m)
2453
+ {
2454
+ // EMSA-PKCS1-v1_5 encoding
2455
+
2456
+ $em = $this->_emsa_pkcs1_v1_5_encode($m, $this->k);
2457
+ if ($em === false) {
2458
+ user_error('RSA modulus too short');
2459
+ return false;
2460
+ }
2461
+
2462
+ // RSA signature
2463
+
2464
+ $m = $this->_os2ip($em);
2465
+ $s = $this->_rsasp1($m);
2466
+ $s = $this->_i2osp($s, $this->k);
2467
+
2468
+ // Output the signature S
2469
+
2470
+ return $s;
2471
+ }
2472
+
2473
+ /**
2474
+ * RSASSA-PKCS1-V1_5-VERIFY
2475
+ *
2476
+ * See {@link http://tools.ietf.org/html/rfc3447#section-8.2.2 RFC3447#section-8.2.2}.
2477
+ *
2478
+ * @access private
2479
+ * @param String $m
2480
+ * @return String
2481
+ */
2482
+ function _rsassa_pkcs1_v1_5_verify($m, $s)
2483
+ {
2484
+ // Length checking
2485
+
2486
+ if (strlen($s) != $this->k) {
2487
+ user_error('Invalid signature');
2488
+ return false;
2489
+ }
2490
+
2491
+ // RSA verification
2492
+
2493
+ $s = $this->_os2ip($s);
2494
+ $m2 = $this->_rsavp1($s);
2495
+ if ($m2 === false) {
2496
+ user_error('Invalid signature');
2497
+ return false;
2498
+ }
2499
+ $em = $this->_i2osp($m2, $this->k);
2500
+ if ($em === false) {
2501
+ user_error('Invalid signature');
2502
+ return false;
2503
+ }
2504
+
2505
+ // EMSA-PKCS1-v1_5 encoding
2506
+
2507
+ $em2 = $this->_emsa_pkcs1_v1_5_encode($m, $this->k);
2508
+ if ($em2 === false) {
2509
+ user_error('RSA modulus too short');
2510
+ return false;
2511
+ }
2512
+
2513
+ // Compare
2514
+ return $this->_equals($em, $em2);
2515
+ }
2516
+
2517
+ /**
2518
+ * Set Encryption Mode
2519
+ *
2520
+ * Valid values include CRYPT_RSA_ENCRYPTION_OAEP and CRYPT_RSA_ENCRYPTION_PKCS1.
2521
+ *
2522
+ * @access public
2523
+ * @param Integer $mode
2524
+ */
2525
+ function setEncryptionMode($mode)
2526
+ {
2527
+ $this->encryptionMode = $mode;
2528
+ }
2529
+
2530
+ /**
2531
+ * Set Signature Mode
2532
+ *
2533
+ * Valid values include CRYPT_RSA_SIGNATURE_PSS and CRYPT_RSA_SIGNATURE_PKCS1
2534
+ *
2535
+ * @access public
2536
+ * @param Integer $mode
2537
+ */
2538
+ function setSignatureMode($mode)
2539
+ {
2540
+ $this->signatureMode = $mode;
2541
+ }
2542
+
2543
+ /**
2544
+ * Set public key comment.
2545
+ *
2546
+ * @access public
2547
+ * @param String $comment
2548
+ */
2549
+ function setComment($comment)
2550
+ {
2551
+ $this->comment = $comment;
2552
+ }
2553
+
2554
+ /**
2555
+ * Get public key comment.
2556
+ *
2557
+ * @access public
2558
+ * @return String
2559
+ */
2560
+ function getComment()
2561
+ {
2562
+ return $this->comment;
2563
+ }
2564
+
2565
+ /**
2566
+ * Encryption
2567
+ *
2568
+ * Both CRYPT_RSA_ENCRYPTION_OAEP and CRYPT_RSA_ENCRYPTION_PKCS1 both place limits on how long $plaintext can be.
2569
+ * If $plaintext exceeds those limits it will be broken up so that it does and the resultant ciphertext's will
2570
+ * be concatenated together.
2571
+ *
2572
+ * @see decrypt()
2573
+ * @access public
2574
+ * @param String $plaintext
2575
+ * @return String
2576
+ */
2577
+ function encrypt($plaintext)
2578
+ {
2579
+ switch ($this->encryptionMode) {
2580
+ case CRYPT_RSA_ENCRYPTION_PKCS1:
2581
+ $length = $this->k - 11;
2582
+ if ($length <= 0) {
2583
+ return false;
2584
+ }
2585
+
2586
+ $plaintext = str_split($plaintext, $length);
2587
+ $ciphertext = '';
2588
+ foreach ($plaintext as $m) {
2589
+ $ciphertext.= $this->_rsaes_pkcs1_v1_5_encrypt($m);
2590
+ }
2591
+ return $ciphertext;
2592
+ //case CRYPT_RSA_ENCRYPTION_OAEP:
2593
+ default:
2594
+ $length = $this->k - 2 * $this->hLen - 2;
2595
+ if ($length <= 0) {
2596
+ return false;
2597
+ }
2598
+
2599
+ $plaintext = str_split($plaintext, $length);
2600
+ $ciphertext = '';
2601
+ foreach ($plaintext as $m) {
2602
+ $ciphertext.= $this->_rsaes_oaep_encrypt($m);
2603
+ }
2604
+ return $ciphertext;
2605
+ }
2606
+ }
2607
+
2608
+ /**
2609
+ * Decryption
2610
+ *
2611
+ * @see encrypt()
2612
+ * @access public
2613
+ * @param String $plaintext
2614
+ * @return String
2615
+ */
2616
+ function decrypt($ciphertext)
2617
+ {
2618
+ if ($this->k <= 0) {
2619
+ return false;
2620
+ }
2621
+
2622
+ $ciphertext = str_split($ciphertext, $this->k);
2623
+ $ciphertext[count($ciphertext) - 1] = str_pad($ciphertext[count($ciphertext) - 1], $this->k, chr(0), STR_PAD_LEFT);
2624
+
2625
+ $plaintext = '';
2626
+
2627
+ switch ($this->encryptionMode) {
2628
+ case CRYPT_RSA_ENCRYPTION_PKCS1:
2629
+ $decrypt = '_rsaes_pkcs1_v1_5_decrypt';
2630
+ break;
2631
+ //case CRYPT_RSA_ENCRYPTION_OAEP:
2632
+ default:
2633
+ $decrypt = '_rsaes_oaep_decrypt';
2634
+ }
2635
+
2636
+ foreach ($ciphertext as $c) {
2637
+ $temp = $this->$decrypt($c);
2638
+ if ($temp === false) {
2639
+ return false;
2640
+ }
2641
+ $plaintext.= $temp;
2642
+ }
2643
+
2644
+ return $plaintext;
2645
+ }
2646
+
2647
+ /**
2648
+ * Create a signature
2649
+ *
2650
+ * @see verify()
2651
+ * @access public
2652
+ * @param String $message
2653
+ * @return String
2654
+ */
2655
+ function sign($message)
2656
+ {
2657
+ if (empty($this->modulus) || empty($this->exponent)) {
2658
+ return false;
2659
+ }
2660
+
2661
+ switch ($this->signatureMode) {
2662
+ case CRYPT_RSA_SIGNATURE_PKCS1:
2663
+ return $this->_rsassa_pkcs1_v1_5_sign($message);
2664
+ //case CRYPT_RSA_SIGNATURE_PSS:
2665
+ default:
2666
+ return $this->_rsassa_pss_sign($message);
2667
+ }
2668
+ }
2669
+
2670
+ /**
2671
+ * Verifies a signature
2672
+ *
2673
+ * @see sign()
2674
+ * @access public
2675
+ * @param String $message
2676
+ * @param String $signature
2677
+ * @return Boolean
2678
+ */
2679
+ function verify($message, $signature)
2680
+ {
2681
+ if (empty($this->modulus) || empty($this->exponent)) {
2682
+ return false;
2683
+ }
2684
+
2685
+ switch ($this->signatureMode) {
2686
+ case CRYPT_RSA_SIGNATURE_PKCS1:
2687
+ return $this->_rsassa_pkcs1_v1_5_verify($message, $signature);
2688
+ //case CRYPT_RSA_SIGNATURE_PSS:
2689
+ default:
2690
+ return $this->_rsassa_pss_verify($message, $signature);
2691
+ }
2692
+ }
2693
+ }
modules/phpseclib/Crypt/Random.php ADDED
@@ -0,0 +1,249 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3
+
4
+ /**
5
+ * Random Number Generator
6
+ *
7
+ * PHP versions 4 and 5
8
+ *
9
+ * Here's a short example of how to use this library:
10
+ * <code>
11
+ * <?php
12
+ * include('Crypt/Random.php');
13
+ *
14
+ * echo bin2hex(crypt_random_string(8));
15
+ * ?>
16
+ * </code>
17
+ *
18
+ * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
19
+ * of this software and associated documentation files (the "Software"), to deal
20
+ * in the Software without restriction, including without limitation the rights
21
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
22
+ * copies of the Software, and to permit persons to whom the Software is
23
+ * furnished to do so, subject to the following conditions:
24
+ *
25
+ * The above copyright notice and this permission notice shall be included in
26
+ * all copies or substantial portions of the Software.
27
+ *
28
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
29
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
30
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
31
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
32
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
33
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
34
+ * THE SOFTWARE.
35
+ *
36
+ * @category Crypt
37
+ * @package Crypt_Random
38
+ * @author Jim Wigginton <terrafrost@php.net>
39
+ * @copyright MMVII Jim Wigginton
40
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
41
+ * @link http://phpseclib.sourceforge.net
42
+ */
43
+
44
+ /**
45
+ * "Is Windows" test
46
+ *
47
+ * @access private
48
+ */
49
+ define('CRYPT_RANDOM_IS_WINDOWS', strtoupper(substr(PHP_OS, 0, 3)) === 'WIN');
50
+
51
+ /**
52
+ * Generate a random string.
53
+ *
54
+ * Although microoptimizations are generally discouraged as they impair readability this function is ripe with
55
+ * microoptimizations because this function has the potential of being called a huge number of times.
56
+ * eg. for RSA key generation.
57
+ *
58
+ * @param Integer $length
59
+ * @return String
60
+ * @access public
61
+ */
62
+ function crypt_random_string($length)
63
+ {
64
+ if (CRYPT_RANDOM_IS_WINDOWS) {
65
+ // method 1. prior to PHP 5.3 this would call rand() on windows hence the function_exists('class_alias') call.
66
+ // ie. class_alias is a function that was introduced in PHP 5.3
67
+ if (function_exists('mcrypt_create_iv') && function_exists('class_alias')) {
68
+ return mcrypt_create_iv($length);
69
+ }
70
+ // method 2. openssl_random_pseudo_bytes was introduced in PHP 5.3.0 but prior to PHP 5.3.4 there was,
71
+ // to quote <http://php.net/ChangeLog-5.php#5.3.4>, "possible blocking behavior". as of 5.3.4
72
+ // openssl_random_pseudo_bytes and mcrypt_create_iv do the exact same thing on Windows. ie. they both
73
+ // call php_win32_get_random_bytes():
74
+ //
75
+ // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/openssl/openssl.c#L5008
76
+ // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/mcrypt/mcrypt.c#L1392
77
+ //
78
+ // php_win32_get_random_bytes() is defined thusly:
79
+ //
80
+ // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/win32/winutil.c#L80
81
+ //
82
+ // we're calling it, all the same, in the off chance that the mcrypt extension is not available
83
+ if (function_exists('openssl_random_pseudo_bytes') && version_compare(PHP_VERSION, '5.3.4', '>=')) {
84
+ return openssl_random_pseudo_bytes($length);
85
+ }
86
+ } else {
87
+ // method 1. the fastest
88
+ if (function_exists('openssl_random_pseudo_bytes')) {
89
+ return openssl_random_pseudo_bytes($length);
90
+ }
91
+ // method 2
92
+ static $fp = true;
93
+ if ($fp === true) {
94
+ // warning's will be output unles the error suppression operator is used. errors such as
95
+ // "open_basedir restriction in effect", "Permission denied", "No such file or directory", etc.
96
+ $fp = @fopen('/dev/urandom', 'rb');
97
+ }
98
+ if ($fp !== true && $fp !== false) { // surprisingly faster than !is_bool() or is_resource()
99
+ return fread($fp, $length);
100
+ }
101
+ // method 3. pretty much does the same thing as method 2 per the following url:
102
+ // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/mcrypt/mcrypt.c#L1391
103
+ // surprisingly slower than method 2. maybe that's because mcrypt_create_iv does a bunch of error checking that we're
104
+ // not doing. regardless, this'll only be called if this PHP script couldn't open /dev/urandom due to open_basedir
105
+ // restrictions or some such
106
+ if (function_exists('mcrypt_create_iv')) {
107
+ return mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
108
+ }
109
+ }
110
+ // at this point we have no choice but to use a pure-PHP CSPRNG
111
+
112
+ // cascade entropy across multiple PHP instances by fixing the session and collecting all
113
+ // environmental variables, including the previous session data and the current session
114
+ // data.
115
+ //
116
+ // mt_rand seeds itself by looking at the PID and the time, both of which are (relatively)
117
+ // easy to guess at. linux uses mouse clicks, keyboard timings, etc, as entropy sources, but
118
+ // PHP isn't low level to be able to use those as sources and on a web server there's not likely
119
+ // going to be a ton of keyboard or mouse action. web servers do have one thing that we can use
120
+ // however. a ton of people visiting the website. obviously you don't want to base your seeding
121
+ // soley on parameters a potential attacker sends but (1) not everything in $_SERVER is controlled
122
+ // by the user and (2) this isn't just looking at the data sent by the current user - it's based
123
+ // on the data sent by all users. one user requests the page and a hash of their info is saved.
124
+ // another user visits the page and the serialization of their data is utilized along with the
125
+ // server envirnment stuff and a hash of the previous http request data (which itself utilizes
126
+ // a hash of the session data before that). certainly an attacker should be assumed to have
127
+ // full control over his own http requests. he, however, is not going to have control over
128
+ // everyone's http requests.
129
+ static $crypto = false, $v;
130
+ if ($crypto === false) {
131
+ // save old session data
132
+ $old_session_id = session_id();
133
+ $old_use_cookies = ini_get('session.use_cookies');
134
+ $old_session_cache_limiter = session_cache_limiter();
135
+ if (isset($_SESSION)) {
136
+ $_OLD_SESSION = $_SESSION;
137
+ }
138
+ if ($old_session_id != '') {
139
+ session_write_close();
140
+ }
141
+
142
+ session_id(1);
143
+ ini_set('session.use_cookies', 0);
144
+ session_cache_limiter('');
145
+ session_start();
146
+
147
+ $v = $seed = $_SESSION['seed'] = pack('H*', sha1(
148
+ serialize($_SERVER) .
149
+ serialize($_POST) .
150
+ serialize($_GET) .
151
+ serialize($_COOKIE) .
152
+ serialize($GLOBALS) .
153
+ serialize($_SESSION) .
154
+ serialize($_OLD_SESSION)
155
+ ));
156
+ if (!isset($_SESSION['count'])) {
157
+ $_SESSION['count'] = 0;
158
+ }
159
+ $_SESSION['count']++;
160
+
161
+ session_write_close();
162
+
163
+ // restore old session data
164
+ if ($old_session_id != '') {
165
+ session_id($old_session_id);
166
+ session_start();
167
+ ini_set('session.use_cookies', $old_use_cookies);
168
+ session_cache_limiter($old_session_cache_limiter);
169
+ } else {
170
+ if (isset($_OLD_SESSION)) {
171
+ $_SESSION = $_OLD_SESSION;
172
+ unset($_OLD_SESSION);
173
+ } else {
174
+ unset($_SESSION);
175
+ }
176
+ }
177
+
178
+ // in SSH2 a shared secret and an exchange hash are generated through the key exchange process.
179
+ // the IV client to server is the hash of that "nonce" with the letter A and for the encryption key it's the letter C.
180
+ // if the hash doesn't produce enough a key or an IV that's long enough concat successive hashes of the
181
+ // original hash and the current hash. we'll be emulating that. for more info see the following URL:
182
+ //
183
+ // http://tools.ietf.org/html/rfc4253#section-7.2
184
+ //
185
+ // see the is_string($crypto) part for an example of how to expand the keys
186
+ $key = pack('H*', sha1($seed . 'A'));
187
+ $iv = pack('H*', sha1($seed . 'C'));
188
+
189
+ // ciphers are used as per the nist.gov link below. also, see this link:
190
+ //
191
+ // http://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator#Designs_based_on_cryptographic_primitives
192
+ switch (true) {
193
+ case class_exists('Crypt_AES'):
194
+ $crypto = new Crypt_AES(CRYPT_AES_MODE_CTR);
195
+ break;
196
+ case class_exists('Crypt_TripleDES'):
197
+ $crypto = new Crypt_TripleDES(CRYPT_DES_MODE_CTR);
198
+ break;
199
+ case class_exists('Crypt_DES'):
200
+ $crypto = new Crypt_DES(CRYPT_DES_MODE_CTR);
201
+ break;
202
+ case class_exists('Crypt_RC4'):
203
+ $crypto = new Crypt_RC4();
204
+ break;
205
+ default:
206
+ $crypto = $seed;
207
+ return crypt_random_string($length);
208
+ }
209
+
210
+ $crypto->setKey($key);
211
+ $crypto->setIV($iv);
212
+ $crypto->enableContinuousBuffer();
213
+ }
214
+
215
+ if (is_string($crypto)) {
216
+ // the following is based off of ANSI X9.31:
217
+ //
218
+ // http://csrc.nist.gov/groups/STM/cavp/documents/rng/931rngext.pdf
219
+ //
220
+ // OpenSSL uses that same standard for it's random numbers:
221
+ //
222
+ // http://www.opensource.apple.com/source/OpenSSL/OpenSSL-38/openssl/fips-1.0/rand/fips_rand.c
223
+ // (do a search for "ANS X9.31 A.2.4")
224
+ //
225
+ // ANSI X9.31 recommends ciphers be used and phpseclib does use them if they're available (see
226
+ // later on in the code) but if they're not we'll use sha1
227
+ $result = '';
228
+ while (strlen($result) < $length) { // each loop adds 20 bytes
229
+ // microtime() isn't packed as "densely" as it could be but then neither is that the idea.
230
+ // the idea is simply to ensure that each "block" has a unique element to it.
231
+ $i = pack('H*', sha1(microtime()));
232
+ $r = pack('H*', sha1($i ^ $v));
233
+ $v = pack('H*', sha1($r ^ $i));
234
+ $result.= $r;
235
+ }
236
+ return substr($result, 0, $length);
237
+ }
238
+
239
+ //return $crypto->encrypt(str_repeat("\0", $length));
240
+
241
+ $result = '';
242
+ while (strlen($result) < $length) {
243
+ $i = $crypto->encrypt(microtime());
244
+ $r = $crypto->encrypt($i ^ $v);
245
+ $v = $crypto->encrypt($r ^ $i);
246
+ $result.= $r;
247
+ }
248
+ return substr($result, 0, $length);
249
+ }
modules/phpseclib/Crypt/Rijndael.php ADDED
@@ -0,0 +1,2062 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3
+
4
+ /**
5
+ * Pure-PHP implementation of Rijndael.
6
+ *
7
+ * Does not use mcrypt, even when available, for reasons that are explained below.
8
+ *
9
+ * PHP versions 4 and 5
10
+ *
11
+ * If {@link Crypt_Rijndael::setBlockLength() setBlockLength()} isn't called, it'll be assumed to be 128 bits. If
12
+ * {@link Crypt_Rijndael::setKeyLength() setKeyLength()} isn't called, it'll be calculated from
13
+ * {@link Crypt_Rijndael::setKey() setKey()}. ie. if the key is 128-bits, the key length will be 128-bits. If it's
14
+ * 136-bits it'll be null-padded to 160-bits and 160 bits will be the key length until
15
+ * {@link Crypt_Rijndael::setKey() setKey()} is called, again, at which point, it'll be recalculated.
16
+ *
17
+ * Not all Rijndael implementations may support 160-bits or 224-bits as the block length / key length. mcrypt, for example,
18
+ * does not. AES, itself, only supports block lengths of 128 and key lengths of 128, 192, and 256.
19
+ * {@link http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=10 Rijndael-ammended.pdf#page=10} defines the
20
+ * algorithm for block lengths of 192 and 256 but not for block lengths / key lengths of 160 and 224. Indeed, 160 and 224
21
+ * are first defined as valid key / block lengths in
22
+ * {@link http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=44 Rijndael-ammended.pdf#page=44}:
23
+ * Extensions: Other block and Cipher Key lengths.
24
+ *
25
+ * {@internal The variable names are the same as those in
26
+ * {@link http://www.csrc.nist.gov/publications/fips/fips197/fips-197.pdf#page=10 fips-197.pdf#page=10}.}}
27
+ *
28
+ * Here's a short example of how to use this library:
29
+ * <code>
30
+ * <?php
31
+ * include('Crypt/Rijndael.php');
32
+ *
33
+ * $rijndael = new Crypt_Rijndael();
34
+ *
35
+ * $rijndael->setKey('abcdefghijklmnop');
36
+ *
37
+ * $size = 10 * 1024;
38
+ * $plaintext = '';
39
+ * for ($i = 0; $i < $size; $i++) {
40
+ * $plaintext.= 'a';
41
+ * }
42
+ *
43
+ * echo $rijndael->decrypt($rijndael->encrypt($plaintext));
44
+ * ?>
45
+ * </code>
46
+ *
47
+ * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
48
+ * of this software and associated documentation files (the "Software"), to deal
49
+ * in the Software without restriction, including without limitation the rights
50
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
51
+ * copies of the Software, and to permit persons to whom the Software is
52
+ * furnished to do so, subject to the following conditions:
53
+ *
54
+ * The above copyright notice and this permission notice shall be included in
55
+ * all copies or substantial portions of the Software.
56
+ *
57
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
58
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
59
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
60
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
61
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
62
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
63
+ * THE SOFTWARE.
64
+ *
65
+ * @category Crypt
66
+ * @package Crypt_Rijndael
67
+ * @author Jim Wigginton <terrafrost@php.net>
68
+ * @copyright MMVIII Jim Wigginton
69
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
70
+ * @link http://phpseclib.sourceforge.net
71
+ */
72
+
73
+ /**#@+
74
+ * @access public
75
+ * @see Crypt_Rijndael::encrypt()
76
+ * @see Crypt_Rijndael::decrypt()
77
+ */
78
+ /**
79
+ * Encrypt / decrypt using the Counter mode.
80
+ *
81
+ * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
82
+ *
83
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
84
+ */
85
+ define('CRYPT_RIJNDAEL_MODE_CTR', -1);
86
+ /**
87
+ * Encrypt / decrypt using the Electronic Code Book mode.
88
+ *
89
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
90
+ */
91
+ define('CRYPT_RIJNDAEL_MODE_ECB', 1);
92
+ /**
93
+ * Encrypt / decrypt using the Code Book Chaining mode.
94
+ *
95
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
96
+ */
97
+ define('CRYPT_RIJNDAEL_MODE_CBC', 2);
98
+ /**
99
+ * Encrypt / decrypt using the Cipher Feedback mode.
100
+ *
101
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
102
+ */
103
+ define('CRYPT_RIJNDAEL_MODE_CFB', 3);
104
+ /**
105
+ * Encrypt / decrypt using the Cipher Feedback mode.
106
+ *
107
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
108
+ */
109
+ define('CRYPT_RIJNDAEL_MODE_OFB', 4);
110
+ /**#@-*/
111
+
112
+ /**#@+
113
+ * @access private
114
+ * @see Crypt_Rijndael::Crypt_Rijndael()
115
+ */
116
+ /**
117
+ * Toggles the internal implementation
118
+ */
119
+ define('CRYPT_RIJNDAEL_MODE_INTERNAL', 1);
120
+ /**
121
+ * Toggles the mcrypt implementation
122
+ */
123
+ define('CRYPT_RIJNDAEL_MODE_MCRYPT', 2);
124
+ /**#@-*/
125
+
126
+ /**
127
+ * Pure-PHP implementation of Rijndael.
128
+ *
129
+ * @author Jim Wigginton <terrafrost@php.net>
130
+ * @version 0.1.0
131
+ * @access public
132
+ * @package Crypt_Rijndael
133
+ */
134
+ class Crypt_Rijndael {
135
+ /**
136
+ * The Encryption Mode
137
+ *
138
+ * @see Crypt_Rijndael::Crypt_Rijndael()
139
+ * @var Integer
140
+ * @access private
141
+ */
142
+ var $mode;
143
+
144
+ /**
145
+ * The Key
146
+ *
147
+ * @see Crypt_Rijndael::setKey()
148
+ * @var String
149
+ * @access private
150
+ */
151
+ var $key = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
152
+
153
+ /**
154
+ * The Initialization Vector
155
+ *
156
+ * @see Crypt_Rijndael::setIV()
157
+ * @var String
158
+ * @access private
159
+ */
160
+ var $iv = '';
161
+
162
+ /**
163
+ * A "sliding" Initialization Vector
164
+ *
165
+ * @see Crypt_Rijndael::enableContinuousBuffer()
166
+ * @var String
167
+ * @access private
168
+ */
169
+ var $encryptIV = '';
170
+
171
+ /**
172
+ * A "sliding" Initialization Vector
173
+ *
174
+ * @see Crypt_Rijndael::enableContinuousBuffer()
175
+ * @var String
176
+ * @access private
177
+ */
178
+ var $decryptIV = '';
179
+
180
+ /**
181
+ * Continuous Buffer status
182
+ *
183
+ * @see Crypt_Rijndael::enableContinuousBuffer()
184
+ * @var Boolean
185
+ * @access private
186
+ */
187
+ var $continuousBuffer = false;
188
+
189
+ /**
190
+ * Padding status
191
+ *
192
+ * @see Crypt_Rijndael::enablePadding()
193
+ * @var Boolean
194
+ * @access private
195
+ */
196
+ var $padding = true;
197
+
198
+ /**
199
+ * Does the key schedule need to be (re)calculated?
200
+ *
201
+ * @see setKey()
202
+ * @see setBlockLength()
203
+ * @see setKeyLength()
204
+ * @var Boolean
205
+ * @access private
206
+ */
207
+ var $changed = true;
208
+
209
+ /**
210
+ * Has the key length explicitly been set or should it be derived from the key, itself?
211
+ *
212
+ * @see setKeyLength()
213
+ * @var Boolean
214
+ * @access private
215
+ */
216
+ var $explicit_key_length = false;
217
+
218
+ /**
219
+ * The Key Schedule
220
+ *
221
+ * @see _setup()
222
+ * @var Array
223
+ * @access private
224
+ */
225
+ var $w;
226
+
227
+ /**
228
+ * The Inverse Key Schedule
229
+ *
230
+ * @see _setup()
231
+ * @var Array
232
+ * @access private
233
+ */
234
+ var $dw;
235
+
236
+ /**
237
+ * The Block Length
238
+ *
239
+ * @see setBlockLength()
240
+ * @var Integer
241
+ * @access private
242
+ * @internal The max value is 32, the min value is 16. All valid values are multiples of 4. Exists in conjunction with
243
+ * $Nb because we need this value and not $Nb to pad strings appropriately.
244
+ */
245
+ var $block_size = 16;
246
+
247
+ /**
248
+ * The Block Length divided by 32
249
+ *
250
+ * @see setBlockLength()
251
+ * @var Integer
252
+ * @access private
253
+ * @internal The max value is 256 / 32 = 8, the min value is 128 / 32 = 4. Exists in conjunction with $block_size
254
+ * because the encryption / decryption / key schedule creation requires this number and not $block_size. We could
255
+ * derive this from $block_size or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu
256
+ * of that, we'll just precompute it once.
257
+ *
258
+ */
259
+ var $Nb = 4;
260
+
261
+ /**
262
+ * The Key Length
263
+ *
264
+ * @see setKeyLength()
265
+ * @var Integer
266
+ * @access private
267
+ * @internal The max value is 256 / 8 = 32, the min value is 128 / 8 = 16. Exists in conjunction with $key_size
268
+ * because the encryption / decryption / key schedule creation requires this number and not $key_size. We could
269
+ * derive this from $key_size or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu
270
+ * of that, we'll just precompute it once.
271
+ */
272
+ var $key_size = 16;
273
+
274
+ /**
275
+ * The Key Length divided by 32
276
+ *
277
+ * @see setKeyLength()
278
+ * @var Integer
279
+ * @access private
280
+ * @internal The max value is 256 / 32 = 8, the min value is 128 / 32 = 4
281
+ */
282
+ var $Nk = 4;
283
+
284
+ /**
285
+ * The Number of Rounds
286
+ *
287
+ * @var Integer
288
+ * @access private
289
+ * @internal The max value is 14, the min value is 10.
290
+ */
291
+ var $Nr;
292
+
293
+ /**
294
+ * Shift offsets
295
+ *
296
+ * @var Array
297
+ * @access private
298
+ */
299
+ var $c;
300
+
301
+ /**
302
+ * Precomputed mixColumns table
303
+ *
304
+ * @see Crypt_Rijndael()
305
+ * @var Array
306
+ * @access private
307
+ */
308
+ var $t0;
309
+
310
+ /**
311
+ * Precomputed mixColumns table
312
+ *
313
+ * @see Crypt_Rijndael()
314
+ * @var Array
315
+ * @access private
316
+ */
317
+ var $t1;
318
+
319
+ /**
320
+ * Precomputed mixColumns table
321
+ *
322
+ * @see Crypt_Rijndael()
323
+ * @var Array
324
+ * @access private
325
+ */
326
+ var $t2;
327
+
328
+ /**
329
+ * Precomputed mixColumns table
330
+ *
331
+ * @see Crypt_Rijndael()
332
+ * @var Array
333
+ * @access private
334
+ */
335
+ var $t3;
336
+
337
+ /**
338
+ * Precomputed invMixColumns table
339
+ *
340
+ * @see Crypt_Rijndael()
341
+ * @var Array
342
+ * @access private
343
+ */
344
+ var $dt0;
345
+
346
+ /**
347
+ * Precomputed invMixColumns table
348
+ *
349
+ * @see Crypt_Rijndael()
350
+ * @var Array
351
+ * @access private
352
+ */
353
+ var $dt1;
354
+
355
+ /**
356
+ * Precomputed invMixColumns table
357
+ *
358
+ * @see Crypt_Rijndael()
359
+ * @var Array
360
+ * @access private
361
+ */
362
+ var $dt2;
363
+
364
+ /**
365
+ * Precomputed invMixColumns table
366
+ *
367
+ * @see Crypt_Rijndael()
368
+ * @var Array
369
+ * @access private
370
+ */
371
+ var $dt3;
372
+
373
+ /**
374
+ * The SubByte S-Box
375
+ *
376
+ * @see Crypt_Rijndael::_encryptBlock()
377
+ * @var Array
378
+ * @access private
379
+ */
380
+ var $sbox;
381
+
382
+ /**
383
+ * The inverse SubByte S-Box
384
+ *
385
+ * @see Crypt_Rijndael::_decryptBlock()
386
+ * @var Array
387
+ * @access private
388
+ */
389
+ var $isbox;
390
+
391
+ /**
392
+ * Performance-optimized callback function for en/decrypt()
393
+ *
394
+ * @see Crypt_Rijndael::encrypt()
395
+ * @see Crypt_Rijndael::decrypt()
396
+ * @see Crypt_Rijndael::inline_crypt_setup()
397
+ * @see Crypt_Rijndael::$use_inline_crypt
398
+ * @var Callback
399
+ * @access private
400
+ */
401
+ var $inline_crypt;
402
+
403
+ /**
404
+ * Holds whether performance-optimized $inline_crypt should be used or not.
405
+ *
406
+ * @see Crypt_Rijndael::Crypt_Rijndael()
407
+ * @see Crypt_Rijndael::inline_crypt_setup()
408
+ * @see Crypt_Rijndael::$inline_crypt
409
+ * @var Boolean
410
+ * @access private
411
+ */
412
+ var $use_inline_crypt = true;
413
+
414
+ /**
415
+ * Is the mode one that is paddable?
416
+ *
417
+ * @see Crypt_Rijndael::Crypt_Rijndael()
418
+ * @var Boolean
419
+ * @access private
420
+ */
421
+ var $paddable = false;
422
+
423
+ /**
424
+ * Encryption buffer for CTR, OFB and CFB modes
425
+ *
426
+ * @see Crypt_Rijndael::encrypt()
427
+ * @var String
428
+ * @access private
429
+ */
430
+ var $enbuffer = array('encrypted' => '', 'xor' => '', 'pos' => 0);
431
+
432
+ /**
433
+ * Decryption buffer for CTR, OFB and CFB modes
434
+ *
435
+ * @see Crypt_Rijndael::decrypt()
436
+ * @var String
437
+ * @access private
438
+ */
439
+ var $debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0);
440
+
441
+ /**
442
+ * Default Constructor.
443
+ *
444
+ * Determines whether or not the mcrypt extension should be used. $mode should only, at present, be
445
+ * CRYPT_RIJNDAEL_MODE_ECB or CRYPT_RIJNDAEL_MODE_CBC. If not explictly set, CRYPT_RIJNDAEL_MODE_CBC will be used.
446
+ *
447
+ * @param optional Integer $mode
448
+ * @return Crypt_Rijndael
449
+ * @access public
450
+ */
451
+ function Crypt_Rijndael($mode = CRYPT_RIJNDAEL_MODE_CBC)
452
+ {
453
+ switch ($mode) {
454
+ case CRYPT_RIJNDAEL_MODE_ECB:
455
+ case CRYPT_RIJNDAEL_MODE_CBC:
456
+ $this->paddable = true;
457
+ $this->mode = $mode;
458
+ break;
459
+ case CRYPT_RIJNDAEL_MODE_CTR:
460
+ case CRYPT_RIJNDAEL_MODE_CFB:
461
+ case CRYPT_RIJNDAEL_MODE_OFB:
462
+ $this->mode = $mode;
463
+ break;
464
+ default:
465
+ $this->paddable = true;
466
+ $this->mode = CRYPT_RIJNDAEL_MODE_CBC;
467
+ }
468
+
469
+ $t3 = &$this->t3;
470
+ $t2 = &$this->t2;
471
+ $t1 = &$this->t1;
472
+ $t0 = &$this->t0;
473
+
474
+ $dt3 = &$this->dt3;
475
+ $dt2 = &$this->dt2;
476
+ $dt1 = &$this->dt1;
477
+ $dt0 = &$this->dt0;
478
+
479
+ // according to <http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=19> (section 5.2.1),
480
+ // precomputed tables can be used in the mixColumns phase. in that example, they're assigned t0...t3, so
481
+ // those are the names we'll use.
482
+ $t3 = array(
483
+ 0x6363A5C6, 0x7C7C84F8, 0x777799EE, 0x7B7B8DF6, 0xF2F20DFF, 0x6B6BBDD6, 0x6F6FB1DE, 0xC5C55491,
484
+ 0x30305060, 0x01010302, 0x6767A9CE, 0x2B2B7D56, 0xFEFE19E7, 0xD7D762B5, 0xABABE64D, 0x76769AEC,
485
+ 0xCACA458F, 0x82829D1F, 0xC9C94089, 0x7D7D87FA, 0xFAFA15EF, 0x5959EBB2, 0x4747C98E, 0xF0F00BFB,
486
+ 0xADADEC41, 0xD4D467B3, 0xA2A2FD5F, 0xAFAFEA45, 0x9C9CBF23, 0xA4A4F753, 0x727296E4, 0xC0C05B9B,
487
+ 0xB7B7C275, 0xFDFD1CE1, 0x9393AE3D, 0x26266A4C, 0x36365A6C, 0x3F3F417E, 0xF7F702F5, 0xCCCC4F83,
488
+ 0x34345C68, 0xA5A5F451, 0xE5E534D1, 0xF1F108F9, 0x717193E2, 0xD8D873AB, 0x31315362, 0x15153F2A,
489
+ 0x04040C08, 0xC7C75295, 0x23236546, 0xC3C35E9D, 0x18182830, 0x9696A137, 0x05050F0A, 0x9A9AB52F,
490
+ 0x0707090E, 0x12123624, 0x80809B1B, 0xE2E23DDF, 0xEBEB26CD, 0x2727694E, 0xB2B2CD7F, 0x75759FEA,
491
+ 0x09091B12, 0x83839E1D, 0x2C2C7458, 0x1A1A2E34, 0x1B1B2D36, 0x6E6EB2DC, 0x5A5AEEB4, 0xA0A0FB5B,
492
+ 0x5252F6A4, 0x3B3B4D76, 0xD6D661B7, 0xB3B3CE7D, 0x29297B52, 0xE3E33EDD, 0x2F2F715E, 0x84849713,
493
+ 0x5353F5A6, 0xD1D168B9, 0x00000000, 0xEDED2CC1, 0x20206040, 0xFCFC1FE3, 0xB1B1C879, 0x5B5BEDB6,
494
+ 0x6A6ABED4, 0xCBCB468D, 0xBEBED967, 0x39394B72, 0x4A4ADE94, 0x4C4CD498, 0x5858E8B0, 0xCFCF4A85,
495
+ 0xD0D06BBB, 0xEFEF2AC5, 0xAAAAE54F, 0xFBFB16ED, 0x4343C586, 0x4D4DD79A, 0x33335566, 0x85859411,
496
+ 0x4545CF8A, 0xF9F910E9, 0x02020604, 0x7F7F81FE, 0x5050F0A0, 0x3C3C4478, 0x9F9FBA25, 0xA8A8E34B,
497
+ 0x5151F3A2, 0xA3A3FE5D, 0x4040C080, 0x8F8F8A05, 0x9292AD3F, 0x9D9DBC21, 0x38384870, 0xF5F504F1,
498
+ 0xBCBCDF63, 0xB6B6C177, 0xDADA75AF, 0x21216342, 0x10103020, 0xFFFF1AE5, 0xF3F30EFD, 0xD2D26DBF,
499
+ 0xCDCD4C81, 0x0C0C1418, 0x13133526, 0xECEC2FC3, 0x5F5FE1BE, 0x9797A235, 0x4444CC88, 0x1717392E,
500
+ 0xC4C45793, 0xA7A7F255, 0x7E7E82FC, 0x3D3D477A, 0x6464ACC8, 0x5D5DE7BA, 0x19192B32, 0x737395E6,
501
+ 0x6060A0C0, 0x81819819, 0x4F4FD19E, 0xDCDC7FA3, 0x22226644, 0x2A2A7E54, 0x9090AB3B, 0x8888830B,
502
+ 0x4646CA8C, 0xEEEE29C7, 0xB8B8D36B, 0x14143C28, 0xDEDE79A7, 0x5E5EE2BC, 0x0B0B1D16, 0xDBDB76AD,
503
+ 0xE0E03BDB, 0x32325664, 0x3A3A4E74, 0x0A0A1E14, 0x4949DB92, 0x06060A0C, 0x24246C48, 0x5C5CE4B8,
504
+ 0xC2C25D9F, 0xD3D36EBD, 0xACACEF43, 0x6262A6C4, 0x9191A839, 0x9595A431, 0xE4E437D3, 0x79798BF2,
505
+ 0xE7E732D5, 0xC8C8438B, 0x3737596E, 0x6D6DB7DA, 0x8D8D8C01, 0xD5D564B1, 0x4E4ED29C, 0xA9A9E049,
506
+ 0x6C6CB4D8, 0x5656FAAC, 0xF4F407F3, 0xEAEA25CF, 0x6565AFCA, 0x7A7A8EF4, 0xAEAEE947, 0x08081810,
507
+ 0xBABAD56F, 0x787888F0, 0x25256F4A, 0x2E2E725C, 0x1C1C2438, 0xA6A6F157, 0xB4B4C773, 0xC6C65197,
508
+ 0xE8E823CB, 0xDDDD7CA1, 0x74749CE8, 0x1F1F213E, 0x4B4BDD96, 0xBDBDDC61, 0x8B8B860D, 0x8A8A850F,
509
+ 0x707090E0, 0x3E3E427C, 0xB5B5C471, 0x6666AACC, 0x4848D890, 0x03030506, 0xF6F601F7, 0x0E0E121C,
510
+ 0x6161A3C2, 0x35355F6A, 0x5757F9AE, 0xB9B9D069, 0x86869117, 0xC1C15899, 0x1D1D273A, 0x9E9EB927,
511
+ 0xE1E138D9, 0xF8F813EB, 0x9898B32B, 0x11113322, 0x6969BBD2, 0xD9D970A9, 0x8E8E8907, 0x9494A733,
512
+ 0x9B9BB62D, 0x1E1E223C, 0x87879215, 0xE9E920C9, 0xCECE4987, 0x5555FFAA, 0x28287850, 0xDFDF7AA5,
513
+ 0x8C8C8F03, 0xA1A1F859, 0x89898009, 0x0D0D171A, 0xBFBFDA65, 0xE6E631D7, 0x4242C684, 0x6868B8D0,
514
+ 0x4141C382, 0x9999B029, 0x2D2D775A, 0x0F0F111E, 0xB0B0CB7B, 0x5454FCA8, 0xBBBBD66D, 0x16163A2C
515
+ );
516
+
517
+ $dt3 = array(
518
+ 0xF4A75051, 0x4165537E, 0x17A4C31A, 0x275E963A, 0xAB6BCB3B, 0x9D45F11F, 0xFA58ABAC, 0xE303934B,
519
+ 0x30FA5520, 0x766DF6AD, 0xCC769188, 0x024C25F5, 0xE5D7FC4F, 0x2ACBD7C5, 0x35448026, 0x62A38FB5,
520
+ 0xB15A49DE, 0xBA1B6725, 0xEA0E9845, 0xFEC0E15D, 0x2F7502C3, 0x4CF01281, 0x4697A38D, 0xD3F9C66B,
521
+ 0x8F5FE703, 0x929C9515, 0x6D7AEBBF, 0x5259DA95, 0xBE832DD4, 0x7421D358, 0xE0692949, 0xC9C8448E,
522
+ 0xC2896A75, 0x8E7978F4, 0x583E6B99, 0xB971DD27, 0xE14FB6BE, 0x88AD17F0, 0x20AC66C9, 0xCE3AB47D,
523
+ 0xDF4A1863, 0x1A3182E5, 0x51336097, 0x537F4562, 0x6477E0B1, 0x6BAE84BB, 0x81A01CFE, 0x082B94F9,
524
+ 0x48685870, 0x45FD198F, 0xDE6C8794, 0x7BF8B752, 0x73D323AB, 0x4B02E272, 0x1F8F57E3, 0x55AB2A66,
525
+ 0xEB2807B2, 0xB5C2032F, 0xC57B9A86, 0x3708A5D3, 0x2887F230, 0xBFA5B223, 0x036ABA02, 0x16825CED,
526
+ 0xCF1C2B8A, 0x79B492A7, 0x07F2F0F3, 0x69E2A14E, 0xDAF4CD65, 0x05BED506, 0x34621FD1, 0xA6FE8AC4,
527
+ 0x2E539D34, 0xF355A0A2, 0x8AE13205, 0xF6EB75A4, 0x83EC390B, 0x60EFAA40, 0x719F065E, 0x6E1051BD,
528
+ 0x218AF93E, 0xDD063D96, 0x3E05AEDD, 0xE6BD464D, 0x548DB591, 0xC45D0571, 0x06D46F04, 0x5015FF60,
529
+ 0x98FB2419, 0xBDE997D6, 0x4043CC89, 0xD99E7767, 0xE842BDB0, 0x898B8807, 0x195B38E7, 0xC8EEDB79,
530
+ 0x7C0A47A1, 0x420FE97C, 0x841EC9F8, 0x00000000, 0x80868309, 0x2BED4832, 0x1170AC1E, 0x5A724E6C,
531
+ 0x0EFFFBFD, 0x8538560F, 0xAED51E3D, 0x2D392736, 0x0FD9640A, 0x5CA62168, 0x5B54D19B, 0x362E3A24,
532
+ 0x0A67B10C, 0x57E70F93, 0xEE96D2B4, 0x9B919E1B, 0xC0C54F80, 0xDC20A261, 0x774B695A, 0x121A161C,
533
+ 0x93BA0AE2, 0xA02AE5C0, 0x22E0433C, 0x1B171D12, 0x090D0B0E, 0x8BC7ADF2, 0xB6A8B92D, 0x1EA9C814,
534
+ 0xF1198557, 0x75074CAF, 0x99DDBBEE, 0x7F60FDA3, 0x01269FF7, 0x72F5BC5C, 0x663BC544, 0xFB7E345B,
535
+ 0x4329768B, 0x23C6DCCB, 0xEDFC68B6, 0xE4F163B8, 0x31DCCAD7, 0x63851042, 0x97224013, 0xC6112084,
536
+ 0x4A247D85, 0xBB3DF8D2, 0xF93211AE, 0x29A16DC7, 0x9E2F4B1D, 0xB230F3DC, 0x8652EC0D, 0xC1E3D077,
537
+ 0xB3166C2B, 0x70B999A9, 0x9448FA11, 0xE9642247, 0xFC8CC4A8, 0xF03F1AA0, 0x7D2CD856, 0x3390EF22,
538
+ 0x494EC787, 0x38D1C1D9, 0xCAA2FE8C, 0xD40B3698, 0xF581CFA6, 0x7ADE28A5, 0xB78E26DA, 0xADBFA43F,
539
+ 0x3A9DE42C, 0x78920D50, 0x5FCC9B6A, 0x7E466254, 0x8D13C2F6, 0xD8B8E890, 0x39F75E2E, 0xC3AFF582,
540
+ 0x5D80BE9F, 0xD0937C69, 0xD52DA96F, 0x2512B3CF, 0xAC993BC8, 0x187DA710, 0x9C636EE8, 0x3BBB7BDB,
541
+ 0x267809CD, 0x5918F46E, 0x9AB701EC, 0x4F9AA883, 0x956E65E6, 0xFFE67EAA, 0xBCCF0821, 0x15E8E6EF,
542
+ 0xE79BD9BA, 0x6F36CE4A, 0x9F09D4EA, 0xB07CD629, 0xA4B2AF31, 0x3F23312A, 0xA59430C6, 0xA266C035,
543
+ 0x4EBC3774, 0x82CAA6FC, 0x90D0B0E0, 0xA7D81533, 0x04984AF1, 0xECDAF741, 0xCD500E7F, 0x91F62F17,
544
+ 0x4DD68D76, 0xEFB04D43, 0xAA4D54CC, 0x9604DFE4, 0xD1B5E39E, 0x6A881B4C, 0x2C1FB8C1, 0x65517F46,
545
+ 0x5EEA049D, 0x8C355D01, 0x877473FA, 0x0B412EFB, 0x671D5AB3, 0xDBD25292, 0x105633E9, 0xD647136D,
546
+ 0xD7618C9A, 0xA10C7A37, 0xF8148E59, 0x133C89EB, 0xA927EECE, 0x61C935B7, 0x1CE5EDE1, 0x47B13C7A,
547
+ 0xD2DF599C, 0xF2733F55, 0x14CE7918, 0xC737BF73, 0xF7CDEA53, 0xFDAA5B5F, 0x3D6F14DF, 0x44DB8678,
548
+ 0xAFF381CA, 0x68C43EB9, 0x24342C38, 0xA3405FC2, 0x1DC37216, 0xE2250CBC, 0x3C498B28, 0x0D9541FF,
549
+ 0xA8017139, 0x0CB3DE08, 0xB4E49CD8, 0x56C19064, 0xCB84617B, 0x32B670D5, 0x6C5C7448, 0xB85742D0
550
+ );
551
+
552
+ for ($i = 0; $i < 256; $i++) {
553
+ $t2[] = (($t3[$i] << 8) & 0xFFFFFF00) | (($t3[$i] >> 24) & 0x000000FF);
554
+ $t1[] = (($t3[$i] << 16) & 0xFFFF0000) | (($t3[$i] >> 16) & 0x0000FFFF);
555
+ $t0[] = (($t3[$i] << 24) & 0xFF000000) | (($t3[$i] >> 8) & 0x00FFFFFF);
556
+
557
+ $dt2[] = (($dt3[$i] << 8) & 0xFFFFFF00) | (($dt3[$i] >> 24) & 0x000000FF);
558
+ $dt1[] = (($dt3[$i] << 16) & 0xFFFF0000) | (($dt3[$i] >> 16) & 0x0000FFFF);
559
+ $dt0[] = (($dt3[$i] << 24) & 0xFF000000) | (($dt3[$i] >> 8) & 0x00FFFFFF);
560
+ }
561
+
562
+ // sbox for the S-Box substitution
563
+ $this->sbox = array(
564
+ 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
565
+ 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
566
+ 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
567
+ 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
568
+ 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
569
+ 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
570
+ 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
571
+ 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
572
+ 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
573
+ 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
574
+ 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
575
+ 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
576
+ 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
577
+ 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
578
+ 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
579
+ 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
580
+ );
581
+
582
+ // sbox for the inverse S-Box substitution
583
+ $this->isbox = array(
584
+ 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB,
585
+ 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB,
586
+ 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
587
+ 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25,
588
+ 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92,
589
+ 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
590
+ 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06,
591
+ 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B,
592
+ 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
593
+ 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E,
594
+ 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B,
595
+ 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
596
+ 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F,
597
+ 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF,
598
+ 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
599
+ 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D
600
+ );
601
+
602
+ if (!function_exists('create_function') || !is_callable('create_function')) {
603
+ $this->use_inline_crypt = false;
604
+ }
605
+ }
606
+
607
+ /**
608
+ * Sets the key.
609
+ *
610
+ * Keys can be of any length. Rijndael, itself, requires the use of a key that's between 128-bits and 256-bits long and
611
+ * whose length is a multiple of 32. If the key is less than 256-bits and the key length isn't set, we round the length
612
+ * up to the closest valid key length, padding $key with null bytes. If the key is more than 256-bits, we trim the
613
+ * excess bits.
614
+ *
615
+ * If the key is not explicitly set, it'll be assumed to be all null bytes.
616
+ *
617
+ * @access public
618
+ * @param String $key
619
+ */
620
+ function setKey($key)
621
+ {
622
+ $this->key = $key;
623
+ $this->changed = true;
624
+ }
625
+
626
+ /**
627
+ * Sets the initialization vector. (optional)
628
+ *
629
+ * SetIV is not required when CRYPT_RIJNDAEL_MODE_ECB is being used. If not explictly set, it'll be assumed
630
+ * to be all zero's.
631
+ *
632
+ * @access public
633
+ * @param String $iv
634
+ */
635
+ function setIV($iv)
636
+ {
637
+ $this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($iv, 0, $this->block_size), $this->block_size, chr(0));
638
+ }
639
+
640
+ /**
641
+ * Sets the key length
642
+ *
643
+ * Valid key lengths are 128, 160, 192, 224, and 256. If the length is less than 128, it will be rounded up to
644
+ * 128. If the length is greater than 128 and invalid, it will be rounded down to the closest valid amount.
645
+ *
646
+ * @access public
647
+ * @param Integer $length
648
+ */
649
+ function setKeyLength($length)
650
+ {
651
+ $length >>= 5;
652
+ if ($length > 8) {
653
+ $length = 8;
654
+ } else if ($length < 4) {
655
+ $length = 4;
656
+ }
657
+ $this->Nk = $length;
658
+ $this->key_size = $length << 2;
659
+
660
+ $this->explicit_key_length = true;
661
+ $this->changed = true;
662
+ }
663
+
664
+ /**
665
+ * Sets the password.
666
+ *
667
+ * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows:
668
+ * {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2}:
669
+ * $hash, $salt, $method
670
+ * Set $dkLen by calling setKeyLength()
671
+ *
672
+ * @param String $password
673
+ * @param optional String $method
674
+ * @access public
675
+ */
676
+ function setPassword($password, $method = 'pbkdf2')
677
+ {
678
+ $key = '';
679
+
680
+ switch ($method) {
681
+ default: // 'pbkdf2'
682
+ list(, , $hash, $salt, $count) = func_get_args();
683
+ if (!isset($hash)) {
684
+ $hash = 'sha1';
685
+ }
686
+ // WPA and WPA2 use the SSID as the salt
687
+ if (!isset($salt)) {
688
+ $salt = 'phpseclib';
689
+ }
690
+ // RFC2898#section-4.2 uses 1,000 iterations by default
691
+ // WPA and WPA2 use 4,096.
692
+ if (!isset($count)) {
693
+ $count = 1000;
694
+ }
695
+
696
+ if (!class_exists('Crypt_Hash')) {
697
+ require_once('Crypt/Hash.php');
698
+ }
699
+
700
+ $i = 1;
701
+ while (strlen($key) < $this->key_size) { // $dkLen == $this->key_size
702
+ //$dk.= $this->_pbkdf($password, $salt, $count, $i++);
703
+ $hmac = new Crypt_Hash();
704
+ $hmac->setHash($hash);
705
+ $hmac->setKey($password);
706
+ $f = $u = $hmac->hash($salt . pack('N', $i++));
707
+ for ($j = 2; $j <= $count; $j++) {
708
+ $u = $hmac->hash($u);
709
+ $f^= $u;
710
+ }
711
+ $key.= $f;
712
+ }
713
+ }
714
+
715
+ $this->setKey(substr($key, 0, $this->key_size));
716
+ }
717
+
718
+ /**
719
+ * Sets the block length
720
+ *
721
+ * Valid block lengths are 128, 160, 192, 224, and 256. If the length is less than 128, it will be rounded up to
722
+ * 128. If the length is greater than 128 and invalid, it will be rounded down to the closest valid amount.
723
+ *
724
+ * @access public
725
+ * @param Integer $length
726
+ */
727
+ function setBlockLength($length)
728
+ {
729
+ $length >>= 5;
730
+ if ($length > 8) {
731
+ $length = 8;
732
+ } else if ($length < 4) {
733
+ $length = 4;
734
+ }
735
+ $this->Nb = $length;
736
+ $this->block_size = $length << 2;
737
+ $this->changed = true;
738
+ }
739
+
740
+ /**
741
+ * Generate CTR XOR encryption key
742
+ *
743
+ * Encrypt the output of this and XOR it against the ciphertext / plaintext to get the
744
+ * plaintext / ciphertext in CTR mode.
745
+ *
746
+ * @see Crypt_Rijndael::decrypt()
747
+ * @see Crypt_Rijndael::encrypt()
748
+ * @access public
749
+ * @param Integer $length
750
+ * @param String $iv
751
+ */
752
+ function _generate_xor($length, &$iv)
753
+ {
754
+ $xor = '';
755
+ $block_size = $this->block_size;
756
+ $num_blocks = floor(($length + ($block_size - 1)) / $block_size);
757
+ for ($i = 0; $i < $num_blocks; $i++) {
758
+ $xor.= $iv;
759
+ for ($j = 4; $j <= $block_size; $j+=4) {
760
+ $temp = substr($iv, -$j, 4);
761
+ switch ($temp) {
762
+ case "\xFF\xFF\xFF\xFF":
763
+ $iv = substr_replace($iv, "\x00\x00\x00\x00", -$j, 4);
764
+ break;
765
+ case "\x7F\xFF\xFF\xFF":
766
+ $iv = substr_replace($iv, "\x80\x00\x00\x00", -$j, 4);
767
+ break 2;
768
+ default:
769
+ extract(unpack('Ncount', $temp));
770
+ $iv = substr_replace($iv, pack('N', $count + 1), -$j, 4);
771
+ break 2;
772
+ }
773
+ }
774
+ }
775
+
776
+ return $xor;
777
+ }
778
+
779
+ /**
780
+ * Encrypts a message.
781
+ *
782
+ * $plaintext will be padded with additional bytes such that it's length is a multiple of the block size. Other Rjindael
783
+ * implementations may or may not pad in the same manner. Other common approaches to padding and the reasons why it's
784
+ * necessary are discussed in the following
785
+ * URL:
786
+ *
787
+ * {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html}
788
+ *
789
+ * An alternative to padding is to, separately, send the length of the file. This is what SSH, in fact, does.
790
+ * strlen($plaintext) will still need to be a multiple of 8, however, arbitrary values can be added to make it that
791
+ * length.
792
+ *
793
+ * @see Crypt_Rijndael::decrypt()
794
+ * @access public
795
+ * @param String $plaintext
796
+ */
797
+ function encrypt($plaintext)
798
+ {
799
+ if ($this->changed) {
800
+ $this->_setup();
801
+ }
802
+ if ($this->use_inline_crypt) {
803
+ $inline = $this->inline_crypt;
804
+ return $inline('encrypt', $this, $plaintext);
805
+ }
806
+ if ($this->paddable) {
807
+ $plaintext = $this->_pad($plaintext);
808
+ }
809
+
810
+ $block_size = $this->block_size;
811
+ $buffer = &$this->enbuffer;
812
+ $ciphertext = '';
813
+ switch ($this->mode) {
814
+ case CRYPT_RIJNDAEL_MODE_ECB:
815
+ for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
816
+ $ciphertext.= $this->_encryptBlock(substr($plaintext, $i, $block_size));
817
+ }
818
+ break;
819
+ case CRYPT_RIJNDAEL_MODE_CBC:
820
+ $xor = $this->encryptIV;
821
+ for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
822
+ $block = substr($plaintext, $i, $block_size);
823
+ $block = $this->_encryptBlock($block ^ $xor);
824
+ $xor = $block;
825
+ $ciphertext.= $block;
826
+ }
827
+ if ($this->continuousBuffer) {
828
+ $this->encryptIV = $xor;
829
+ }
830
+ break;
831
+ case CRYPT_RIJNDAEL_MODE_CTR:
832
+ $xor = $this->encryptIV;
833
+ if (strlen($buffer['encrypted'])) {
834
+ for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
835
+ $block = substr($plaintext, $i, $block_size);
836
+ if (strlen($block) > strlen($buffer['encrypted'])) {
837
+ $buffer['encrypted'].= $this->_encryptBlock($this->_generate_xor($block_size, $xor));
838
+ }
839
+ $key = $this->_string_shift($buffer['encrypted'], $block_size);
840
+ $ciphertext.= $block ^ $key;
841
+ }
842
+ } else {
843
+ for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
844
+ $block = substr($plaintext, $i, $block_size);
845
+ $key = $this->_encryptBlock($this->_generate_xor($block_size, $xor));
846
+ $ciphertext.= $block ^ $key;
847
+ }
848
+ }
849
+ if ($this->continuousBuffer) {
850
+ $this->encryptIV = $xor;
851
+ if ($start = strlen($plaintext) % $block_size) {
852
+ $buffer['encrypted'] = substr($key, $start) . $buffer['encrypted'];
853
+ }
854
+ }
855
+ break;
856
+ case CRYPT_RIJNDAEL_MODE_CFB:
857
+ // cfb loosely routines inspired by openssl's:
858
+ // http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1
859
+ if ($this->continuousBuffer) {
860
+ $iv = &$this->encryptIV;
861
+ $pos = &$buffer['pos'];
862
+ } else {
863
+ $iv = $this->encryptIV;
864
+ $pos = 0;
865
+ }
866
+ $len = strlen($plaintext);
867
+ $i = 0;
868
+ if ($pos) {
869
+ $orig_pos = $pos;
870
+ $max = $block_size - $pos;
871
+ if ($len >= $max) {
872
+ $i = $max;
873
+ $len-= $max;
874
+ $pos = 0;
875
+ } else {
876
+ $i = $len;
877
+ $pos+= $len;
878
+ $len = 0;
879
+ }
880
+ // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
881
+ $ciphertext = substr($iv, $orig_pos) ^ $plaintext;
882
+ $iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
883
+ }
884
+ while ($len >= $block_size) {
885
+ $iv = $this->_encryptBlock($iv) ^ substr($plaintext, $i, $block_size);
886
+ $ciphertext.= $iv;
887
+ $len-= $block_size;
888
+ $i+= $block_size;
889
+ }
890
+ if ($len) {
891
+ $iv = $this->_encryptBlock($iv);
892
+ $block = $iv ^ substr($plaintext, $i);
893
+ $iv = substr_replace($iv, $block, 0, $len);
894
+ $ciphertext.= $block;
895
+ $pos = $len;
896
+ }
897
+ break;
898
+ case CRYPT_RIJNDAEL_MODE_OFB:
899
+ $xor = $this->encryptIV;
900
+ if (strlen($buffer['xor'])) {
901
+ for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
902
+ $block = substr($plaintext, $i, $block_size);
903
+ if (strlen($block) > strlen($buffer['xor'])) {
904
+ $xor = $this->_encryptBlock($xor);
905
+ $buffer['xor'].= $xor;
906
+ }
907
+ $key = $this->_string_shift($buffer['xor'], $block_size);
908
+ $ciphertext.= $block ^ $key;
909
+ }
910
+ } else {
911
+ for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
912
+ $xor = $this->_encryptBlock($xor);
913
+ $ciphertext.= substr($plaintext, $i, $block_size) ^ $xor;
914
+ }
915
+ $key = $xor;
916
+ }
917
+ if ($this->continuousBuffer) {
918
+ $this->encryptIV = $xor;
919
+ if ($start = strlen($plaintext) % $block_size) {
920
+ $buffer['xor'] = substr($key, $start) . $buffer['xor'];
921
+ }
922
+ }
923
+ }
924
+
925
+ return $ciphertext;
926
+ }
927
+
928
+ /**
929
+ * Decrypts a message.
930
+ *
931
+ * If strlen($ciphertext) is not a multiple of the block size, null bytes will be added to the end of the string until
932
+ * it is.
933
+ *
934
+ * @see Crypt_Rijndael::encrypt()
935
+ * @access public
936
+ * @param String $ciphertext
937
+ */
938
+ function decrypt($ciphertext)
939
+ {
940
+ if ($this->changed) {
941
+ $this->_setup();
942
+ }
943
+ if ($this->use_inline_crypt) {
944
+ $inline = $this->inline_crypt;
945
+ return $inline('decrypt', $this, $ciphertext);
946
+ }
947
+ if ($this->paddable) {
948
+ // we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic :
949
+ // "The data is padded with "\0" to make sure the length of the data is n * blocksize."
950
+ $ciphertext = str_pad($ciphertext, strlen($ciphertext) + ($this->block_size - strlen($ciphertext) % $this->block_size) % $this->block_size, chr(0));
951
+ }
952
+
953
+ $block_size = $this->block_size;
954
+ $buffer = &$this->debuffer;
955
+ $plaintext = '';
956
+ switch ($this->mode) {
957
+ case CRYPT_RIJNDAEL_MODE_ECB:
958
+ for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
959
+ $plaintext.= $this->_decryptBlock(substr($ciphertext, $i, $block_size));
960
+ }
961
+ break;
962
+ case CRYPT_RIJNDAEL_MODE_CBC:
963
+ $xor = $this->decryptIV;
964
+ for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
965
+ $block = substr($ciphertext, $i, $block_size);
966
+ $plaintext.= $this->_decryptBlock($block) ^ $xor;
967
+ $xor = $block;
968
+ }
969
+ if ($this->continuousBuffer) {
970
+ $this->decryptIV = $xor;
971
+ }
972
+ break;
973
+ case CRYPT_RIJNDAEL_MODE_CTR:
974
+ $xor = $this->decryptIV;
975
+ if (strlen($buffer['ciphertext'])) {
976
+ for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
977
+ $block = substr($ciphertext, $i, $block_size);
978
+ if (strlen($block) > strlen($buffer['ciphertext'])) {
979
+ $buffer['ciphertext'].= $this->_encryptBlock($this->_generate_xor($block_size, $xor));
980
+ }
981
+ $key = $this->_string_shift($buffer['ciphertext'], $block_size);
982
+ $plaintext.= $block ^ $key;
983
+ }
984
+ } else {
985
+ for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
986
+ $block = substr($ciphertext, $i, $block_size);
987
+ $key = $this->_encryptBlock($this->_generate_xor($block_size, $xor));
988
+ $plaintext.= $block ^ $key;
989
+ }
990
+ }
991
+ if ($this->continuousBuffer) {
992
+ $this->decryptIV = $xor;
993
+ if ($start = strlen($ciphertext) % $block_size) {
994
+ $buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext'];
995
+ }
996
+ }
997
+ break;
998
+ case CRYPT_RIJNDAEL_MODE_CFB:
999
+ if ($this->continuousBuffer) {
1000
+ $iv = &$this->decryptIV;
1001
+ $pos = &$buffer['pos'];
1002
+ } else {
1003
+ $iv = $this->decryptIV;
1004
+ $pos = 0;
1005
+ }
1006
+ $len = strlen($ciphertext);
1007
+ $i = 0;
1008
+ if ($pos) {
1009
+ $orig_pos = $pos;
1010
+ $max = $block_size - $pos;
1011
+ if ($len >= $max) {
1012
+ $i = $max;
1013
+ $len-= $max;
1014
+ $pos = 0;
1015
+ } else {
1016
+ $i = $len;
1017
+ $pos+= $len;
1018
+ $len = 0;
1019
+ }
1020
+ // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
1021
+ $plaintext = substr($iv, $orig_pos) ^ $ciphertext;
1022
+ $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
1023
+ }
1024
+ while ($len >= $block_size) {
1025
+ $iv = $this->_encryptBlock($iv);
1026
+ $cb = substr($ciphertext, $i, $block_size);
1027
+ $plaintext.= $iv ^ $cb;
1028
+ $iv = $cb;
1029
+ $len-= $block_size;
1030
+ $i+= $block_size;
1031
+ }
1032
+ if ($len) {
1033
+ $iv = $this->_encryptBlock($iv);
1034
+ $plaintext.= $iv ^ substr($ciphertext, $i);
1035
+ $iv = substr_replace($iv, substr($ciphertext, $i), 0, $len);
1036
+ $pos = $len;
1037
+ }
1038
+ break;
1039
+ case CRYPT_RIJNDAEL_MODE_OFB:
1040
+ $xor = $this->decryptIV;
1041
+ if (strlen($buffer['xor'])) {
1042
+ for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
1043
+ $block = substr($ciphertext, $i, $block_size);
1044
+ if (strlen($block) > strlen($buffer['xor'])) {
1045
+ $xor = $this->_encryptBlock($xor);
1046
+ $buffer['xor'].= $xor;
1047
+ }
1048
+ $key = $this->_string_shift($buffer['xor'], $block_size);
1049
+ $plaintext.= $block ^ $key;
1050
+ }
1051
+ } else {
1052
+ for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
1053
+ $xor = $this->_encryptBlock($xor);
1054
+ $plaintext.= substr($ciphertext, $i, $block_size) ^ $xor;
1055
+ }
1056
+ $key = $xor;
1057
+ }
1058
+ if ($this->continuousBuffer) {
1059
+ $this->decryptIV = $xor;
1060
+ if ($start = strlen($ciphertext) % $block_size) {
1061
+ $buffer['xor'] = substr($key, $start) . $buffer['xor'];
1062
+ }
1063
+ }
1064
+ }
1065
+
1066
+ return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
1067
+ }
1068
+
1069
+ /**
1070
+ * Encrypts a block
1071
+ *
1072
+ * @access private
1073
+ * @param String $in
1074
+ * @return String
1075
+ */
1076
+ function _encryptBlock($in)
1077
+ {
1078
+ $state = array();
1079
+ $words = unpack('N*word', $in);
1080
+
1081
+ $w = $this->w;
1082
+ $t0 = $this->t0;
1083
+ $t1 = $this->t1;
1084
+ $t2 = $this->t2;
1085
+ $t3 = $this->t3;
1086
+ $Nb = $this->Nb;
1087
+ $Nr = $this->Nr;
1088
+ $c = $this->c;
1089
+
1090
+ // addRoundKey
1091
+ $i = -1;
1092
+ foreach ($words as $word) {
1093
+ $state[] = $word ^ $w[0][++$i];
1094
+ }
1095
+
1096
+ // fips-197.pdf#page=19, "Figure 5. Pseudo Code for the Cipher", states that this loop has four components -
1097
+ // subBytes, shiftRows, mixColumns, and addRoundKey. fips-197.pdf#page=30, "Implementation Suggestions Regarding
1098
+ // Various Platforms" suggests that performs enhanced implementations are described in Rijndael-ammended.pdf.
1099
+ // Rijndael-ammended.pdf#page=20, "Implementation aspects / 32-bit processor", discusses such an optimization.
1100
+ // Unfortunately, the description given there is not quite correct. Per aes.spec.v316.pdf#page=19 [1],
1101
+ // equation (7.4.7) is supposed to use addition instead of subtraction, so we'll do that here, as well.
1102
+
1103
+ // [1] http://fp.gladman.plus.com/cryptography_technology/rijndael/aes.spec.v316.pdf
1104
+ $temp = array();
1105
+ for ($round = 1; $round < $Nr; ++$round) {
1106
+ $i = 0; // $c[0] == 0
1107
+ $j = $c[1];
1108
+ $k = $c[2];
1109
+ $l = $c[3];
1110
+
1111
+ while ($i < $Nb) {
1112
+ $temp[$i] = $t0[$state[$i] >> 24 & 0x000000FF] ^
1113
+ $t1[$state[$j] >> 16 & 0x000000FF] ^
1114
+ $t2[$state[$k] >> 8 & 0x000000FF] ^
1115
+ $t3[$state[$l] & 0x000000FF] ^
1116
+ $w[$round][$i];
1117
+ ++$i;
1118
+ $j = ($j + 1) % $Nb;
1119
+ $k = ($k + 1) % $Nb;
1120
+ $l = ($l + 1) % $Nb;
1121
+ }
1122
+ $state = $temp;
1123
+ }
1124
+
1125
+ // subWord
1126
+ for ($i = 0; $i < $Nb; ++$i) {
1127
+ $state[$i] = $this->_subWord($state[$i]);
1128
+ }
1129
+
1130
+ // shiftRows + addRoundKey
1131
+ $i = 0; // $c[0] == 0
1132
+ $j = $c[1];
1133
+ $k = $c[2];
1134
+ $l = $c[3];
1135
+ while ($i < $Nb) {
1136
+ $temp[$i] = ($state[$i] & 0xFF000000) ^
1137
+ ($state[$j] & 0x00FF0000) ^
1138
+ ($state[$k] & 0x0000FF00) ^
1139
+ ($state[$l] & 0x000000FF) ^
1140
+ $w[$Nr][$i];
1141
+ ++$i;
1142
+ $j = ($j + 1) % $Nb;
1143
+ $k = ($k + 1) % $Nb;
1144
+ $l = ($l + 1) % $Nb;
1145
+ }
1146
+
1147
+ // 100% ugly switch/case code... but ~5% faster ("smart code" below commented out)
1148
+ switch ($Nb) {
1149
+ case 8:
1150
+ return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6], $temp[7]);
1151
+ case 7:
1152
+ return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6]);
1153
+ case 6:
1154
+ return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5]);
1155
+ case 5:
1156
+ return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4]);
1157
+ default:
1158
+ return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3]);
1159
+ }
1160
+ /*
1161
+ $state = $temp;
1162
+
1163
+ array_unshift($state, 'N*');
1164
+
1165
+ return call_user_func_array('pack', $state);
1166
+ */
1167
+ }
1168
+
1169
+ /**
1170
+ * Decrypts a block
1171
+ *
1172
+ * @access private
1173
+ * @param String $in
1174
+ * @return String
1175
+ */
1176
+ function _decryptBlock($in)
1177
+ {
1178
+ $state = array();
1179
+ $words = unpack('N*word', $in);
1180
+
1181
+ $dw = $this->dw;
1182
+ $dt0 = $this->dt0;
1183
+ $dt1 = $this->dt1;
1184
+ $dt2 = $this->dt2;
1185
+ $dt3 = $this->dt3;
1186
+ $Nb = $this->Nb;
1187
+ $Nr = $this->Nr;
1188
+ $c = $this->c;
1189
+
1190
+ // addRoundKey
1191
+ $i = -1;
1192
+ foreach ($words as $word) {
1193
+ $state[] = $word ^ $dw[$Nr][++$i];
1194
+ }
1195
+
1196
+ $temp = array();
1197
+ for ($round = $Nr - 1; $round > 0; --$round) {
1198
+ $i = 0; // $c[0] == 0
1199
+ $j = $Nb - $c[1];
1200
+ $k = $Nb - $c[2];
1201
+ $l = $Nb - $c[3];
1202
+
1203
+ while ($i < $Nb) {
1204
+ $temp[$i] = $dt0[$state[$i] >> 24 & 0x000000FF] ^
1205
+ $dt1[$state[$j] >> 16 & 0x000000FF] ^
1206
+ $dt2[$state[$k] >> 8 & 0x000000FF] ^
1207
+ $dt3[$state[$l] & 0x000000FF] ^
1208
+ $dw[$round][$i];
1209
+ ++$i;
1210
+ $j = ($j + 1) % $Nb;
1211
+ $k = ($k + 1) % $Nb;
1212
+ $l = ($l + 1) % $Nb;
1213
+ }
1214
+ $state = $temp;
1215
+ }
1216
+
1217
+ // invShiftRows + invSubWord + addRoundKey
1218
+ $i = 0; // $c[0] == 0
1219
+ $j = $Nb - $c[1];
1220
+ $k = $Nb - $c[2];
1221
+ $l = $Nb - $c[3];
1222
+
1223
+ while ($i < $Nb) {
1224
+ $temp[$i] = $dw[0][$i] ^
1225
+ $this->_invSubWord(($state[$i] & 0xFF000000) |
1226
+ ($state[$j] & 0x00FF0000) |
1227
+ ($state[$k] & 0x0000FF00) |
1228
+ ($state[$l] & 0x000000FF));
1229
+ ++$i;
1230
+ $j = ($j + 1) % $Nb;
1231
+ $k = ($k + 1) % $Nb;
1232
+ $l = ($l + 1) % $Nb;
1233
+ }
1234
+
1235
+ switch ($Nb) {
1236
+ case 8:
1237
+ return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6], $temp[7]);
1238
+ case 7:
1239
+ return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6]);
1240
+ case 6:
1241
+ return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5]);
1242
+ case 5:
1243
+ return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4]);
1244
+ default:
1245
+ return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3]);
1246
+ }
1247
+ /*
1248
+ $state = $temp;
1249
+
1250
+ array_unshift($state, 'N*');
1251
+
1252
+ return call_user_func_array('pack', $state);
1253
+ */
1254
+ }
1255
+
1256
+ /**
1257
+ * Setup Rijndael
1258
+ *
1259
+ * Validates all the variables and calculates $Nr - the number of rounds that need to be performed - and $w - the key
1260
+ * key schedule.
1261
+ *
1262
+ * @access private
1263
+ */
1264
+ function _setup()
1265
+ {
1266
+ // Each number in $rcon is equal to the previous number multiplied by two in Rijndael's finite field.
1267
+ // See http://en.wikipedia.org/wiki/Finite_field_arithmetic#Multiplicative_inverse
1268
+ static $rcon = array(0,
1269
+ 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000,
1270
+ 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000,
1271
+ 0x6C000000, 0xD8000000, 0xAB000000, 0x4D000000, 0x9A000000,
1272
+ 0x2F000000, 0x5E000000, 0xBC000000, 0x63000000, 0xC6000000,
1273
+ 0x97000000, 0x35000000, 0x6A000000, 0xD4000000, 0xB3000000,
1274
+ 0x7D000000, 0xFA000000, 0xEF000000, 0xC5000000, 0x91000000
1275
+ );
1276
+
1277
+ if (!$this->explicit_key_length) {
1278
+ // we do >> 2, here, and not >> 5, as we do above, since strlen($this->key) tells us the number of bytes - not bits
1279
+ $length = strlen($this->key) >> 2;
1280
+ if ($length > 8) {
1281
+ $length = 8;
1282
+ } else if ($length < 4) {
1283
+ $length = 4;
1284
+ }
1285
+ $this->Nk = $length;
1286
+ $this->key_size = $length << 2;
1287
+ }
1288
+
1289
+ $this->key = str_pad(substr($this->key, 0, $this->key_size), $this->key_size, chr(0));
1290
+ $this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($this->iv, 0, $this->block_size), $this->block_size, chr(0));
1291
+
1292
+ // see Rijndael-ammended.pdf#page=44
1293
+ $this->Nr = max($this->Nk, $this->Nb) + 6;
1294
+
1295
+ // shift offsets for Nb = 5, 7 are defined in Rijndael-ammended.pdf#page=44,
1296
+ // "Table 8: Shift offsets in Shiftrow for the alternative block lengths"
1297
+ // shift offsets for Nb = 4, 6, 8 are defined in Rijndael-ammended.pdf#page=14,
1298
+ // "Table 2: Shift offsets for different block lengths"
1299
+ switch ($this->Nb) {
1300
+ case 4:
1301
+ case 5:
1302
+ case 6:
1303
+ $this->c = array(0, 1, 2, 3);
1304
+ break;
1305
+ case 7:
1306
+ $this->c = array(0, 1, 2, 4);
1307
+ break;
1308
+ case 8:
1309
+ $this->c = array(0, 1, 3, 4);
1310
+ }
1311
+
1312
+ $key = $this->key;
1313
+
1314
+ $w = array_values(unpack('N*words', $key));
1315
+
1316
+ $length = $this->Nb * ($this->Nr + 1);
1317
+ for ($i = $this->Nk; $i < $length; $i++) {
1318
+ $temp = $w[$i - 1];
1319
+ if ($i % $this->Nk == 0) {
1320
+ // according to <http://php.net/language.types.integer>, "the size of an integer is platform-dependent".
1321
+ // on a 32-bit machine, it's 32-bits, and on a 64-bit machine, it's 64-bits. on a 32-bit machine,
1322
+ // 0xFFFFFFFF << 8 == 0xFFFFFF00, but on a 64-bit machine, it equals 0xFFFFFFFF00. as such, doing 'and'
1323
+ // with 0xFFFFFFFF (or 0xFFFFFF00) on a 32-bit machine is unnecessary, but on a 64-bit machine, it is.
1324
+ $temp = (($temp << 8) & 0xFFFFFF00) | (($temp >> 24) & 0x000000FF); // rotWord
1325
+ $temp = $this->_subWord($temp) ^ $rcon[$i / $this->Nk];
1326
+ } else if ($this->Nk > 6 && $i % $this->Nk == 4) {
1327
+ $temp = $this->_subWord($temp);
1328
+ }
1329
+ $w[$i] = $w[$i - $this->Nk] ^ $temp;
1330
+ }
1331
+
1332
+ // convert the key schedule from a vector of $Nb * ($Nr + 1) length to a matrix with $Nr + 1 rows and $Nb columns
1333
+ // and generate the inverse key schedule. more specifically,
1334
+ // according to <http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=23> (section 5.3.3),
1335
+ // "The key expansion for the Inverse Cipher is defined as follows:
1336
+ // 1. Apply the Key Expansion.
1337
+ // 2. Apply InvMixColumn to all Round Keys except the first and the last one."
1338
+ // also, see fips-197.pdf#page=27, "5.3.5 Equivalent Inverse Cipher"
1339
+ $temp = $this->w = $this->dw = array();
1340
+ for ($i = $row = $col = 0; $i < $length; $i++, $col++) {
1341
+ if ($col == $this->Nb) {
1342
+ if ($row == 0) {
1343
+ $this->dw[0] = $this->w[0];
1344
+ } else {
1345
+ // subWord + invMixColumn + invSubWord = invMixColumn
1346
+ $j = 0;
1347
+ while ($j < $this->Nb) {
1348
+ $dw = $this->_subWord($this->w[$row][$j]);
1349
+ $temp[$j] = $this->dt0[$dw >> 24 & 0x000000FF] ^
1350
+ $this->dt1[$dw >> 16 & 0x000000FF] ^
1351
+ $this->dt2[$dw >> 8 & 0x000000FF] ^
1352
+ $this->dt3[$dw & 0x000000FF];
1353
+ $j++;
1354
+ }
1355
+ $this->dw[$row] = $temp;
1356
+ }
1357
+
1358
+ $col = 0;
1359
+ $row++;
1360
+ }
1361
+ $this->w[$row][$col] = $w[$i];
1362
+ }
1363
+
1364
+ $this->dw[$row] = $this->w[$row];
1365
+
1366
+ // In case of $this->use_inline_crypt === true we have to use 1-dim key arrays (both ascending)
1367
+ if ($this->use_inline_crypt) {
1368
+ $this->dw = array_reverse($this->dw);
1369
+ $w = array_pop($this->w);
1370
+ $dw = array_pop($this->dw);
1371
+ foreach ($this->w as $r => $wr) {
1372
+ foreach ($wr as $c => $wc) {
1373
+ $w[] = $wc;
1374
+ $dw[] = $this->dw[$r][$c];
1375
+ }
1376
+ }
1377
+ $this->w = $w;
1378
+ $this->dw = $dw;
1379
+
1380
+ $this->inline_crypt_setup();
1381
+ }
1382
+
1383
+ $this->changed = false;
1384
+ }
1385
+
1386
+ /**
1387
+ * Performs S-Box substitutions
1388
+ *
1389
+ * @access private
1390
+ */
1391
+ function _subWord($word)
1392
+ {
1393
+ $sbox = $this->sbox;
1394
+
1395
+ return $sbox[$word & 0x000000FF] |
1396
+ ($sbox[$word >> 8 & 0x000000FF] << 8) |
1397
+ ($sbox[$word >> 16 & 0x000000FF] << 16) |
1398
+ ($sbox[$word >> 24 & 0x000000FF] << 24);
1399
+ }
1400
+
1401
+ /**
1402
+ * Performs inverse S-Box substitutions
1403
+ *
1404
+ * @access private
1405
+ */
1406
+ function _invSubWord($word)
1407
+ {
1408
+ $isbox = $this->isbox;
1409
+
1410
+ return $isbox[$word & 0x000000FF] |
1411
+ ($isbox[$word >> 8 & 0x000000FF] << 8) |
1412
+ ($isbox[$word >> 16 & 0x000000FF] << 16) |
1413
+ ($isbox[$word >> 24 & 0x000000FF] << 24);
1414
+ }
1415
+
1416
+ /**
1417
+ * Pad "packets".
1418
+ *
1419
+ * Rijndael works by encrypting between sixteen and thirty-two bytes at a time, provided that number is also a multiple
1420
+ * of four. If you ever need to encrypt or decrypt something that isn't of the proper length, it becomes necessary to
1421
+ * pad the input so that it is of the proper length.
1422
+ *
1423
+ * Padding is enabled by default. Sometimes, however, it is undesirable to pad strings. Such is the case in SSH,
1424
+ * where "packets" are padded with random bytes before being encrypted. Unpad these packets and you risk stripping
1425
+ * away characters that shouldn't be stripped away. (SSH knows how many bytes are added because the length is
1426
+ * transmitted separately)
1427
+ *
1428
+ * @see Crypt_Rijndael::disablePadding()
1429
+ * @access public
1430
+ */
1431
+ function enablePadding()
1432
+ {
1433
+ $this->padding = true;
1434
+ }
1435
+
1436
+ /**
1437
+ * Do not pad packets.
1438
+ *
1439
+ * @see Crypt_Rijndael::enablePadding()
1440
+ * @access public
1441
+ */
1442
+ function disablePadding()
1443
+ {
1444
+ $this->padding = false;
1445
+ }
1446
+
1447
+ /**
1448
+ * Pads a string
1449
+ *
1450
+ * Pads a string using the RSA PKCS padding standards so that its length is a multiple of the blocksize.
1451
+ * $block_size - (strlen($text) % $block_size) bytes are added, each of which is equal to
1452
+ * chr($block_size - (strlen($text) % $block_size)
1453
+ *
1454
+ * If padding is disabled and $text is not a multiple of the blocksize, the string will be padded regardless
1455
+ * and padding will, hence forth, be enabled.
1456
+ *
1457
+ * @see Crypt_Rijndael::_unpad()
1458
+ * @access private
1459
+ */
1460
+ function _pad($text)
1461
+ {
1462
+ $length = strlen($text);
1463
+
1464
+ if (!$this->padding) {
1465
+ if ($length % $this->block_size == 0) {
1466
+ return $text;
1467
+ } else {
1468
+ user_error("The plaintext's length ($length) is not a multiple of the block size ({$this->block_size})");
1469
+ $this->padding = true;
1470
+ }
1471
+ }
1472
+
1473
+ $pad = $this->block_size - ($length % $this->block_size);
1474
+
1475
+ return str_pad($text, $length + $pad, chr($pad));
1476
+ }
1477
+
1478
+ /**
1479
+ * Unpads a string.
1480
+ *
1481
+ * If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong
1482
+ * and false will be returned.
1483
+ *
1484
+ * @see Crypt_Rijndael::_pad()
1485
+ * @access private
1486
+ */
1487
+ function _unpad($text)
1488
+ {
1489
+ if (!$this->padding) {
1490
+ return $text;
1491
+ }
1492
+
1493
+ $length = ord($text[strlen($text) - 1]);
1494
+
1495
+ if (!$length || $length > $this->block_size) {
1496
+ return false;
1497
+ }
1498
+
1499
+ return substr($text, 0, -$length);
1500
+ }
1501
+
1502
+ /**
1503
+ * Treat consecutive "packets" as if they are a continuous buffer.
1504
+ *
1505
+ * Say you have a 32-byte plaintext $plaintext. Using the default behavior, the two following code snippets
1506
+ * will yield different outputs:
1507
+ *
1508
+ * <code>
1509
+ * echo $rijndael->encrypt(substr($plaintext, 0, 16));
1510
+ * echo $rijndael->encrypt(substr($plaintext, 16, 16));
1511
+ * </code>
1512
+ * <code>
1513
+ * echo $rijndael->encrypt($plaintext);
1514
+ * </code>
1515
+ *
1516
+ * The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates
1517
+ * another, as demonstrated with the following:
1518
+ *
1519
+ * <code>
1520
+ * $rijndael->encrypt(substr($plaintext, 0, 16));
1521
+ * echo $rijndael->decrypt($des->encrypt(substr($plaintext, 16, 16)));
1522
+ * </code>
1523
+ * <code>
1524
+ * echo $rijndael->decrypt($des->encrypt(substr($plaintext, 16, 16)));
1525
+ * </code>
1526
+ *
1527
+ * With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different
1528
+ * outputs. The reason is due to the fact that the initialization vector's change after every encryption /
1529
+ * decryption round when the continuous buffer is enabled. When it's disabled, they remain constant.
1530
+ *
1531
+ * Put another way, when the continuous buffer is enabled, the state of the Crypt_Rijndael() object changes after each
1532
+ * encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that
1533
+ * continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them),
1534
+ * however, they are also less intuitive and more likely to cause you problems.
1535
+ *
1536
+ * @see Crypt_Rijndael::disableContinuousBuffer()
1537
+ * @access public
1538
+ */
1539
+ function enableContinuousBuffer()
1540
+ {
1541
+ $this->continuousBuffer = true;
1542
+ }
1543
+
1544
+ /**
1545
+ * Treat consecutive packets as if they are a discontinuous buffer.
1546
+ *
1547
+ * The default behavior.
1548
+ *
1549
+ * @see Crypt_Rijndael::enableContinuousBuffer()
1550
+ * @access public
1551
+ */
1552
+ function disableContinuousBuffer()
1553
+ {
1554
+ $this->continuousBuffer = false;
1555
+ $this->encryptIV = $this->iv;
1556
+ $this->decryptIV = $this->iv;
1557
+ $this->enbuffer = array('encrypted' => '', 'xor' => '', 'pos' => 0);
1558
+ $this->debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0);
1559
+ }
1560
+
1561
+ /**
1562
+ * String Shift
1563
+ *
1564
+ * Inspired by array_shift
1565
+ *
1566
+ * @param String $string
1567
+ * @param optional Integer $index
1568
+ * @return String
1569
+ * @access private
1570
+ */
1571
+ function _string_shift(&$string, $index = 1)
1572
+ {
1573
+ $substr = substr($string, 0, $index);
1574
+ $string = substr($string, $index);
1575
+ return $substr;
1576
+ }
1577
+
1578
+ /**
1579
+ * Creates performance-optimized function for de/encrypt(), storing it in $this->inline_crypt
1580
+ *
1581
+ * @see Crypt_Rijndael::encrypt()
1582
+ * @see Crypt_Rijndael::decrypt()
1583
+ * @access private
1584
+ */
1585
+ function inline_crypt_setup()
1586
+ {
1587
+ // Note: inline_crypt_setup() will be called only if $this->changed === true
1588
+ // So here we are'nt under the same heavy timing-stress as we are in _de/encryptBlock() or de/encrypt().
1589
+ // However...the here generated function- $code, stored as php callback in $this->inline_crypt, must work as fast as even possible.
1590
+
1591
+ $lambda_functions =& Crypt_Rijndael::get_lambda_functions();
1592
+ $block_size = $this->block_size;
1593
+ $mode = $this->mode;
1594
+
1595
+ // The first 5 generated $lambda_functions will use the key-words hardcoded for better performance.
1596
+ // For memory reason we limit those ultra-optimized function code to 5.
1597
+ // After that, we use pure (extracted) integer vars for the key-words which is faster than accessing them via array.
1598
+ if (count($lambda_functions) < 5) {
1599
+ $w = $this->w;
1600
+ $dw = $this->dw;
1601
+ $init_encryptBlock = '';
1602
+ $init_decryptBlock = '';
1603
+ } else {
1604
+ for ($i = 0, $cw = count($this->w); $i < $cw; ++$i) {
1605
+ $w[] = '$w_'.$i;
1606
+ $dw[] = '$dw_'.$i;
1607
+ }
1608
+ $init_encryptBlock = 'extract($self->w, EXTR_PREFIX_ALL, "w");';
1609
+ $init_decryptBlock = 'extract($self->dw, EXTR_PREFIX_ALL, "dw");';
1610
+ }
1611
+
1612
+ $code_hash = md5("$mode, $block_size, " . implode(',', $w));
1613
+
1614
+ if (!isset($lambda_functions[$code_hash])) {
1615
+ $Nr = $this->Nr;
1616
+ $Nb = $this->Nb;
1617
+ $c = $this->c;
1618
+
1619
+ // Generating encrypt code:
1620
+ $init_encryptBlock.= '
1621
+ $t0 = $self->t0;
1622
+ $t1 = $self->t1;
1623
+ $t2 = $self->t2;
1624
+ $t3 = $self->t3;
1625
+ $sbox = $self->sbox;';
1626
+
1627
+ $s = 'e';
1628
+ $e = 's';
1629
+ $wc = $Nb - 1;
1630
+
1631
+ // Preround: addRoundKey
1632
+ $_encryptBlock = '$in = unpack("N*", $in);'."\n";
1633
+ for ($i = 0; $i < $Nb; ++$i) {
1634
+ $_encryptBlock .= '$s'.$i.' = $in['.($i + 1).'] ^ '.$w[++$wc].";\n";
1635
+ }
1636
+
1637
+ // Mainrounds: shiftRows + subWord + mixColumns + addRoundKey
1638
+ for ($round = 1; $round < $Nr; ++$round) {
1639
+ list($s, $e) = array($e, $s);
1640
+ for ($i = 0; $i < $Nb; ++$i) {
1641
+ $_encryptBlock.=
1642
+ '$'.$e.$i.' =
1643
+ $t0[($'.$s.$i .' >> 24) & 0xff] ^
1644
+ $t1[($'.$s.(($i + $c[1]) % $Nb).' >> 16) & 0xff] ^
1645
+ $t2[($'.$s.(($i + $c[2]) % $Nb).' >> 8) & 0xff] ^
1646
+ $t3[ $'.$s.(($i + $c[3]) % $Nb).' & 0xff] ^
1647
+ '.$w[++$wc].";\n";
1648
+ }
1649
+ }
1650
+
1651
+ // Finalround: subWord + shiftRows + addRoundKey
1652
+ for ($i = 0; $i < $Nb; ++$i) {
1653
+ $_encryptBlock.=
1654
+ '$'.$e.$i.' =
1655
+ $sbox[ $'.$e.$i.' & 0xff] |
1656
+ ($sbox[($'.$e.$i.' >> 8) & 0xff] << 8) |
1657
+ ($sbox[($'.$e.$i.' >> 16) & 0xff] << 16) |
1658
+ ($sbox[($'.$e.$i.' >> 24) & 0xff] << 24);'."\n";
1659
+ }
1660
+ $_encryptBlock .= '$in = pack("N*"'."\n";
1661
+ for ($i = 0; $i < $Nb; ++$i) {
1662
+ $_encryptBlock.= ',
1663
+ ($'.$e.$i .' & 0xFF000000) ^
1664
+ ($'.$e.(($i + $c[1]) % $Nb).' & 0x00FF0000) ^
1665
+ ($'.$e.(($i + $c[2]) % $Nb).' & 0x0000FF00) ^
1666
+ ($'.$e.(($i + $c[3]) % $Nb).' & 0x000000FF) ^
1667
+ '.$w[$i]."\n";
1668
+ }
1669
+ $_encryptBlock .= ');';
1670
+
1671
+ // Generating decrypt code:
1672
+ $init_decryptBlock.= '
1673
+ $dt0 = $self->dt0;
1674
+ $dt1 = $self->dt1;
1675
+ $dt2 = $self->dt2;
1676
+ $dt3 = $self->dt3;
1677
+ $isbox = $self->isbox;';
1678
+
1679
+ $s = 'e';
1680
+ $e = 's';
1681
+ $wc = $Nb - 1;
1682
+
1683
+ // Preround: addRoundKey
1684
+ $_decryptBlock = '$in = unpack("N*", $in);'."\n";
1685
+ for ($i = 0; $i < $Nb; ++$i) {
1686
+ $_decryptBlock .= '$s'.$i.' = $in['.($i + 1).'] ^ '.$dw[++$wc].';'."\n";
1687
+ }
1688
+
1689
+ // Mainrounds: shiftRows + subWord + mixColumns + addRoundKey
1690
+ for ($round = 1; $round < $Nr; ++$round) {
1691
+ list($s, $e) = array($e, $s);
1692
+ for ($i = 0; $i < $Nb; ++$i) {
1693
+ $_decryptBlock.=
1694
+ '$'.$e.$i.' =
1695
+ $dt0[($'.$s.$i .' >> 24) & 0xff] ^
1696
+ $dt1[($'.$s.(($Nb + $i - $c[1]) % $Nb).' >> 16) & 0xff] ^
1697
+ $dt2[($'.$s.(($Nb + $i - $c[2]) % $Nb).' >> 8) & 0xff] ^
1698
+ $dt3[ $'.$s.(($Nb + $i - $c[3]) % $Nb).' & 0xff] ^
1699
+ '.$dw[++$wc].";\n";
1700
+ }
1701
+ }
1702
+
1703
+ // Finalround: subWord + shiftRows + addRoundKey
1704
+ for ($i = 0; $i < $Nb; ++$i) {
1705
+ $_decryptBlock.=
1706
+ '$'.$e.$i.' =
1707
+ $isbox[ $'.$e.$i.' & 0xff] |
1708
+ ($isbox[($'.$e.$i.' >> 8) & 0xff] << 8) |
1709
+ ($isbox[($'.$e.$i.' >> 16) & 0xff] << 16) |
1710
+ ($isbox[($'.$e.$i.' >> 24) & 0xff] << 24);'."\n";
1711
+ }
1712
+ $_decryptBlock .= '$in = pack("N*"'."\n";
1713
+ for ($i = 0; $i < $Nb; ++$i) {
1714
+ $_decryptBlock.= ',
1715
+ ($'.$e.$i. ' & 0xFF000000) ^
1716
+ ($'.$e.(($Nb + $i - $c[1]) % $Nb).' & 0x00FF0000) ^
1717
+ ($'.$e.(($Nb + $i - $c[2]) % $Nb).' & 0x0000FF00) ^
1718
+ ($'.$e.(($Nb + $i - $c[3]) % $Nb).' & 0x000000FF) ^
1719
+ '.$dw[$i]."\n";
1720
+ }
1721
+ $_decryptBlock .= ');';
1722
+
1723
+ // Generating mode of operation code:
1724
+ switch ($mode) {
1725
+ case CRYPT_RIJNDAEL_MODE_ECB:
1726
+ $encrypt = $init_encryptBlock . '
1727
+ $ciphertext = "";
1728
+ $text = $self->_pad($text);
1729
+ $plaintext_len = strlen($text);
1730
+
1731
+ for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') {
1732
+ $in = substr($text, $i, '.$block_size.');
1733
+ '.$_encryptBlock.'
1734
+ $ciphertext.= $in;
1735
+ }
1736
+
1737
+ return $ciphertext;
1738
+ ';
1739
+
1740
+ $decrypt = $init_decryptBlock . '
1741
+ $plaintext = "";
1742
+ $text = str_pad($text, strlen($text) + ('.$block_size.' - strlen($text) % '.$block_size.') % '.$block_size.', chr(0));
1743
+ $ciphertext_len = strlen($text);
1744
+
1745
+ for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') {
1746
+ $in = substr($text, $i, '.$block_size.');
1747
+ '.$_decryptBlock.'
1748
+ $plaintext.= $in;
1749
+ }
1750
+
1751
+ return $self->_unpad($plaintext);
1752
+ ';
1753
+ break;
1754
+ case CRYPT_RIJNDAEL_MODE_CBC:
1755
+ $encrypt = $init_encryptBlock . '
1756
+ $ciphertext = "";
1757
+ $text = $self->_pad($text);
1758
+ $plaintext_len = strlen($text);
1759
+
1760
+ $in = $self->encryptIV;
1761
+
1762
+ for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') {
1763
+ $in = substr($text, $i, '.$block_size.') ^ $in;
1764
+ '.$_encryptBlock.'
1765
+ $ciphertext.= $in;
1766
+ }
1767
+
1768
+ if ($self->continuousBuffer) {
1769
+ $self->encryptIV = $in;
1770
+ }
1771
+
1772
+ return $ciphertext;
1773
+ ';
1774
+
1775
+ $decrypt = $init_decryptBlock . '
1776
+ $plaintext = "";
1777
+ $text = str_pad($text, strlen($text) + ('.$block_size.' - strlen($text) % '.$block_size.') % '.$block_size.', chr(0));
1778
+ $ciphertext_len = strlen($text);
1779
+
1780
+ $iv = $self->decryptIV;
1781
+
1782
+ for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') {
1783
+ $in = $block = substr($text, $i, '.$block_size.');
1784
+ '.$_decryptBlock.'
1785
+ $plaintext.= $in ^ $iv;
1786
+ $iv = $block;
1787
+ }
1788
+
1789
+ if ($self->continuousBuffer) {
1790
+ $self->decryptIV = $iv;
1791
+ }
1792
+
1793
+ return $self->_unpad($plaintext);
1794
+ ';
1795
+ break;
1796
+ case CRYPT_RIJNDAEL_MODE_CTR:
1797
+ $encrypt = $init_encryptBlock . '
1798
+ $ciphertext = "";
1799
+ $plaintext_len = strlen($text);
1800
+ $xor = $self->encryptIV;
1801
+ $buffer = &$self->enbuffer;
1802
+
1803
+ if (strlen($buffer["encrypted"])) {
1804
+ for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') {
1805
+ $block = substr($text, $i, '.$block_size.');
1806
+ if (strlen($block) > strlen($buffer["encrypted"])) {
1807
+ $in = $self->_generate_xor('.$block_size.', $xor);
1808
+ '.$_encryptBlock.'
1809
+ $buffer["encrypted"].= $in;
1810
+ }
1811
+ $key = $self->_string_shift($buffer["encrypted"], '.$block_size.');
1812
+ $ciphertext.= $block ^ $key;
1813
+ }
1814
+ } else {
1815
+ for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') {
1816
+ $block = substr($text, $i, '.$block_size.');
1817
+ $in = $self->_generate_xor('.$block_size.', $xor);
1818
+ '.$_encryptBlock.'
1819
+ $key = $in;
1820
+ $ciphertext.= $block ^ $key;
1821
+ }
1822
+ }
1823
+ if ($self->continuousBuffer) {
1824
+ $self->encryptIV = $xor;
1825
+ if ($start = $plaintext_len % '.$block_size.') {
1826
+ $buffer["encrypted"] = substr($key, $start) . $buffer["encrypted"];
1827
+ }
1828
+ }
1829
+
1830
+ return $ciphertext;
1831
+ ';
1832
+
1833
+ $decrypt = $init_encryptBlock . '
1834
+ $plaintext = "";
1835
+ $ciphertext_len = strlen($text);
1836
+ $xor = $self->decryptIV;
1837
+ $buffer = &$self->debuffer;
1838
+
1839
+ if (strlen($buffer["ciphertext"])) {
1840
+ for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') {
1841
+ $block = substr($text, $i, '.$block_size.');
1842
+ if (strlen($block) > strlen($buffer["ciphertext"])) {
1843
+ $in = $self->_generate_xor('.$block_size.', $xor);
1844
+ '.$_encryptBlock.'
1845
+ $buffer["ciphertext"].= $in;
1846
+ }
1847
+ $key = $self->_string_shift($buffer["ciphertext"], '.$block_size.');
1848
+ $plaintext.= $block ^ $key;
1849
+ }
1850
+ } else {
1851
+ for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') {
1852
+ $block = substr($text, $i, '.$block_size.');
1853
+ $in = $self->_generate_xor('.$block_size.', $xor);
1854
+ '.$_encryptBlock.'
1855
+ $key = $in;
1856
+ $plaintext.= $block ^ $key;
1857
+ }
1858
+ }
1859
+ if ($self->continuousBuffer) {
1860
+ $self->decryptIV = $xor;
1861
+ if ($start = $ciphertext_len % '.$block_size.') {
1862
+ $buffer["ciphertext"] = substr($key, $start) . $buffer["ciphertext"];
1863
+ }
1864
+ }
1865
+
1866
+ return $plaintext;
1867
+ ';
1868
+ break;
1869
+ case CRYPT_RIJNDAEL_MODE_CFB:
1870
+ $encrypt = $init_encryptBlock . '
1871
+ $ciphertext = "";
1872
+ $buffer = &$self->enbuffer;
1873
+
1874
+ if ($self->continuousBuffer) {
1875
+ $iv = &$self->encryptIV;
1876
+ $pos = &$buffer["pos"];
1877
+ } else {
1878
+ $iv = $self->encryptIV;
1879
+ $pos = 0;
1880
+ }
1881
+ $len = strlen($text);
1882
+ $i = 0;
1883
+ if ($pos) {
1884
+ $orig_pos = $pos;
1885
+ $max = '.$block_size.' - $pos;
1886
+ if ($len >= $max) {
1887
+ $i = $max;
1888
+ $len-= $max;
1889
+ $pos = 0;
1890
+ } else {
1891
+ $i = $len;
1892
+ $pos+= $len;
1893
+ $len = 0;
1894
+ }
1895
+ $ciphertext = substr($iv, $orig_pos) ^ $text;
1896
+ $iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
1897
+ }
1898
+ while ($len >= '.$block_size.') {
1899
+ $in = $iv;
1900
+ '.$_encryptBlock.';
1901
+ $iv = $in ^ substr($text, $i, '.$block_size.');
1902
+ $ciphertext.= $iv;
1903
+ $len-= '.$block_size.';
1904
+ $i+= '.$block_size.';
1905
+ }
1906
+ if ($len) {
1907
+ $in = $iv;
1908
+ '.$_encryptBlock.'
1909
+ $iv = $in;
1910
+ $block = $iv ^ substr($text, $i);
1911
+ $iv = substr_replace($iv, $block, 0, $len);
1912
+ $ciphertext.= $block;
1913
+ $pos = $len;
1914
+ }
1915
+ return $ciphertext;
1916
+ ';
1917
+
1918
+ $decrypt = $init_encryptBlock . '
1919
+ $plaintext = "";
1920
+ $buffer = &$self->debuffer;
1921
+
1922
+ if ($self->continuousBuffer) {
1923
+ $iv = &$self->decryptIV;
1924
+ $pos = &$buffer["pos"];
1925
+ } else {
1926
+ $iv = $self->decryptIV;
1927
+ $pos = 0;
1928
+ }
1929
+ $len = strlen($text);
1930
+ $i = 0;
1931
+ if ($pos) {
1932
+ $orig_pos = $pos;
1933
+ $max = '.$block_size.' - $pos;
1934
+ if ($len >= $max) {
1935
+ $i = $max;
1936
+ $len-= $max;
1937
+ $pos = 0;
1938
+ } else {
1939
+ $i = $len;
1940
+ $pos+= $len;
1941
+ $len = 0;
1942
+ }
1943
+ $plaintext = substr($iv, $orig_pos) ^ $text;
1944
+ $iv = substr_replace($iv, substr($text, 0, $i), $orig_pos, $i);
1945
+ }
1946
+ while ($len >= '.$block_size.') {
1947
+ $in = $iv;
1948
+ '.$_encryptBlock.'
1949
+ $iv = $in;
1950
+ $cb = substr($text, $i, '.$block_size.');
1951
+ $plaintext.= $iv ^ $cb;
1952
+ $iv = $cb;
1953
+ $len-= '.$block_size.';
1954
+ $i+= '.$block_size.';
1955
+ }
1956
+ if ($len) {
1957
+ $in = $iv;
1958
+ '.$_encryptBlock.'
1959
+ $iv = $in;
1960
+ $plaintext.= $iv ^ substr($text, $i);
1961
+ $iv = substr_replace($iv, substr($text, $i), 0, $len);
1962
+ $pos = $len;
1963
+ }
1964
+
1965
+ return $plaintext;
1966
+ ';
1967
+ break;
1968
+ case CRYPT_RIJNDAEL_MODE_OFB:
1969
+ $encrypt = $init_encryptBlock . '
1970
+ $ciphertext = "";
1971
+ $plaintext_len = strlen($text);
1972
+ $xor = $self->encryptIV;
1973
+ $buffer = &$self->enbuffer;
1974
+
1975
+ if (strlen($buffer["xor"])) {
1976
+ for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') {
1977
+ $block = substr($text, $i, '.$block_size.');
1978
+ if (strlen($block) > strlen($buffer["xor"])) {
1979
+ $in = $xor;
1980
+ '.$_encryptBlock.'
1981
+ $xor = $in;
1982
+ $buffer["xor"].= $xor;
1983
+ }
1984
+ $key = $self->_string_shift($buffer["xor"], '.$block_size.');
1985
+ $ciphertext.= $block ^ $key;
1986
+ }
1987
+ } else {
1988
+ for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') {
1989
+ $in = $xor;
1990
+ '.$_encryptBlock.'
1991
+ $xor = $in;
1992
+ $ciphertext.= substr($text, $i, '.$block_size.') ^ $xor;
1993
+ }
1994
+ $key = $xor;
1995
+ }
1996
+ if ($self->continuousBuffer) {
1997
+ $self->encryptIV = $xor;
1998
+ if ($start = $plaintext_len % '.$block_size.') {
1999
+ $buffer["xor"] = substr($key, $start) . $buffer["xor"];
2000
+ }
2001
+ }
2002
+ return $ciphertext;
2003
+ ';
2004
+
2005
+ $decrypt = $init_encryptBlock . '
2006
+ $plaintext = "";
2007
+ $ciphertext_len = strlen($text);
2008
+ $xor = $self->decryptIV;
2009
+ $buffer = &$self->debuffer;
2010
+
2011
+ if (strlen($buffer["xor"])) {
2012
+ for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') {
2013
+ $block = substr($text, $i, '.$block_size.');
2014
+ if (strlen($block) > strlen($buffer["xor"])) {
2015
+ $in = $xor;
2016
+ '.$_encryptBlock.'
2017
+ $xor = $in;
2018
+ $buffer["xor"].= $xor;
2019
+ }
2020
+ $key = $self->_string_shift($buffer["xor"], '.$block_size.');
2021
+ $plaintext.= $block ^ $key;
2022
+ }
2023
+ } else {
2024
+ for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') {
2025
+ $in = $xor;
2026
+ '.$_encryptBlock.'
2027
+ $xor = $in;
2028
+ $plaintext.= substr($text, $i, '.$block_size.') ^ $xor;
2029
+ }
2030
+ $key = $xor;
2031
+ }
2032
+ if ($self->continuousBuffer) {
2033
+ $self->decryptIV = $xor;
2034
+ if ($start = $ciphertext_len % '.$block_size.') {
2035
+ $buffer["xor"] = substr($key, $start) . $buffer["xor"];
2036
+ }
2037
+ }
2038
+ return $plaintext;
2039
+ ';
2040
+ break;
2041
+ }
2042
+ $lambda_functions[$code_hash] = create_function('$action, &$self, $text', 'if ($action == "encrypt") { '.$encrypt.' } else { '.$decrypt.' }');
2043
+ }
2044
+ $this->inline_crypt = $lambda_functions[$code_hash];
2045
+ }
2046
+
2047
+ /**
2048
+ * Holds the lambda_functions table (classwide)
2049
+ *
2050
+ * @see Crypt_Rijndael::inline_crypt_setup()
2051
+ * @return Array
2052
+ * @access private
2053
+ */
2054
+ function &get_lambda_functions()
2055
+ {
2056
+ static $functions = array();
2057
+ return $functions;
2058
+ }
2059
+ }
2060
+
2061
+ // vim: ts=4:sw=4:et:
2062
+ // vim6: fdl=1:
modules/phpseclib/Crypt/TripleDES.php ADDED
@@ -0,0 +1,842 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3
+
4
+ /**
5
+ * Pure-PHP implementation of Triple DES.
6
+ *
7
+ * Uses mcrypt, if available, and an internal implementation, otherwise. Operates in the EDE3 mode (encrypt-decrypt-encrypt).
8
+ *
9
+ * PHP versions 4 and 5
10
+ *
11
+ * Here's a short example of how to use this library:
12
+ * <code>
13
+ * <?php
14
+ * include('Crypt/TripleDES.php');
15
+ *
16
+ * $des = new Crypt_TripleDES();
17
+ *
18
+ * $des->setKey('abcdefghijklmnopqrstuvwx');
19
+ *
20
+ * $size = 10 * 1024;
21
+ * $plaintext = '';
22
+ * for ($i = 0; $i < $size; $i++) {
23
+ * $plaintext.= 'a';
24
+ * }
25
+ *
26
+ * echo $des->decrypt($des->encrypt($plaintext));
27
+ * ?>
28
+ * </code>
29
+ *
30
+ * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
31
+ * of this software and associated documentation files (the "Software"), to deal
32
+ * in the Software without restriction, including without limitation the rights
33
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
34
+ * copies of the Software, and to permit persons to whom the Software is
35
+ * furnished to do so, subject to the following conditions:
36
+ *
37
+ * The above copyright notice and this permission notice shall be included in
38
+ * all copies or substantial portions of the Software.
39
+ *
40
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
41
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
42
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
43
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
44
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
45
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
46
+ * THE SOFTWARE.
47
+ *
48
+ * @category Crypt
49
+ * @package Crypt_TripleDES
50
+ * @author Jim Wigginton <terrafrost@php.net>
51
+ * @copyright MMVII Jim Wigginton
52
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
53
+ * @link http://phpseclib.sourceforge.net
54
+ */
55
+
56
+ /**
57
+ * Include Crypt_DES
58
+ */
59
+ if (!class_exists('Crypt_DES')) {
60
+ require_once('DES.php');
61
+ }
62
+
63
+ /**
64
+ * Encrypt / decrypt using inner chaining
65
+ *
66
+ * Inner chaining is used by SSH-1 and is generally considered to be less secure then outer chaining (CRYPT_DES_MODE_CBC3).
67
+ */
68
+ define('CRYPT_DES_MODE_3CBC', -2);
69
+
70
+ /**
71
+ * Encrypt / decrypt using outer chaining
72
+ *
73
+ * Outer chaining is used by SSH-2 and when the mode is set to CRYPT_DES_MODE_CBC.
74
+ */
75
+ define('CRYPT_DES_MODE_CBC3', CRYPT_DES_MODE_CBC);
76
+
77
+ /**
78
+ * Pure-PHP implementation of Triple DES.
79
+ *
80
+ * @author Jim Wigginton <terrafrost@php.net>
81
+ * @version 0.1.0
82
+ * @access public
83
+ * @package Crypt_TerraDES
84
+ */
85
+ class Crypt_TripleDES extends Crypt_DES {
86
+ /**
87
+ * The Crypt_DES objects
88
+ *
89
+ * @var Array
90
+ * @access private
91
+ */
92
+ var $des;
93
+
94
+ /**
95
+ * Default Constructor.
96
+ *
97
+ * Determines whether or not the mcrypt extension should be used. $mode should only, at present, be
98
+ * CRYPT_DES_MODE_ECB or CRYPT_DES_MODE_CBC. If not explictly set, CRYPT_DES_MODE_CBC will be used.
99
+ *
100
+ * @param optional Integer $mode
101
+ * @return Crypt_TripleDES
102
+ * @access public
103
+ */
104
+ function Crypt_TripleDES($mode = CRYPT_DES_MODE_CBC)
105
+ {
106
+ if ( !defined('CRYPT_DES_MODE') ) {
107
+ switch (true) {
108
+ case extension_loaded('mcrypt') && in_array('tripledes', mcrypt_list_algorithms()):
109
+ define('CRYPT_DES_MODE', CRYPT_DES_MODE_MCRYPT);
110
+ break;
111
+ default:
112
+ define('CRYPT_DES_MODE', CRYPT_DES_MODE_INTERNAL);
113
+ }
114
+ }
115
+
116
+ if ( $mode == CRYPT_DES_MODE_3CBC ) {
117
+ $this->mode = CRYPT_DES_MODE_3CBC;
118
+ $this->des = array(
119
+ new Crypt_DES(CRYPT_DES_MODE_CBC),
120
+ new Crypt_DES(CRYPT_DES_MODE_CBC),
121
+ new Crypt_DES(CRYPT_DES_MODE_CBC)
122
+ );
123
+ $this->paddable = true;
124
+
125
+ // we're going to be doing the padding, ourselves, so disable it in the Crypt_DES objects
126
+ $this->des[0]->disablePadding();
127
+ $this->des[1]->disablePadding();
128
+ $this->des[2]->disablePadding();
129
+
130
+ return;
131
+ }
132
+
133
+ switch ( CRYPT_DES_MODE ) {
134
+ case CRYPT_DES_MODE_MCRYPT:
135
+ switch ($mode) {
136
+ case CRYPT_DES_MODE_ECB:
137
+ $this->paddable = true;
138
+ $this->mode = MCRYPT_MODE_ECB;
139
+ break;
140
+ case CRYPT_DES_MODE_CTR:
141
+ $this->mode = 'ctr';
142
+ break;
143
+ case CRYPT_DES_MODE_CFB:
144
+ $this->mode = 'ncfb';
145
+ $this->ecb = mcrypt_module_open(MCRYPT_3DES, '', MCRYPT_MODE_ECB, '');
146
+ break;
147
+ case CRYPT_DES_MODE_OFB:
148
+ $this->mode = MCRYPT_MODE_NOFB;
149
+ break;
150
+ case CRYPT_DES_MODE_CBC:
151
+ default:
152
+ $this->paddable = true;
153
+ $this->mode = MCRYPT_MODE_CBC;
154
+ }
155
+ $this->enmcrypt = mcrypt_module_open(MCRYPT_3DES, '', $this->mode, '');
156
+ $this->demcrypt = mcrypt_module_open(MCRYPT_3DES, '', $this->mode, '');
157
+
158
+ break;
159
+ default:
160
+ $this->des = array(
161
+ new Crypt_DES(CRYPT_DES_MODE_ECB),
162
+ new Crypt_DES(CRYPT_DES_MODE_ECB),
163
+ new Crypt_DES(CRYPT_DES_MODE_ECB)
164
+ );
165
+
166
+ // we're going to be doing the padding, ourselves, so disable it in the Crypt_DES objects
167
+ $this->des[0]->disablePadding();
168
+ $this->des[1]->disablePadding();
169
+ $this->des[2]->disablePadding();
170
+
171
+ switch ($mode) {
172
+ case CRYPT_DES_MODE_ECB:
173
+ case CRYPT_DES_MODE_CBC:
174
+ $this->paddable = true;
175
+ $this->mode = $mode;
176
+ break;
177
+ case CRYPT_DES_MODE_CTR:
178
+ case CRYPT_DES_MODE_CFB:
179
+ case CRYPT_DES_MODE_OFB:
180
+ $this->mode = $mode;
181
+ break;
182
+ default:
183
+ $this->paddable = true;
184
+ $this->mode = CRYPT_DES_MODE_CBC;
185
+ }
186
+ if (function_exists('create_function') && is_callable('create_function')) {
187
+ $this->inline_crypt_setup(3);
188
+ $this->use_inline_crypt = true;
189
+ }
190
+ }
191
+ }
192
+
193
+ /**
194
+ * Sets the key.
195
+ *
196
+ * Keys can be of any length. Triple DES, itself, can use 128-bit (eg. strlen($key) == 16) or
197
+ * 192-bit (eg. strlen($key) == 24) keys. This function pads and truncates $key as appropriate.
198
+ *
199
+ * DES also requires that every eighth bit be a parity bit, however, we'll ignore that.
200
+ *
201
+ * If the key is not explicitly set, it'll be assumed to be all zero's.
202
+ *
203
+ * @access public
204
+ * @param String $key
205
+ */
206
+ function setKey($key)
207
+ {
208
+ $length = strlen($key);
209
+ if ($length > 8) {
210
+ $key = str_pad($key, 24, chr(0));
211
+ // if $key is between 64 and 128-bits, use the first 64-bits as the last, per this:
212
+ // http://php.net/function.mcrypt-encrypt#47973
213
+ //$key = $length <= 16 ? substr_replace($key, substr($key, 0, 8), 16) : substr($key, 0, 24);
214
+ } else {
215
+ $key = str_pad($key, 8, chr(0));
216
+ }
217
+ $this->key = $key;
218
+ switch (true) {
219
+ case CRYPT_DES_MODE == CRYPT_DES_MODE_INTERNAL:
220
+ case $this->mode == CRYPT_DES_MODE_3CBC:
221
+ $this->des[0]->setKey(substr($key, 0, 8));
222
+ $this->des[1]->setKey(substr($key, 8, 8));
223
+ $this->des[2]->setKey(substr($key, 16, 8));
224
+
225
+ // Merge the three DES-1-dim-key-arrays for 3DES-inline-en/decrypting
226
+ if ($this->use_inline_crypt && $this->mode != CRYPT_DES_MODE_3CBC) {
227
+ $this->keys = array(
228
+ CRYPT_DES_ENCRYPT_1DIM => array_merge(
229
+ $this->des[0]->keys[CRYPT_DES_ENCRYPT_1DIM],
230
+ $this->des[1]->keys[CRYPT_DES_DECRYPT_1DIM],
231
+ $this->des[2]->keys[CRYPT_DES_ENCRYPT_1DIM]
232
+ ),
233
+ CRYPT_DES_DECRYPT_1DIM => array_merge(
234
+ $this->des[2]->keys[CRYPT_DES_DECRYPT_1DIM],
235
+ $this->des[1]->keys[CRYPT_DES_ENCRYPT_1DIM],
236
+ $this->des[0]->keys[CRYPT_DES_DECRYPT_1DIM]
237
+ ),
238
+ );
239
+ }
240
+ }
241
+ $this->enchanged = $this->dechanged = true;
242
+ }
243
+
244
+ /**
245
+ * Sets the password.
246
+ *
247
+ * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows:
248
+ * {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2}:
249
+ * $hash, $salt, $method
250
+ *
251
+ * @param String $password
252
+ * @param optional String $method
253
+ * @access public
254
+ */
255
+ function setPassword($password, $method = 'pbkdf2')
256
+ {
257
+ $key = '';
258
+
259
+ switch ($method) {
260
+ default: // 'pbkdf2'
261
+ list(, , $hash, $salt, $count) = func_get_args();
262
+ if (!isset($hash)) {
263
+ $hash = 'sha1';
264
+ }
265
+ // WPA and WPA2 use the SSID as the salt
266
+ if (!isset($salt)) {
267
+ $salt = 'phpseclib';
268
+ }
269
+ // RFC2898#section-4.2 uses 1,000 iterations by default
270
+ // WPA and WPA2 use 4,096.
271
+ if (!isset($count)) {
272
+ $count = 1000;
273
+ }
274
+
275
+ if (!class_exists('Crypt_Hash')) {
276
+ require_once('Crypt/Hash.php');
277
+ }
278
+
279
+ $i = 1;
280
+ while (strlen($key) < 24) { // $dkLen == 24
281
+ $hmac = new Crypt_Hash();
282
+ $hmac->setHash($hash);
283
+ $hmac->setKey($password);
284
+ $f = $u = $hmac->hash($salt . pack('N', $i++));
285
+ for ($j = 2; $j <= $count; $j++) {
286
+ $u = $hmac->hash($u);
287
+ $f^= $u;
288
+ }
289
+ $key.= $f;
290
+ }
291
+ }
292
+
293
+ $this->setKey($key);
294
+ }
295
+
296
+ /**
297
+ * Sets the initialization vector. (optional)
298
+ *
299
+ * SetIV is not required when CRYPT_DES_MODE_ECB is being used. If not explictly set, it'll be assumed
300
+ * to be all zero's.
301
+ *
302
+ * @access public
303
+ * @param String $iv
304
+ */
305
+ function setIV($iv)
306
+ {
307
+ $this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($iv, 0, 8), 8, chr(0));
308
+ if ($this->mode == CRYPT_DES_MODE_3CBC) {
309
+ $this->des[0]->setIV($iv);
310
+ $this->des[1]->setIV($iv);
311
+ $this->des[2]->setIV($iv);
312
+ }
313
+ $this->enchanged = $this->dechanged = true;
314
+ }
315
+
316
+ /**
317
+ * Encrypts a message.
318
+ *
319
+ * @access public
320
+ * @param String $plaintext
321
+ */
322
+ function encrypt($plaintext)
323
+ {
324
+ if ($this->paddable) {
325
+ $plaintext = $this->_pad($plaintext);
326
+ }
327
+
328
+ // if the key is smaller then 8, do what we'd normally do
329
+ if ($this->mode == CRYPT_DES_MODE_3CBC && strlen($this->key) > 8) {
330
+ $ciphertext = $this->des[2]->encrypt($this->des[1]->decrypt($this->des[0]->encrypt($plaintext)));
331
+
332
+ return $ciphertext;
333
+ }
334
+
335
+ if ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) {
336
+ if ($this->enchanged) {
337
+ mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
338
+ if ($this->mode == 'ncfb') {
339
+ mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0");
340
+ }
341
+ $this->enchanged = false;
342
+ }
343
+
344
+ if ($this->mode != 'ncfb' || !$this->continuousBuffer) {
345
+ $ciphertext = mcrypt_generic($this->enmcrypt, $plaintext);
346
+ } else {
347
+ $iv = &$this->encryptIV;
348
+ $pos = &$this->enbuffer['pos'];
349
+ $len = strlen($plaintext);
350
+ $ciphertext = '';
351
+ $i = 0;
352
+ if ($pos) {
353
+ $orig_pos = $pos;
354
+ $max = 8 - $pos;
355
+ if ($len >= $max) {
356
+ $i = $max;
357
+ $len-= $max;
358
+ $pos = 0;
359
+ } else {
360
+ $i = $len;
361
+ $pos+= $len;
362
+ $len = 0;
363
+ }
364
+ $ciphertext = substr($iv, $orig_pos) ^ $plaintext;
365
+ $iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
366
+ $this->enbuffer['enmcrypt_init'] = true;
367
+ }
368
+ if ($len >= 8) {
369
+ if ($this->enbuffer['enmcrypt_init'] === false || $len > 950) {
370
+ if ($this->enbuffer['enmcrypt_init'] === true) {
371
+ mcrypt_generic_init($this->enmcrypt, $this->key, $iv);
372
+ $this->enbuffer['enmcrypt_init'] = false;
373
+ }
374
+ $ciphertext.= mcrypt_generic($this->enmcrypt, substr($plaintext, $i, $len - $len % 8));
375
+ $iv = substr($ciphertext, -8);
376
+ $i = strlen($ciphertext);
377
+ $len%= 8;
378
+ } else {
379
+ while ($len >= 8) {
380
+ $iv = mcrypt_generic($this->ecb, $iv) ^ substr($plaintext, $i, 8);
381
+ $ciphertext.= $iv;
382
+ $len-= 8;
383
+ $i+= 8;
384
+ }
385
+ }
386
+ }
387
+ if ($len) {
388
+ $iv = mcrypt_generic($this->ecb, $iv);
389
+ $block = $iv ^ substr($plaintext, $i);
390
+ $iv = substr_replace($iv, $block, 0, $len);
391
+ $ciphertext.= $block;
392
+ $pos = $len;
393
+ }
394
+ return $ciphertext;
395
+ }
396
+
397
+ if (!$this->continuousBuffer) {
398
+ mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
399
+ }
400
+
401
+ return $ciphertext;
402
+ }
403
+
404
+ if (strlen($this->key) <= 8) {
405
+ $this->des[0]->mode = $this->mode;
406
+
407
+ return $this->des[0]->encrypt($plaintext);
408
+ }
409
+
410
+ if ($this->use_inline_crypt) {
411
+ $inline = $this->inline_crypt;
412
+ return $inline('encrypt', $this, $plaintext);
413
+ }
414
+
415
+ $des = $this->des;
416
+
417
+ $buffer = &$this->enbuffer;
418
+ $continuousBuffer = $this->continuousBuffer;
419
+ $ciphertext = '';
420
+ switch ($this->mode) {
421
+ case CRYPT_DES_MODE_ECB:
422
+ for ($i = 0; $i < strlen($plaintext); $i+=8) {
423
+ $block = substr($plaintext, $i, 8);
424
+ // all of these _processBlock calls could, in theory, be put in a function - say Crypt_TripleDES::_ede_encrypt() or something.
425
+ // only problem with that: it would slow encryption and decryption down. $this->des would have to be called every time that
426
+ // function is called, instead of once for the whole string of text that's being encrypted, which would, in turn, make
427
+ // encryption and decryption take more time, per this:
428
+ //
429
+ // http://blog.libssh2.org/index.php?/archives/21-Compiled-Variables.html
430
+ $block = $des[0]->_processBlock($block, CRYPT_DES_ENCRYPT);
431
+ $block = $des[1]->_processBlock($block, CRYPT_DES_DECRYPT);
432
+ $block = $des[2]->_processBlock($block, CRYPT_DES_ENCRYPT);
433
+ $ciphertext.= $block;
434
+ }
435
+ break;
436
+ case CRYPT_DES_MODE_CBC:
437
+ $xor = $this->encryptIV;
438
+ for ($i = 0; $i < strlen($plaintext); $i+=8) {
439
+ $block = substr($plaintext, $i, 8) ^ $xor;
440
+ $block = $des[0]->_processBlock($block, CRYPT_DES_ENCRYPT);
441
+ $block = $des[1]->_processBlock($block, CRYPT_DES_DECRYPT);
442
+ $block = $des[2]->_processBlock($block, CRYPT_DES_ENCRYPT);
443
+ $xor = $block;
444
+ $ciphertext.= $block;
445
+ }
446
+ if ($this->continuousBuffer) {
447
+ $this->encryptIV = $xor;
448
+ }
449
+ break;
450
+ case CRYPT_DES_MODE_CTR:
451
+ $xor = $this->encryptIV;
452
+ if (strlen($buffer['encrypted'])) {
453
+ for ($i = 0; $i < strlen($plaintext); $i+=8) {
454
+ $block = substr($plaintext, $i, 8);
455
+ if (strlen($block) > strlen($buffer['encrypted'])) {
456
+ $key = $this->_generate_xor($xor);
457
+ $key = $des[0]->_processBlock($key, CRYPT_DES_ENCRYPT);
458
+ $key = $des[1]->_processBlock($key, CRYPT_DES_DECRYPT);
459
+ $key = $des[2]->_processBlock($key, CRYPT_DES_ENCRYPT);
460
+ $buffer['encrypted'].= $key;
461
+ }
462
+ $key = $this->_string_shift($buffer['encrypted']);
463
+ $ciphertext.= $block ^ $key;
464
+ }
465
+ } else {
466
+ for ($i = 0; $i < strlen($plaintext); $i+=8) {
467
+ $block = substr($plaintext, $i, 8);
468
+ $key = $this->_generate_xor($xor);
469
+ $key = $des[0]->_processBlock($key, CRYPT_DES_ENCRYPT);
470
+ $key = $des[1]->_processBlock($key, CRYPT_DES_DECRYPT);
471
+ $key = $des[2]->_processBlock($key, CRYPT_DES_ENCRYPT);
472
+ $ciphertext.= $block ^ $key;
473
+ }
474
+ }
475
+ if ($this->continuousBuffer) {
476
+ $this->encryptIV = $xor;
477
+ if ($start = strlen($plaintext) & 7) {
478
+ $buffer['encrypted'] = substr($key, $start) . $buffer['encrypted'];
479
+ }
480
+ }
481
+ break;
482
+ case CRYPT_DES_MODE_CFB:
483
+ if (strlen($buffer['xor'])) {
484
+ $ciphertext = $plaintext ^ $buffer['xor'];
485
+ $iv = $buffer['encrypted'] . $ciphertext;
486
+ $start = strlen($ciphertext);
487
+ $buffer['encrypted'].= $ciphertext;
488
+ $buffer['xor'] = substr($buffer['xor'], strlen($ciphertext));
489
+ } else {
490
+ $ciphertext = '';
491
+ $iv = $this->encryptIV;
492
+ $start = 0;
493
+ }
494
+
495
+ for ($i = $start; $i < strlen($plaintext); $i+=8) {
496
+ $block = substr($plaintext, $i, 8);
497
+ $iv = $des[0]->_processBlock($iv, CRYPT_DES_ENCRYPT);
498
+ $iv = $des[1]->_processBlock($iv, CRYPT_DES_DECRYPT);
499
+ $xor= $des[2]->_processBlock($iv, CRYPT_DES_ENCRYPT);
500
+
501
+ $iv = $block ^ $xor;
502
+ if ($continuousBuffer && strlen($iv) != 8) {
503
+ $buffer = array(
504
+ 'encrypted' => $iv,
505
+ 'xor' => substr($xor, strlen($iv))
506
+ );
507
+ }
508
+ $ciphertext.= $iv;
509
+ }
510
+
511
+ if ($this->continuousBuffer) {
512
+ $this->encryptIV = $iv;
513
+ }
514
+ break;
515
+ case CRYPT_DES_MODE_OFB:
516
+ $xor = $this->encryptIV;
517
+ if (strlen($buffer['xor'])) {
518
+ for ($i = 0; $i < strlen($plaintext); $i+=8) {
519
+ $block = substr($plaintext, $i, 8);
520
+ if (strlen($block) > strlen($buffer['xor'])) {
521
+ $xor = $des[0]->_processBlock($xor, CRYPT_DES_ENCRYPT);
522
+ $xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT);
523
+ $xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT);
524
+ $buffer['xor'].= $xor;
525
+ }
526
+ $key = $this->_string_shift($buffer['xor']);
527
+ $ciphertext.= $block ^ $key;
528
+ }
529
+ } else {
530
+ for ($i = 0; $i < strlen($plaintext); $i+=8) {
531
+ $xor = $des[0]->_processBlock($xor, CRYPT_DES_ENCRYPT);
532
+ $xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT);
533
+ $xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT);
534
+ $ciphertext.= substr($plaintext, $i, 8) ^ $xor;
535
+ }
536
+ $key = $xor;
537
+ }
538
+ if ($this->continuousBuffer) {
539
+ $this->encryptIV = $xor;
540
+ if ($start = strlen($plaintext) & 7) {
541
+ $buffer['xor'] = substr($key, $start) . $buffer['xor'];
542
+ }
543
+ }
544
+ }
545
+
546
+ return $ciphertext;
547
+ }
548
+
549
+ /**
550
+ * Decrypts a message.
551
+ *
552
+ * @access public
553
+ * @param String $ciphertext
554
+ */
555
+ function decrypt($ciphertext)
556
+ {
557
+ if ($this->mode == CRYPT_DES_MODE_3CBC && strlen($this->key) > 8) {
558
+ $plaintext = $this->des[0]->decrypt($this->des[1]->encrypt($this->des[2]->decrypt($ciphertext)));
559
+
560
+ return $this->_unpad($plaintext);
561
+ }
562
+
563
+ if ($this->paddable) {
564
+ // we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic :
565
+ // "The data is padded with "\0" to make sure the length of the data is n * blocksize."
566
+ $ciphertext = str_pad($ciphertext, (strlen($ciphertext) + 7) & 0xFFFFFFF8, chr(0));
567
+ }
568
+
569
+ if ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) {
570
+ if ($this->dechanged) {
571
+ mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
572
+ if ($this->mode == 'ncfb') {
573
+ mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0");
574
+ }
575
+ $this->dechanged = false;
576
+ }
577
+
578
+ if ($this->mode != 'ncfb' || !$this->continuousBuffer) {
579
+ $plaintext = mdecrypt_generic($this->demcrypt, $ciphertext);
580
+ } else {
581
+ $iv = &$this->decryptIV;
582
+ $pos = &$this->debuffer['pos'];
583
+ $len = strlen($ciphertext);
584
+ $plaintext = '';
585
+ $i = 0;
586
+ if ($pos) {
587
+ $orig_pos = $pos;
588
+ $max = 8 - $pos;
589
+ if ($len >= $max) {
590
+ $i = $max;
591
+ $len-= $max;
592
+ $pos = 0;
593
+ } else {
594
+ $i = $len;
595
+ $pos+= $len;
596
+ $len = 0;
597
+ }
598
+ $plaintext = substr($iv, $orig_pos) ^ $ciphertext;
599
+ $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
600
+ }
601
+ if ($len >= 8) {
602
+ $cb = substr($ciphertext, $i, $len - $len % 8);
603
+ $plaintext.= mcrypt_generic($this->ecb, $iv . $cb) ^ $cb;
604
+ $iv = substr($cb, -8);
605
+ $len%= 8;
606
+ }
607
+ if ($len) {
608
+ $iv = mcrypt_generic($this->ecb, $iv);
609
+ $cb = substr($ciphertext, -$len);
610
+ $plaintext.= $iv ^ $cb;
611
+ $iv = substr_replace($iv, $cb, 0, $len);
612
+ $pos = $len;
613
+ }
614
+ return $plaintext;
615
+ }
616
+
617
+ if (!$this->continuousBuffer) {
618
+ mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
619
+ }
620
+
621
+ return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
622
+ }
623
+
624
+ if (strlen($this->key) <= 8) {
625
+ $this->des[0]->mode = $this->mode;
626
+ $plaintext = $this->des[0]->decrypt($ciphertext);
627
+ return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
628
+ }
629
+
630
+ if ($this->use_inline_crypt) {
631
+ $inline = $this->inline_crypt;
632
+ return $inline('decrypt', $this, $ciphertext);
633
+ }
634
+
635
+ $des = $this->des;
636
+
637
+ $buffer = &$this->debuffer;
638
+ $continuousBuffer = $this->continuousBuffer;
639
+ $plaintext = '';
640
+ switch ($this->mode) {
641
+ case CRYPT_DES_MODE_ECB:
642
+ for ($i = 0; $i < strlen($ciphertext); $i+=8) {
643
+ $block = substr($ciphertext, $i, 8);
644
+ $block = $des[2]->_processBlock($block, CRYPT_DES_DECRYPT);
645
+ $block = $des[1]->_processBlock($block, CRYPT_DES_ENCRYPT);
646
+ $block = $des[0]->_processBlock($block, CRYPT_DES_DECRYPT);
647
+ $plaintext.= $block;
648
+ }
649
+ break;
650
+ case CRYPT_DES_MODE_CBC:
651
+ $xor = $this->decryptIV;
652
+ for ($i = 0; $i < strlen($ciphertext); $i+=8) {
653
+ $orig = $block = substr($ciphertext, $i, 8);
654
+ $block = $des[2]->_processBlock($block, CRYPT_DES_DECRYPT);
655
+ $block = $des[1]->_processBlock($block, CRYPT_DES_ENCRYPT);
656
+ $block = $des[0]->_processBlock($block, CRYPT_DES_DECRYPT);
657
+ $plaintext.= $block ^ $xor;
658
+ $xor = $orig;
659
+ }
660
+ if ($this->continuousBuffer) {
661
+ $this->decryptIV = $xor;
662
+ }
663
+ break;
664
+ case CRYPT_DES_MODE_CTR:
665
+ $xor = $this->decryptIV;
666
+ if (strlen($buffer['ciphertext'])) {
667
+ for ($i = 0; $i < strlen($ciphertext); $i+=8) {
668
+ $block = substr($ciphertext, $i, 8);
669
+ if (strlen($block) > strlen($buffer['ciphertext'])) {
670
+ $key = $this->_generate_xor($xor);
671
+ $key = $des[0]->_processBlock($key, CRYPT_DES_ENCRYPT);
672
+ $key = $des[1]->_processBlock($key, CRYPT_DES_DECRYPT);
673
+ $key = $des[2]->_processBlock($key, CRYPT_DES_ENCRYPT);
674
+ $buffer['ciphertext'].= $key;
675
+ }
676
+ $key = $this->_string_shift($buffer['ciphertext']);
677
+ $plaintext.= $block ^ $key;
678
+ }
679
+ } else {
680
+ for ($i = 0; $i < strlen($ciphertext); $i+=8) {
681
+ $block = substr($ciphertext, $i, 8);
682
+ $key = $this->_generate_xor($xor);
683
+ $key = $des[0]->_processBlock($key, CRYPT_DES_ENCRYPT);
684
+ $key = $des[1]->_processBlock($key, CRYPT_DES_DECRYPT);
685
+ $key = $des[2]->_processBlock($key, CRYPT_DES_ENCRYPT);
686
+ $plaintext.= $block ^ $key;
687
+ }
688
+ }
689
+ if ($this->continuousBuffer) {
690
+ $this->decryptIV = $xor;
691
+ if ($start = strlen($plaintext) & 7) {
692
+ $buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext'];
693
+ }
694
+ }
695
+ break;
696
+ case CRYPT_DES_MODE_CFB:
697
+ if (strlen($buffer['ciphertext'])) {
698
+ $plaintext = $ciphertext ^ substr($this->decryptIV, strlen($buffer['ciphertext']));
699
+ $buffer['ciphertext'].= substr($ciphertext, 0, strlen($plaintext));
700
+ if (strlen($buffer['ciphertext']) != 8) {
701
+ $block = $this->decryptIV;
702
+ } else {
703
+ $block = $buffer['ciphertext'];
704
+ $xor = $des[0]->_processBlock($buffer['ciphertext'], CRYPT_DES_ENCRYPT);
705
+ $xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT);
706
+ $xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT);
707
+ $buffer['ciphertext'] = '';
708
+ }
709
+ $start = strlen($plaintext);
710
+ } else {
711
+ $plaintext = '';
712
+ $xor = $des[0]->_processBlock($this->decryptIV, CRYPT_DES_ENCRYPT);
713
+ $xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT);
714
+ $xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT);
715
+ $start = 0;
716
+ }
717
+
718
+ for ($i = $start; $i < strlen($ciphertext); $i+=8) {
719
+ $block = substr($ciphertext, $i, 8);
720
+ $plaintext.= $block ^ $xor;
721
+ if ($continuousBuffer && strlen($block) != 8) {
722
+ $buffer['ciphertext'].= $block;
723
+ $block = $xor;
724
+ } else if (strlen($block) == 8) {
725
+ $xor = $des[0]->_processBlock($block, CRYPT_DES_ENCRYPT);
726
+ $xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT);
727
+ $xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT);
728
+ }
729
+ }
730
+ if ($this->continuousBuffer) {
731
+ $this->decryptIV = $block;
732
+ }
733
+ break;
734
+ case CRYPT_DES_MODE_OFB:
735
+ $xor = $this->decryptIV;
736
+ if (strlen($buffer['xor'])) {
737
+ for ($i = 0; $i < strlen($ciphertext); $i+=8) {
738
+ $block = substr($ciphertext, $i, 8);
739
+ if (strlen($block) > strlen($buffer['xor'])) {
740
+ $xor = $des[0]->_processBlock($xor, CRYPT_DES_ENCRYPT);
741
+ $xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT);
742
+ $xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT);
743
+ $buffer['xor'].= $xor;
744
+ }
745
+ $key = $this->_string_shift($buffer['xor']);
746
+ $plaintext.= $block ^ $key;
747
+ }
748
+ } else {
749
+ for ($i = 0; $i < strlen($ciphertext); $i+=8) {
750
+ $xor = $des[0]->_processBlock($xor, CRYPT_DES_ENCRYPT);
751
+ $xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT);
752
+ $xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT);
753
+ $plaintext.= substr($ciphertext, $i, 8) ^ $xor;
754
+ }
755
+ $key = $xor;
756
+ }
757
+ if ($this->continuousBuffer) {
758
+ $this->decryptIV = $xor;
759
+ if ($start = strlen($ciphertext) & 7) {
760
+ $buffer['xor'] = substr($key, $start) . $buffer['xor'];
761
+ }
762
+ }
763
+ }
764
+
765
+ return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
766
+ }
767
+
768
+ /**
769
+ * Treat consecutive "packets" as if they are a continuous buffer.
770
+ *
771
+ * Say you have a 16-byte plaintext $plaintext. Using the default behavior, the two following code snippets
772
+ * will yield different outputs:
773
+ *
774
+ * <code>
775
+ * echo $des->encrypt(substr($plaintext, 0, 8));
776
+ * echo $des->encrypt(substr($plaintext, 8, 8));
777
+ * </code>
778
+ * <code>
779
+ * echo $des->encrypt($plaintext);
780
+ * </code>
781
+ *
782
+ * The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates
783
+ * another, as demonstrated with the following:
784
+ *
785
+ * <code>
786
+ * $des->encrypt(substr($plaintext, 0, 8));
787
+ * echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8)));
788
+ * </code>
789
+ * <code>
790
+ * echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8)));
791
+ * </code>
792
+ *
793
+ * With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different
794
+ * outputs. The reason is due to the fact that the initialization vector's change after every encryption /
795
+ * decryption round when the continuous buffer is enabled. When it's disabled, they remain constant.
796
+ *
797
+ * Put another way, when the continuous buffer is enabled, the state of the Crypt_DES() object changes after each
798
+ * encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that
799
+ * continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them),
800
+ * however, they are also less intuitive and more likely to cause you problems.
801
+ *
802
+ * @see Crypt_TripleDES::disableContinuousBuffer()
803
+ * @access public
804
+ */
805
+ function enableContinuousBuffer()
806
+ {
807
+ $this->continuousBuffer = true;
808
+ if ($this->mode == CRYPT_DES_MODE_3CBC) {
809
+ $this->des[0]->enableContinuousBuffer();
810
+ $this->des[1]->enableContinuousBuffer();
811
+ $this->des[2]->enableContinuousBuffer();
812
+ }
813
+ }
814
+
815
+ /**
816
+ * Treat consecutive packets as if they are a discontinuous buffer.
817
+ *
818
+ * The default behavior.
819
+ *
820
+ * @see Crypt_TripleDES::enableContinuousBuffer()
821
+ * @access public
822
+ */
823
+ function disableContinuousBuffer()
824
+ {
825
+ $this->continuousBuffer = false;
826
+ $this->encryptIV = $this->iv;
827
+ $this->decryptIV = $this->iv;
828
+ $this->enchanged = true;
829
+ $this->dechanged = true;
830
+ $this->enbuffer = array('encrypted' => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true);
831
+ $this->debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0, 'demcrypt_init' => true);
832
+
833
+ if ($this->mode == CRYPT_DES_MODE_3CBC) {
834
+ $this->des[0]->disableContinuousBuffer();
835
+ $this->des[1]->disableContinuousBuffer();
836
+ $this->des[2]->disableContinuousBuffer();
837
+ }
838
+ }
839
+ }
840
+
841
+ // vim: ts=4:sw=4:et:
842
+ // vim6: fdl=1:
modules/phpseclib/Crypt/Twofish.php ADDED
@@ -0,0 +1,1664 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3
+
4
+ /**
5
+ * Pure-PHP implementation of Twofish.
6
+ *
7
+ * Uses mcrypt, if available, and an internal implementation, otherwise.
8
+ *
9
+ * PHP versions 4 and 5
10
+ *
11
+ * Useful resources are as follows:
12
+ *
13
+ * - {@link http://en.wikipedia.org/wiki/Twofish Wikipedia description of Twofish}
14
+ *
15
+ * Here's a short example of how to use this library:
16
+ * <code>
17
+ * <?php
18
+ * include('Crypt/Twofish.php');
19
+ *
20
+ * $Twofish = new Crypt_Twofish();
21
+ *
22
+ * $Twofish->setKey('12345678901234567890123456789012');
23
+ *
24
+ * $plaintext = str_repeat('a', 1024);
25
+ *
26
+ * echo $Twofish->decrypt($Twofish->encrypt($plaintext));
27
+ * ?>
28
+ * </code>
29
+ *
30
+ * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
31
+ * of this software and associated documentation files (the "Software"), to deal
32
+ * in the Software without restriction, including without limitation the rights
33
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
34
+ * copies of the Software, and to permit persons to whom the Software is
35
+ * furnished to do so, subject to the following conditions:
36
+ *
37
+ * The above copyright notice and this permission notice shall be included in
38
+ * all copies or substantial portions of the Software.
39
+ *
40
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
41
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
42
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
43
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
44
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
45
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
46
+ * THE SOFTWARE.
47
+ *
48
+ * @category Crypt
49
+ * @package Crypt_Twofish
50
+ * @author Jim Wigginton <terrafrost@php.net>
51
+ * @author Hans-Juergen Petrich <petrich@tronic-media.com>
52
+ * @copyright MMVII Jim Wigginton
53
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
54
+ * @version 1.0
55
+ * @link http://phpseclib.sourceforge.net
56
+ */
57
+
58
+ /**#@+
59
+ * @access public
60
+ * @see Crypt_Twofish::encrypt()
61
+ * @see Crypt_Twofish::decrypt()
62
+ */
63
+ /**
64
+ * Encrypt / decrypt using the Counter mode.
65
+ *
66
+ * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
67
+ *
68
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
69
+ */
70
+ define('CRYPT_TWOFISH_MODE_CTR', -1);
71
+ /**
72
+ * Encrypt / decrypt using the Electronic Code Book mode.
73
+ *
74
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
75
+ */
76
+ define('CRYPT_TWOFISH_MODE_ECB', 1);
77
+ /**
78
+ * Encrypt / decrypt using the Code Book Chaining mode.
79
+ *
80
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
81
+ */
82
+ define('CRYPT_TWOFISH_MODE_CBC', 2);
83
+ /**
84
+ * Encrypt / decrypt using the Cipher Feedback mode.
85
+ *
86
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
87
+ */
88
+ define('CRYPT_TWOFISH_MODE_CFB', 3);
89
+ /**
90
+ * Encrypt / decrypt using the Cipher Feedback mode.
91
+ *
92
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
93
+ */
94
+ define('CRYPT_TWOFISH_MODE_OFB', 4);
95
+ /**#@-*/
96
+
97
+ /**#@+
98
+ * @access private
99
+ * @see Crypt_Twofish::Crypt_Twofish()
100
+ */
101
+ /**
102
+ * Toggles the internal implementation
103
+ */
104
+ define('CRYPT_TWOFISH_MODE_INTERNAL', 1);
105
+ /**
106
+ * Toggles the mcrypt implementation
107
+ */
108
+ define('CRYPT_TWOFISH_MODE_MCRYPT', 2);
109
+ /**#@-*/
110
+
111
+ /**
112
+ * Pure-PHP implementation of Twofish.
113
+ *
114
+ * @author Jim Wigginton <terrafrost@php.net>
115
+ * @author Hans-Juergen Petrich <petrich@tronic-media.com>
116
+ * @version 1.0
117
+ * @access public
118
+ * @package Crypt_Twofish
119
+ */
120
+ class Crypt_Twofish {
121
+ /**
122
+ * The Key as String
123
+ *
124
+ * @see Crypt_Twofish::setKey()
125
+ * @var Array
126
+ * @access private
127
+ */
128
+ var $key = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
129
+
130
+ /**
131
+ * The Encryption Mode
132
+ *
133
+ * @see Crypt_Twofish::Crypt_Twofish()
134
+ * @var Integer
135
+ * @access private
136
+ */
137
+ var $mode;
138
+
139
+ /**
140
+ * Continuous Buffer status
141
+ *
142
+ * @see Crypt_Twofish::enableContinuousBuffer()
143
+ * @var Boolean
144
+ * @access private
145
+ */
146
+ var $continuousBuffer = false;
147
+
148
+ /**
149
+ * Padding status
150
+ *
151
+ * @see Crypt_Twofish::enablePadding()
152
+ * @var Boolean
153
+ * @access private
154
+ */
155
+ var $padding = true;
156
+
157
+ /**
158
+ * The Initialization Vector
159
+ *
160
+ * @see Crypt_Twofish::setIV()
161
+ * @var String
162
+ * @access private
163
+ */
164
+ var $iv = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
165
+
166
+ /**
167
+ * A "sliding" Initialization Vector
168
+ *
169
+ * @see Crypt_Twofish::enableContinuousBuffer()
170
+ * @var String
171
+ * @access private
172
+ */
173
+ var $encryptIV = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
174
+
175
+ /**
176
+ * A "sliding" Initialization Vector
177
+ *
178
+ * @see Crypt_Twofish::enableContinuousBuffer()
179
+ * @var String
180
+ * @access private
181
+ */
182
+ var $decryptIV = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
183
+
184
+ /**
185
+ * mcrypt resource for encryption
186
+ *
187
+ * The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
188
+ * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
189
+ *
190
+ * @see Crypt_Twofish::encrypt()
191
+ * @var String
192
+ * @access private
193
+ */
194
+ var $enmcrypt;
195
+
196
+ /**
197
+ * mcrypt resource for decryption
198
+ *
199
+ * The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
200
+ * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
201
+ *
202
+ * @see Crypt_Twofish::decrypt()
203
+ * @var String
204
+ * @access private
205
+ */
206
+ var $demcrypt;
207
+
208
+ /**
209
+ * Does the enmcrypt resource need to be (re)initialized?
210
+ *
211
+ * @see Crypt_Twofish::setKey()
212
+ * @see Crypt_Twofish::setIV()
213
+ * @var Boolean
214
+ * @access private
215
+ */
216
+ var $enchanged = true;
217
+
218
+ /**
219
+ * Does the demcrypt resource need to be (re)initialized?
220
+ *
221
+ * @see Crypt_Twofish::setKey()
222
+ * @see Crypt_Twofish::setIV()
223
+ * @var Boolean
224
+ * @access private
225
+ */
226
+ var $dechanged = true;
227
+
228
+ /**
229
+ * Is the mode one that is paddable?
230
+ *
231
+ * @see Crypt_Twofish::Crypt_Twofish()
232
+ * @var Boolean
233
+ * @access private
234
+ */
235
+ var $paddable = false;
236
+
237
+ /**
238
+ * Encryption buffer for CTR, OFB and CFB modes
239
+ *
240
+ * @see Crypt_Twofish::encrypt()
241
+ * @var Array
242
+ * @access private
243
+ */
244
+ var $enbuffer = array('encrypted' => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true);
245
+
246
+ /**
247
+ * Decryption buffer for CTR, OFB and CFB modes
248
+ *
249
+ * @see Crypt_Twofish::decrypt()
250
+ * @var Array
251
+ * @access private
252
+ */
253
+ var $debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0, 'demcrypt_init' => true);
254
+
255
+ /**
256
+ * mcrypt resource for CFB mode
257
+ *
258
+ * @see Crypt_Twofish::encrypt()
259
+ * @see Crypt_Twofish::decrypt()
260
+ * @var String
261
+ * @access private
262
+ */
263
+ var $ecb;
264
+
265
+ /**
266
+ * Performance-optimized callback function for en/decrypt()
267
+ *
268
+ * @var Callback
269
+ * @access private
270
+ */
271
+ var $inline_crypt;
272
+
273
+ /**
274
+ * Q-Table
275
+ *
276
+ * @var Array
277
+ * @access private
278
+ */
279
+ var $q0 = array (
280
+ 0xA9, 0x67, 0xB3, 0xE8, 0x04, 0xFD, 0xA3, 0x76,
281
+ 0x9A, 0x92, 0x80, 0x78, 0xE4, 0xDD, 0xD1, 0x38,
282
+ 0x0D, 0xC6, 0x35, 0x98, 0x18, 0xF7, 0xEC, 0x6C,
283
+ 0x43, 0x75, 0x37, 0x26, 0xFA, 0x13, 0x94, 0x48,
284
+ 0xF2, 0xD0, 0x8B, 0x30, 0x84, 0x54, 0xDF, 0x23,
285
+ 0x19, 0x5B, 0x3D, 0x59, 0xF3, 0xAE, 0xA2, 0x82,
286
+ 0x63, 0x01, 0x83, 0x2E, 0xD9, 0x51, 0x9B, 0x7C,
287
+ 0xA6, 0xEB, 0xA5, 0xBE, 0x16, 0x0C, 0xE3, 0x61,
288
+ 0xC0, 0x8C, 0x3A, 0xF5, 0x73, 0x2C, 0x25, 0x0B,
289
+ 0xBB, 0x4E, 0x89, 0x6B, 0x53, 0x6A, 0xB4, 0xF1,
290
+ 0xE1, 0xE6, 0xBD, 0x45, 0xE2, 0xF4, 0xB6, 0x66,
291
+ 0xCC, 0x95, 0x03, 0x56, 0xD4, 0x1C, 0x1E, 0xD7,
292
+ 0xFB, 0xC3, 0x8E, 0xB5, 0xE9, 0xCF, 0xBF, 0xBA,
293
+ 0xEA, 0x77, 0x39, 0xAF, 0x33, 0xC9, 0x62, 0x71,
294
+ 0x81, 0x79, 0x09, 0xAD, 0x24, 0xCD, 0xF9, 0xD8,
295
+ 0xE5, 0xC5, 0xB9, 0x4D, 0x44, 0x08, 0x86, 0xE7,
296
+ 0xA1, 0x1D, 0xAA, 0xED, 0x06, 0x70, 0xB2, 0xD2,
297
+ 0x41, 0x7B, 0xA0, 0x11, 0x31, 0xC2, 0x27, 0x90,
298
+ 0x20, 0xF6, 0x60, 0xFF, 0x96, 0x5C, 0xB1, 0xAB,
299
+ 0x9E, 0x9C, 0x52, 0x1B, 0x5F, 0x93, 0x0A, 0xEF,
300
+ 0x91, 0x85, 0x49, 0xEE, 0x2D, 0x4F, 0x8F, 0x3B,
301
+ 0x47, 0x87, 0x6D, 0x46, 0xD6, 0x3E, 0x69, 0x64,
302
+ 0x2A, 0xCE, 0xCB, 0x2F, 0xFC, 0x97, 0x05, 0x7A,
303
+ 0xAC, 0x7F, 0xD5, 0x1A, 0x4B, 0x0E, 0xA7, 0x5A,
304
+ 0x28, 0x14, 0x3F, 0x29, 0x88, 0x3C, 0x4C, 0x02,
305
+ 0xB8, 0xDA, 0xB0, 0x17, 0x55, 0x1F, 0x8A, 0x7D,
306
+ 0x57, 0xC7, 0x8D, 0x74, 0xB7, 0xC4, 0x9F, 0x72,
307
+ 0x7E, 0x15, 0x22, 0x12, 0x58, 0x07, 0x99, 0x34,
308
+ 0x6E, 0x50, 0xDE, 0x68, 0x65, 0xBC, 0xDB, 0xF8,
309
+ 0xC8, 0xA8, 0x2B, 0x40, 0xDC, 0xFE, 0x32, 0xA4,
310
+ 0xCA, 0x10, 0x21, 0xF0, 0xD3, 0x5D, 0x0F, 0x00,
311
+ 0x6F, 0x9D, 0x36, 0x42, 0x4A, 0x5E, 0xC1, 0xE0
312
+ );
313
+
314
+ /**
315
+ * Q-Table
316
+ *
317
+ * @var Array
318
+ * @access private
319
+ */
320
+ var $q1 = array (
321
+ 0x75, 0xF3, 0xC6, 0xF4, 0xDB, 0x7B, 0xFB, 0xC8,
322
+ 0x4A, 0xD3, 0xE6, 0x6B, 0x45, 0x7D, 0xE8, 0x4B,
323
+ 0xD6, 0x32, 0xD8, 0xFD, 0x37, 0x71, 0xF1, 0xE1,
324
+ 0x30, 0x0F, 0xF8, 0x1B, 0x87, 0xFA, 0x06, 0x3F,
325
+ 0x5E, 0xBA, 0xAE, 0x5B, 0x8A, 0x00, 0xBC, 0x9D,
326
+ 0x6D, 0xC1, 0xB1, 0x0E, 0x80, 0x5D, 0xD2, 0xD5,
327
+ 0xA0, 0x84, 0x07, 0x14, 0xB5, 0x90, 0x2C, 0xA3,
328
+ 0xB2, 0x73, 0x4C, 0x54, 0x92, 0x74, 0x36, 0x51,
329
+ 0x38, 0xB0, 0xBD, 0x5A, 0xFC, 0x60, 0x62, 0x96,
330
+ 0x6C, 0x42, 0xF7, 0x10, 0x7C, 0x28, 0x27, 0x8C,
331
+ 0x13, 0x95, 0x9C, 0xC7, 0x24, 0x46, 0x3B, 0x70,
332
+ 0xCA, 0xE3, 0x85, 0xCB, 0x11, 0xD0, 0x93, 0xB8,
333
+ 0xA6, 0x83, 0x20, 0xFF, 0x9F, 0x77, 0xC3, 0xCC,
334
+ 0x03, 0x6F, 0x08, 0xBF, 0x40, 0xE7, 0x2B, 0xE2,
335
+ 0x79, 0x0C, 0xAA, 0x82, 0x41, 0x3A, 0xEA, 0xB9,
336
+ 0xE4, 0x9A, 0xA4, 0x97, 0x7E, 0xDA, 0x7A, 0x17,
337
+ 0x66, 0x94, 0xA1, 0x1D, 0x3D, 0xF0, 0xDE, 0xB3,
338
+ 0x0B, 0x72, 0xA7, 0x1C, 0xEF, 0xD1, 0x53, 0x3E,
339
+ 0x8F, 0x33, 0x26, 0x5F, 0xEC, 0x76, 0x2A, 0x49,
340
+ 0x81, 0x88, 0xEE, 0x21, 0xC4, 0x1A, 0xEB, 0xD9,
341
+ 0xC5, 0x39, 0x99, 0xCD, 0xAD, 0x31, 0x8B, 0x01,
342
+ 0x18, 0x23, 0xDD, 0x1F, 0x4E, 0x2D, 0xF9, 0x48,
343
+ 0x4F, 0xF2, 0x65, 0x8E, 0x78, 0x5C, 0x58, 0x19,
344
+ 0x8D, 0xE5, 0x98, 0x57, 0x67, 0x7F, 0x05, 0x64,
345
+ 0xAF, 0x63, 0xB6, 0xFE, 0xF5, 0xB7, 0x3C, 0xA5,
346
+ 0xCE, 0xE9, 0x68, 0x44, 0xE0, 0x4D, 0x43, 0x69,
347
+ 0x29, 0x2E, 0xAC, 0x15, 0x59, 0xA8, 0x0A, 0x9E,
348
+ 0x6E, 0x47, 0xDF, 0x34, 0x35, 0x6A, 0xCF, 0xDC,
349
+ 0x22, 0xC9, 0xC0, 0x9B, 0x89, 0xD4, 0xED, 0xAB,
350
+ 0x12, 0xA2, 0x0D, 0x52, 0xBB, 0x02, 0x2F, 0xA9,
351
+ 0xD7, 0x61, 0x1E, 0xB4, 0x50, 0x04, 0xF6, 0xC2,
352
+ 0x16, 0x25, 0x86, 0x56, 0x55, 0x09, 0xBE, 0x91
353
+ );
354
+
355
+ /**
356
+ * M-Table
357
+ *
358
+ * @var Array
359
+ * @access private
360
+ */
361
+ var $m0 = array (
362
+ 0xBCBC3275, 0xECEC21F3, 0x202043C6, 0xB3B3C9F4, 0xDADA03DB, 0x02028B7B, 0xE2E22BFB, 0x9E9EFAC8,
363
+ 0xC9C9EC4A, 0xD4D409D3, 0x18186BE6, 0x1E1E9F6B, 0x98980E45, 0xB2B2387D, 0xA6A6D2E8, 0x2626B74B,
364
+ 0x3C3C57D6, 0x93938A32, 0x8282EED8, 0x525298FD, 0x7B7BD437, 0xBBBB3771, 0x5B5B97F1, 0x474783E1,
365
+ 0x24243C30, 0x5151E20F, 0xBABAC6F8, 0x4A4AF31B, 0xBFBF4887, 0x0D0D70FA, 0xB0B0B306, 0x7575DE3F,
366
+ 0xD2D2FD5E, 0x7D7D20BA, 0x666631AE, 0x3A3AA35B, 0x59591C8A, 0x00000000, 0xCDCD93BC, 0x1A1AE09D,
367
+ 0xAEAE2C6D, 0x7F7FABC1, 0x2B2BC7B1, 0xBEBEB90E, 0xE0E0A080, 0x8A8A105D, 0x3B3B52D2, 0x6464BAD5,
368
+ 0xD8D888A0, 0xE7E7A584, 0x5F5FE807, 0x1B1B1114, 0x2C2CC2B5, 0xFCFCB490, 0x3131272C, 0x808065A3,
369
+ 0x73732AB2, 0x0C0C8173, 0x79795F4C, 0x6B6B4154, 0x4B4B0292, 0x53536974, 0x94948F36, 0x83831F51,
370
+ 0x2A2A3638, 0xC4C49CB0, 0x2222C8BD, 0xD5D5F85A, 0xBDBDC3FC, 0x48487860, 0xFFFFCE62, 0x4C4C0796,
371
+ 0x4141776C, 0xC7C7E642, 0xEBEB24F7, 0x1C1C1410, 0x5D5D637C, 0x36362228, 0x6767C027, 0xE9E9AF8C,
372
+ 0x4444F913, 0x1414EA95, 0xF5F5BB9C, 0xCFCF18C7, 0x3F3F2D24, 0xC0C0E346, 0x7272DB3B, 0x54546C70,
373
+ 0x29294CCA, 0xF0F035E3, 0x0808FE85, 0xC6C617CB, 0xF3F34F11, 0x8C8CE4D0, 0xA4A45993, 0xCACA96B8,
374
+ 0x68683BA6, 0xB8B84D83, 0x38382820, 0xE5E52EFF, 0xADAD569F, 0x0B0B8477, 0xC8C81DC3, 0x9999FFCC,
375
+ 0x5858ED03, 0x19199A6F, 0x0E0E0A08, 0x95957EBF, 0x70705040, 0xF7F730E7, 0x6E6ECF2B, 0x1F1F6EE2,
376
+ 0xB5B53D79, 0x09090F0C, 0x616134AA, 0x57571682, 0x9F9F0B41, 0x9D9D803A, 0x111164EA, 0x2525CDB9,
377
+ 0xAFAFDDE4, 0x4545089A, 0xDFDF8DA4, 0xA3A35C97, 0xEAEAD57E, 0x353558DA, 0xEDEDD07A, 0x4343FC17,
378
+ 0xF8F8CB66, 0xFBFBB194, 0x3737D3A1, 0xFAFA401D, 0xC2C2683D, 0xB4B4CCF0, 0x32325DDE, 0x9C9C71B3,
379
+ 0x5656E70B, 0xE3E3DA72, 0x878760A7, 0x15151B1C, 0xF9F93AEF, 0x6363BFD1, 0x3434A953, 0x9A9A853E,
380
+ 0xB1B1428F, 0x7C7CD133, 0x88889B26, 0x3D3DA65F, 0xA1A1D7EC, 0xE4E4DF76, 0x8181942A, 0x91910149,
381
+ 0x0F0FFB81, 0xEEEEAA88, 0x161661EE, 0xD7D77321, 0x9797F5C4, 0xA5A5A81A, 0xFEFE3FEB, 0x6D6DB5D9,
382
+ 0x7878AEC5, 0xC5C56D39, 0x1D1DE599, 0x7676A4CD, 0x3E3EDCAD, 0xCBCB6731, 0xB6B6478B, 0xEFEF5B01,
383
+ 0x12121E18, 0x6060C523, 0x6A6AB0DD, 0x4D4DF61F, 0xCECEE94E, 0xDEDE7C2D, 0x55559DF9, 0x7E7E5A48,
384
+ 0x2121B24F, 0x03037AF2, 0xA0A02665, 0x5E5E198E, 0x5A5A6678, 0x65654B5C, 0x62624E58, 0xFDFD4519,
385
+ 0x0606F48D, 0x404086E5, 0xF2F2BE98, 0x3333AC57, 0x17179067, 0x05058E7F, 0xE8E85E05, 0x4F4F7D64,
386
+ 0x89896AAF, 0x10109563, 0x74742FB6, 0x0A0A75FE, 0x5C5C92F5, 0x9B9B74B7, 0x2D2D333C, 0x3030D6A5,
387
+ 0x2E2E49CE, 0x494989E9, 0x46467268, 0x77775544, 0xA8A8D8E0, 0x9696044D, 0x2828BD43, 0xA9A92969,
388
+ 0xD9D97929, 0x8686912E, 0xD1D187AC, 0xF4F44A15, 0x8D8D1559, 0xD6D682A8, 0xB9B9BC0A, 0x42420D9E,
389
+ 0xF6F6C16E, 0x2F2FB847, 0xDDDD06DF, 0x23233934, 0xCCCC6235, 0xF1F1C46A, 0xC1C112CF, 0x8585EBDC,
390
+ 0x8F8F9E22, 0x7171A1C9, 0x9090F0C0, 0xAAAA539B, 0x0101F189, 0x8B8BE1D4, 0x4E4E8CED, 0x8E8E6FAB,
391
+ 0xABABA212, 0x6F6F3EA2, 0xE6E6540D, 0xDBDBF252, 0x92927BBB, 0xB7B7B602, 0x6969CA2F, 0x3939D9A9,
392
+ 0xD3D30CD7, 0xA7A72361, 0xA2A2AD1E, 0xC3C399B4, 0x6C6C4450, 0x07070504, 0x04047FF6, 0x272746C2,
393
+ 0xACACA716, 0xD0D07625, 0x50501386, 0xDCDCF756, 0x84841A55, 0xE1E15109, 0x7A7A25BE, 0x1313EF91
394
+ );
395
+
396
+ /**
397
+ * M-Table
398
+ *
399
+ * @var Array
400
+ * @access private
401
+ */
402
+ var $m1 = array (
403
+ 0xA9D93939, 0x67901717, 0xB3719C9C, 0xE8D2A6A6, 0x04050707, 0xFD985252, 0xA3658080, 0x76DFE4E4,
404
+ 0x9A084545, 0x92024B4B, 0x80A0E0E0, 0x78665A5A, 0xE4DDAFAF, 0xDDB06A6A, 0xD1BF6363, 0x38362A2A,
405
+ 0x0D54E6E6, 0xC6432020, 0x3562CCCC, 0x98BEF2F2, 0x181E1212, 0xF724EBEB, 0xECD7A1A1, 0x6C774141,
406
+ 0x43BD2828, 0x7532BCBC, 0x37D47B7B, 0x269B8888, 0xFA700D0D, 0x13F94444, 0x94B1FBFB, 0x485A7E7E,
407
+ 0xF27A0303, 0xD0E48C8C, 0x8B47B6B6, 0x303C2424, 0x84A5E7E7, 0x54416B6B, 0xDF06DDDD, 0x23C56060,
408
+ 0x1945FDFD, 0x5BA33A3A, 0x3D68C2C2, 0x59158D8D, 0xF321ECEC, 0xAE316666, 0xA23E6F6F, 0x82165757,
409
+ 0x63951010, 0x015BEFEF, 0x834DB8B8, 0x2E918686, 0xD9B56D6D, 0x511F8383, 0x9B53AAAA, 0x7C635D5D,
410
+ 0xA63B6868, 0xEB3FFEFE, 0xA5D63030, 0xBE257A7A, 0x16A7ACAC, 0x0C0F0909, 0xE335F0F0, 0x6123A7A7,
411
+ 0xC0F09090, 0x8CAFE9E9, 0x3A809D9D, 0xF5925C5C, 0x73810C0C, 0x2C273131, 0x2576D0D0, 0x0BE75656,
412
+ 0xBB7B9292, 0x4EE9CECE, 0x89F10101, 0x6B9F1E1E, 0x53A93434, 0x6AC4F1F1, 0xB499C3C3, 0xF1975B5B,
413
+ 0xE1834747, 0xE66B1818, 0xBDC82222, 0x450E9898, 0xE26E1F1F, 0xF4C9B3B3, 0xB62F7474, 0x66CBF8F8,
414
+ 0xCCFF9999, 0x95EA1414, 0x03ED5858, 0x56F7DCDC, 0xD4E18B8B, 0x1C1B1515, 0x1EADA2A2, 0xD70CD3D3,
415
+ 0xFB2BE2E2, 0xC31DC8C8, 0x8E195E5E, 0xB5C22C2C, 0xE9894949, 0xCF12C1C1, 0xBF7E9595, 0xBA207D7D,
416
+ 0xEA641111, 0x77840B0B, 0x396DC5C5, 0xAF6A8989, 0x33D17C7C, 0xC9A17171, 0x62CEFFFF, 0x7137BBBB,
417
+ 0x81FB0F0F, 0x793DB5B5, 0x0951E1E1, 0xADDC3E3E, 0x242D3F3F, 0xCDA47676, 0xF99D5555, 0xD8EE8282,
418
+ 0xE5864040, 0xC5AE7878, 0xB9CD2525, 0x4D049696, 0x44557777, 0x080A0E0E, 0x86135050, 0xE730F7F7,
419
+ 0xA1D33737, 0x1D40FAFA, 0xAA346161, 0xED8C4E4E, 0x06B3B0B0, 0x706C5454, 0xB22A7373, 0xD2523B3B,
420
+ 0x410B9F9F, 0x7B8B0202, 0xA088D8D8, 0x114FF3F3, 0x3167CBCB, 0xC2462727, 0x27C06767, 0x90B4FCFC,
421
+ 0x20283838, 0xF67F0404, 0x60784848, 0xFF2EE5E5, 0x96074C4C, 0x5C4B6565, 0xB1C72B2B, 0xAB6F8E8E,
422
+ 0x9E0D4242, 0x9CBBF5F5, 0x52F2DBDB, 0x1BF34A4A, 0x5FA63D3D, 0x9359A4A4, 0x0ABCB9B9, 0xEF3AF9F9,
423
+ 0x91EF1313, 0x85FE0808, 0x49019191, 0xEE611616, 0x2D7CDEDE, 0x4FB22121, 0x8F42B1B1, 0x3BDB7272,
424
+ 0x47B82F2F, 0x8748BFBF, 0x6D2CAEAE, 0x46E3C0C0, 0xD6573C3C, 0x3E859A9A, 0x6929A9A9, 0x647D4F4F,
425
+ 0x2A948181, 0xCE492E2E, 0xCB17C6C6, 0x2FCA6969, 0xFCC3BDBD, 0x975CA3A3, 0x055EE8E8, 0x7AD0EDED,
426
+ 0xAC87D1D1, 0x7F8E0505, 0xD5BA6464, 0x1AA8A5A5, 0x4BB72626, 0x0EB9BEBE, 0xA7608787, 0x5AF8D5D5,
427
+ 0x28223636, 0x14111B1B, 0x3FDE7575, 0x2979D9D9, 0x88AAEEEE, 0x3C332D2D, 0x4C5F7979, 0x02B6B7B7,
428
+ 0xB896CACA, 0xDA583535, 0xB09CC4C4, 0x17FC4343, 0x551A8484, 0x1FF64D4D, 0x8A1C5959, 0x7D38B2B2,
429
+ 0x57AC3333, 0xC718CFCF, 0x8DF40606, 0x74695353, 0xB7749B9B, 0xC4F59797, 0x9F56ADAD, 0x72DAE3E3,
430
+ 0x7ED5EAEA, 0x154AF4F4, 0x229E8F8F, 0x12A2ABAB, 0x584E6262, 0x07E85F5F, 0x99E51D1D, 0x34392323,
431
+ 0x6EC1F6F6, 0x50446C6C, 0xDE5D3232, 0x68724646, 0x6526A0A0, 0xBC93CDCD, 0xDB03DADA, 0xF8C6BABA,
432
+ 0xC8FA9E9E, 0xA882D6D6, 0x2BCF6E6E, 0x40507070, 0xDCEB8585, 0xFE750A0A, 0x328A9393, 0xA48DDFDF,
433
+ 0xCA4C2929, 0x10141C1C, 0x2173D7D7, 0xF0CCB4B4, 0xD309D4D4, 0x5D108A8A, 0x0FE25151, 0x00000000,
434
+ 0x6F9A1919, 0x9DE01A1A, 0x368F9494, 0x42E6C7C7, 0x4AECC9C9, 0x5EFDD2D2, 0xC1AB7F7F, 0xE0D8A8A8
435
+ );
436
+
437
+ /**
438
+ * M-Table
439
+ *
440
+ * @var Array
441
+ * @access private
442
+ */
443
+ var $m2 = array (
444
+ 0xBC75BC32, 0xECF3EC21, 0x20C62043, 0xB3F4B3C9, 0xDADBDA03, 0x027B028B, 0xE2FBE22B, 0x9EC89EFA,
445
+ 0xC94AC9EC, 0xD4D3D409, 0x18E6186B, 0x1E6B1E9F, 0x9845980E, 0xB27DB238, 0xA6E8A6D2, 0x264B26B7,
446
+ 0x3CD63C57, 0x9332938A, 0x82D882EE, 0x52FD5298, 0x7B377BD4, 0xBB71BB37, 0x5BF15B97, 0x47E14783,
447
+ 0x2430243C, 0x510F51E2, 0xBAF8BAC6, 0x4A1B4AF3, 0xBF87BF48, 0x0DFA0D70, 0xB006B0B3, 0x753F75DE,
448
+ 0xD25ED2FD, 0x7DBA7D20, 0x66AE6631, 0x3A5B3AA3, 0x598A591C, 0x00000000, 0xCDBCCD93, 0x1A9D1AE0,
449
+ 0xAE6DAE2C, 0x7FC17FAB, 0x2BB12BC7, 0xBE0EBEB9, 0xE080E0A0, 0x8A5D8A10, 0x3BD23B52, 0x64D564BA,
450
+ 0xD8A0D888, 0xE784E7A5, 0x5F075FE8, 0x1B141B11, 0x2CB52CC2, 0xFC90FCB4, 0x312C3127, 0x80A38065,
451
+ 0x73B2732A, 0x0C730C81, 0x794C795F, 0x6B546B41, 0x4B924B02, 0x53745369, 0x9436948F, 0x8351831F,
452
+ 0x2A382A36, 0xC4B0C49C, 0x22BD22C8, 0xD55AD5F8, 0xBDFCBDC3, 0x48604878, 0xFF62FFCE, 0x4C964C07,
453
+ 0x416C4177, 0xC742C7E6, 0xEBF7EB24, 0x1C101C14, 0x5D7C5D63, 0x36283622, 0x672767C0, 0xE98CE9AF,
454
+ 0x441344F9, 0x149514EA, 0xF59CF5BB, 0xCFC7CF18, 0x3F243F2D, 0xC046C0E3, 0x723B72DB, 0x5470546C,
455
+ 0x29CA294C, 0xF0E3F035, 0x088508FE, 0xC6CBC617, 0xF311F34F, 0x8CD08CE4, 0xA493A459, 0xCAB8CA96,
456
+ 0x68A6683B, 0xB883B84D, 0x38203828, 0xE5FFE52E, 0xAD9FAD56, 0x0B770B84, 0xC8C3C81D, 0x99CC99FF,
457
+ 0x580358ED, 0x196F199A, 0x0E080E0A, 0x95BF957E, 0x70407050, 0xF7E7F730, 0x6E2B6ECF, 0x1FE21F6E,
458
+ 0xB579B53D, 0x090C090F, 0x61AA6134, 0x57825716, 0x9F419F0B, 0x9D3A9D80, 0x11EA1164, 0x25B925CD,
459
+ 0xAFE4AFDD, 0x459A4508, 0xDFA4DF8D, 0xA397A35C, 0xEA7EEAD5, 0x35DA3558, 0xED7AEDD0, 0x431743FC,
460
+ 0xF866F8CB, 0xFB94FBB1, 0x37A137D3, 0xFA1DFA40, 0xC23DC268, 0xB4F0B4CC, 0x32DE325D, 0x9CB39C71,
461
+ 0x560B56E7, 0xE372E3DA, 0x87A78760, 0x151C151B, 0xF9EFF93A, 0x63D163BF, 0x345334A9, 0x9A3E9A85,
462
+ 0xB18FB142, 0x7C337CD1, 0x8826889B, 0x3D5F3DA6, 0xA1ECA1D7, 0xE476E4DF, 0x812A8194, 0x91499101,
463
+ 0x0F810FFB, 0xEE88EEAA, 0x16EE1661, 0xD721D773, 0x97C497F5, 0xA51AA5A8, 0xFEEBFE3F, 0x6DD96DB5,
464
+ 0x78C578AE, 0xC539C56D, 0x1D991DE5, 0x76CD76A4, 0x3EAD3EDC, 0xCB31CB67, 0xB68BB647, 0xEF01EF5B,
465
+ 0x1218121E, 0x602360C5, 0x6ADD6AB0, 0x4D1F4DF6, 0xCE4ECEE9, 0xDE2DDE7C, 0x55F9559D, 0x7E487E5A,
466
+ 0x214F21B2, 0x03F2037A, 0xA065A026, 0x5E8E5E19, 0x5A785A66, 0x655C654B, 0x6258624E, 0xFD19FD45,
467
+ 0x068D06F4, 0x40E54086, 0xF298F2BE, 0x335733AC, 0x17671790, 0x057F058E, 0xE805E85E, 0x4F644F7D,
468
+ 0x89AF896A, 0x10631095, 0x74B6742F, 0x0AFE0A75, 0x5CF55C92, 0x9BB79B74, 0x2D3C2D33, 0x30A530D6,
469
+ 0x2ECE2E49, 0x49E94989, 0x46684672, 0x77447755, 0xA8E0A8D8, 0x964D9604, 0x284328BD, 0xA969A929,
470
+ 0xD929D979, 0x862E8691, 0xD1ACD187, 0xF415F44A, 0x8D598D15, 0xD6A8D682, 0xB90AB9BC, 0x429E420D,
471
+ 0xF66EF6C1, 0x2F472FB8, 0xDDDFDD06, 0x23342339, 0xCC35CC62, 0xF16AF1C4, 0xC1CFC112, 0x85DC85EB,
472
+ 0x8F228F9E, 0x71C971A1, 0x90C090F0, 0xAA9BAA53, 0x018901F1, 0x8BD48BE1, 0x4EED4E8C, 0x8EAB8E6F,
473
+ 0xAB12ABA2, 0x6FA26F3E, 0xE60DE654, 0xDB52DBF2, 0x92BB927B, 0xB702B7B6, 0x692F69CA, 0x39A939D9,
474
+ 0xD3D7D30C, 0xA761A723, 0xA21EA2AD, 0xC3B4C399, 0x6C506C44, 0x07040705, 0x04F6047F, 0x27C22746,
475
+ 0xAC16ACA7, 0xD025D076, 0x50865013, 0xDC56DCF7, 0x8455841A, 0xE109E151, 0x7ABE7A25, 0x139113EF
476
+ );
477
+
478
+ /**
479
+ * M-Table
480
+ *
481
+ * @var Array
482
+ * @access private
483
+ */
484
+ var $m3 = array (
485
+ 0xD939A9D9, 0x90176790, 0x719CB371, 0xD2A6E8D2, 0x05070405, 0x9852FD98, 0x6580A365, 0xDFE476DF,
486
+ 0x08459A08, 0x024B9202, 0xA0E080A0, 0x665A7866, 0xDDAFE4DD, 0xB06ADDB0, 0xBF63D1BF, 0x362A3836,
487
+ 0x54E60D54, 0x4320C643, 0x62CC3562, 0xBEF298BE, 0x1E12181E, 0x24EBF724, 0xD7A1ECD7, 0x77416C77,
488
+ 0xBD2843BD, 0x32BC7532, 0xD47B37D4, 0x9B88269B, 0x700DFA70, 0xF94413F9, 0xB1FB94B1, 0x5A7E485A,
489
+ 0x7A03F27A, 0xE48CD0E4, 0x47B68B47, 0x3C24303C, 0xA5E784A5, 0x416B5441, 0x06DDDF06, 0xC56023C5,
490
+ 0x45FD1945, 0xA33A5BA3, 0x68C23D68, 0x158D5915, 0x21ECF321, 0x3166AE31, 0x3E6FA23E, 0x16578216,
491
+ 0x95106395, 0x5BEF015B, 0x4DB8834D, 0x91862E91, 0xB56DD9B5, 0x1F83511F, 0x53AA9B53, 0x635D7C63,
492
+ 0x3B68A63B, 0x3FFEEB3F, 0xD630A5D6, 0x257ABE25, 0xA7AC16A7, 0x0F090C0F, 0x35F0E335, 0x23A76123,
493
+ 0xF090C0F0, 0xAFE98CAF, 0x809D3A80, 0x925CF592, 0x810C7381, 0x27312C27, 0x76D02576, 0xE7560BE7,
494
+ 0x7B92BB7B, 0xE9CE4EE9, 0xF10189F1, 0x9F1E6B9F, 0xA93453A9, 0xC4F16AC4, 0x99C3B499, 0x975BF197,
495
+ 0x8347E183, 0x6B18E66B, 0xC822BDC8, 0x0E98450E, 0x6E1FE26E, 0xC9B3F4C9, 0x2F74B62F, 0xCBF866CB,
496
+ 0xFF99CCFF, 0xEA1495EA, 0xED5803ED, 0xF7DC56F7, 0xE18BD4E1, 0x1B151C1B, 0xADA21EAD, 0x0CD3D70C,
497
+ 0x2BE2FB2B, 0x1DC8C31D, 0x195E8E19, 0xC22CB5C2, 0x8949E989, 0x12C1CF12, 0x7E95BF7E, 0x207DBA20,
498
+ 0x6411EA64, 0x840B7784, 0x6DC5396D, 0x6A89AF6A, 0xD17C33D1, 0xA171C9A1, 0xCEFF62CE, 0x37BB7137,
499
+ 0xFB0F81FB, 0x3DB5793D, 0x51E10951, 0xDC3EADDC, 0x2D3F242D, 0xA476CDA4, 0x9D55F99D, 0xEE82D8EE,
500
+ 0x8640E586, 0xAE78C5AE, 0xCD25B9CD, 0x04964D04, 0x55774455, 0x0A0E080A, 0x13508613, 0x30F7E730,
501
+ 0xD337A1D3, 0x40FA1D40, 0x3461AA34, 0x8C4EED8C, 0xB3B006B3, 0x6C54706C, 0x2A73B22A, 0x523BD252,
502
+ 0x0B9F410B, 0x8B027B8B, 0x88D8A088, 0x4FF3114F, 0x67CB3167, 0x4627C246, 0xC06727C0, 0xB4FC90B4,
503
+ 0x28382028, 0x7F04F67F, 0x78486078, 0x2EE5FF2E, 0x074C9607, 0x4B655C4B, 0xC72BB1C7, 0x6F8EAB6F,
504
+ 0x0D429E0D, 0xBBF59CBB, 0xF2DB52F2, 0xF34A1BF3, 0xA63D5FA6, 0x59A49359, 0xBCB90ABC, 0x3AF9EF3A,
505
+ 0xEF1391EF, 0xFE0885FE, 0x01914901, 0x6116EE61, 0x7CDE2D7C, 0xB2214FB2, 0x42B18F42, 0xDB723BDB,
506
+ 0xB82F47B8, 0x48BF8748, 0x2CAE6D2C, 0xE3C046E3, 0x573CD657, 0x859A3E85, 0x29A96929, 0x7D4F647D,
507
+ 0x94812A94, 0x492ECE49, 0x17C6CB17, 0xCA692FCA, 0xC3BDFCC3, 0x5CA3975C, 0x5EE8055E, 0xD0ED7AD0,
508
+ 0x87D1AC87, 0x8E057F8E, 0xBA64D5BA, 0xA8A51AA8, 0xB7264BB7, 0xB9BE0EB9, 0x6087A760, 0xF8D55AF8,
509
+ 0x22362822, 0x111B1411, 0xDE753FDE, 0x79D92979, 0xAAEE88AA, 0x332D3C33, 0x5F794C5F, 0xB6B702B6,
510
+ 0x96CAB896, 0x5835DA58, 0x9CC4B09C, 0xFC4317FC, 0x1A84551A, 0xF64D1FF6, 0x1C598A1C, 0x38B27D38,
511
+ 0xAC3357AC, 0x18CFC718, 0xF4068DF4, 0x69537469, 0x749BB774, 0xF597C4F5, 0x56AD9F56, 0xDAE372DA,
512
+ 0xD5EA7ED5, 0x4AF4154A, 0x9E8F229E, 0xA2AB12A2, 0x4E62584E, 0xE85F07E8, 0xE51D99E5, 0x39233439,
513
+ 0xC1F66EC1, 0x446C5044, 0x5D32DE5D, 0x72466872, 0x26A06526, 0x93CDBC93, 0x03DADB03, 0xC6BAF8C6,
514
+ 0xFA9EC8FA, 0x82D6A882, 0xCF6E2BCF, 0x50704050, 0xEB85DCEB, 0x750AFE75, 0x8A93328A, 0x8DDFA48D,
515
+ 0x4C29CA4C, 0x141C1014, 0x73D72173, 0xCCB4F0CC, 0x09D4D309, 0x108A5D10, 0xE2510FE2, 0x00000000,
516
+ 0x9A196F9A, 0xE01A9DE0, 0x8F94368F, 0xE6C742E6, 0xECC94AEC, 0xFDD25EFD, 0xAB7FC1AB, 0xD8A8E0D8
517
+ );
518
+
519
+ /**
520
+ * The Key Schedule Array
521
+ *
522
+ * @var Array
523
+ * @access private
524
+ */
525
+ var $K = array();
526
+
527
+ /**
528
+ * The Key depended S-Table 0
529
+ *
530
+ * @var Array
531
+ * @access private
532
+ */
533
+ var $S0 = array();
534
+
535
+ /**
536
+ * The Key depended S-Table 1
537
+ *
538
+ * @var Array
539
+ * @access private
540
+ */
541
+ var $S1 = array();
542
+
543
+ /**
544
+ * The Key depended S-Table 2
545
+ *
546
+ * @var Array
547
+ * @access private
548
+ */
549
+ var $S2 = array();
550
+
551
+ /**
552
+ * The Key depended S-Table 3
553
+ *
554
+ * @var Array
555
+ * @access private
556
+ */
557
+ var $S3 = array();
558
+
559
+ /**
560
+ * Default Constructor.
561
+ *
562
+ * Determines whether or not the mcrypt extension should be used.
563
+ * If not explictly set, CRYPT_TWOFISH_MODE_CBC will be used.
564
+ *
565
+ * @param optional Integer $mode
566
+ * @access public
567
+ */
568
+ function Crypt_Twofish($mode = CRYPT_TWOFISH_MODE_CBC)
569
+ {
570
+ if ( !defined('CRYPT_TWOFISH_MODE') ) {
571
+ switch (true) {
572
+ case extension_loaded('mcrypt') && in_array('twofish', mcrypt_list_algorithms()):
573
+ define('CRYPT_TWOFISH_MODE', CRYPT_TWOFISH_MODE_MCRYPT);
574
+ break;
575
+ default:
576
+ define('CRYPT_TWOFISH_MODE', CRYPT_TWOFISH_MODE_INTERNAL);
577
+ }
578
+ }
579
+
580
+ switch ( CRYPT_TWOFISH_MODE ) {
581
+ case CRYPT_TWOFISH_MODE_MCRYPT:
582
+ switch ($mode) {
583
+ case CRYPT_TWOFISH_MODE_ECB:
584
+ $this->paddable = true;
585
+ $this->mode = MCRYPT_MODE_ECB;
586
+ break;
587
+ case CRYPT_TWOFISH_MODE_CTR:
588
+ $this->mode = 'ctr';
589
+ break;
590
+ case CRYPT_TWOFISH_MODE_CFB:
591
+ $this->mode = 'ncfb';
592
+ $this->ecb = mcrypt_module_open(MCRYPT_TWOFISH, '', MCRYPT_MODE_ECB, '');
593
+ break;
594
+ case CRYPT_TWOFISH_MODE_OFB:
595
+ $this->mode = MCRYPT_MODE_NOFB;
596
+ break;
597
+ case CRYPT_TWOFISH_MODE_CBC:
598
+ default:
599
+ $this->paddable = true;
600
+ $this->mode = MCRYPT_MODE_CBC;
601
+ }
602
+ $this->enmcrypt = mcrypt_module_open(MCRYPT_TWOFISH, '', $this->mode, '');
603
+ $this->demcrypt = mcrypt_module_open(MCRYPT_TWOFISH, '', $this->mode, '');
604
+
605
+ break;
606
+ default:
607
+ switch ($mode) {
608
+ case CRYPT_TWOFISH_MODE_ECB:
609
+ case CRYPT_TWOFISH_MODE_CBC:
610
+ $this->paddable = true;
611
+ $this->mode = $mode;
612
+ break;
613
+ case CRYPT_TWOFISH_MODE_CTR:
614
+ case CRYPT_TWOFISH_MODE_CFB:
615
+ case CRYPT_TWOFISH_MODE_OFB:
616
+ $this->mode = $mode;
617
+ break;
618
+ default:
619
+ $this->paddable = true;
620
+ $this->mode = CRYPT_TWOFISH_MODE_CBC;
621
+ }
622
+ $this->inline_crypt_setup();
623
+ }
624
+ }
625
+
626
+ /**
627
+ * Sets the key.
628
+ *
629
+ * Keys can be of any length. Twofish, itself, requires the use of a key that's 128, 192 or 256-bits long.
630
+ * If the key is less than 256-bits we round the length up to the closest valid key length,
631
+ * padding $key with null bytes. If the key is more than 256-bits, we trim the excess bits.
632
+ *
633
+ * If the key is not explicitly set, it'll be assumed a 128 bits key to be all null bytes.
634
+ *
635
+ * @access public
636
+ * @param String $key
637
+ */
638
+ function setKey($key)
639
+ {
640
+ $keylength = strlen($key);
641
+ switch (true) {
642
+ case $keylength <= 16:
643
+ $key.= str_repeat("\0", 16 - $keylength);
644
+ break;
645
+ case $keylength <= 24:
646
+ $key.= str_repeat("\0", 24 - $keylength);
647
+ break;
648
+ case $keylength <= 32:
649
+ $key.= str_repeat("\0", 32 - $keylength);
650
+ break;
651
+ default:
652
+ $key = substr($key, 0, 32);
653
+ }
654
+ $this->key = $key;
655
+
656
+ $this->enchanged = true;
657
+ $this->dechanged = true;
658
+
659
+ if (CRYPT_TWOFISH_MODE == CRYPT_TWOFISH_MODE_MCRYPT) {
660
+ return;
661
+ }
662
+
663
+ /* Key expanding and generating the key-depended s-boxes */
664
+ $le_longs = unpack('V*', $key);
665
+ $key = unpack('C*', $key);
666
+ $m0 = $this->m0;
667
+ $m1 = $this->m1;
668
+ $m2 = $this->m2;
669
+ $m3 = $this->m3;
670
+ $q0 = $this->q0;
671
+ $q1 = $this->q1;
672
+
673
+ $K = $S0 = $S1 = $S2 = $S3 = array();
674
+
675
+ switch (strlen($this->key)) {
676
+ case 16:
677
+ list ($s7, $s6, $s5, $s4) = $this->mds_rem($le_longs[1], $le_longs[2]);
678
+ list ($s3, $s2, $s1, $s0) = $this->mds_rem($le_longs[3], $le_longs[4]);
679
+ for ($i = 0, $j = 1; $i < 40; $i+= 2,$j+= 2) {
680
+ $A = $m0[$q0[$q0[$i] ^ $key[ 9]] ^ $key[1]] ^
681
+ $m1[$q0[$q1[$i] ^ $key[10]] ^ $key[2]] ^
682
+ $m2[$q1[$q0[$i] ^ $key[11]] ^ $key[3]] ^
683
+ $m3[$q1[$q1[$i] ^ $key[12]] ^ $key[4]];
684
+ $B = $m0[$q0[$q0[$j] ^ $key[13]] ^ $key[5]] ^
685
+ $m1[$q0[$q1[$j] ^ $key[14]] ^ $key[6]] ^
686
+ $m2[$q1[$q0[$j] ^ $key[15]] ^ $key[7]] ^
687
+ $m3[$q1[$q1[$j] ^ $key[16]] ^ $key[8]];
688
+ $B = ($B << 8) | ($B >> 24 & 0xff);
689
+ $K[] = $A+= $B;
690
+ $K[] = (($A+= $B) << 9 | $A >> 23 & 0x1ff);
691
+ }
692
+ for ($i = 0; $i < 256; ++$i) {
693
+ $S0[$i] = $m0[$q0[$q0[$i] ^ $s4] ^ $s0];
694
+ $S1[$i] = $m1[$q0[$q1[$i] ^ $s5] ^ $s1];
695
+ $S2[$i] = $m2[$q1[$q0[$i] ^ $s6] ^ $s2];
696
+ $S3[$i] = $m3[$q1[$q1[$i] ^ $s7] ^ $s3];
697
+ }
698
+ break;
699
+ case 24:
700
+ list ($sb, $sa, $s9, $s8) = $this->mds_rem($le_longs[1], $le_longs[2]);
701
+ list ($s7, $s6, $s5, $s4) = $this->mds_rem($le_longs[3], $le_longs[4]);
702
+ list ($s3, $s2, $s1, $s0) = $this->mds_rem($le_longs[5], $le_longs[6]);
703
+ for ($i = 0, $j = 1; $i < 40; $i+= 2, $j+= 2) {
704
+ $A = $m0[$q0[$q0[$q1[$i] ^ $key[17]] ^ $key[ 9]] ^ $key[1]] ^
705
+ $m1[$q0[$q1[$q1[$i] ^ $key[18]] ^ $key[10]] ^ $key[2]] ^
706
+ $m2[$q1[$q0[$q0[$i] ^ $key[19]] ^ $key[11]] ^ $key[3]] ^
707
+ $m3[$q1[$q1[$q0[$i] ^ $key[20]] ^ $key[12]] ^ $key[4]];
708
+ $B = $m0[$q0[$q0[$q1[$j] ^ $key[21]] ^ $key[13]] ^ $key[5]] ^
709
+ $m1[$q0[$q1[$q1[$j] ^ $key[22]] ^ $key[14]] ^ $key[6]] ^
710
+ $m2[$q1[$q0[$q0[$j] ^ $key[23]] ^ $key[15]] ^ $key[7]] ^
711
+ $m3[$q1[$q1[$q0[$j] ^ $key[24]] ^ $key[16]] ^ $key[8]];
712
+ $B = ($B << 8) | ($B >> 24 & 0xff);
713
+ $K[] = $A+= $B;
714
+ $K[] = (($A+= $B) << 9 | $A >> 23 & 0x1ff);
715
+ }
716
+ for ($i = 0; $i < 256; ++$i) {
717
+ $S0[$i] = $m0[$q0[$q0[$q1[$i] ^ $s8] ^ $s4] ^ $s0];
718
+ $S1[$i] = $m1[$q0[$q1[$q1[$i] ^ $s9] ^ $s5] ^ $s1];
719
+ $S2[$i] = $m2[$q1[$q0[$q0[$i] ^ $sa] ^ $s6] ^ $s2];
720
+ $S3[$i] = $m3[$q1[$q1[$q0[$i] ^ $sb] ^ $s7] ^ $s3];
721
+ }
722
+ break;
723
+ default: // 32
724
+ list ($sf, $se, $sd, $sc) = $this->mds_rem($le_longs[1], $le_longs[2]);
725
+ list ($sb, $sa, $s9, $s8) = $this->mds_rem($le_longs[3], $le_longs[4]);
726
+ list ($s7, $s6, $s5, $s4) = $this->mds_rem($le_longs[5], $le_longs[6]);
727
+ list ($s3, $s2, $s1, $s0) = $this->mds_rem($le_longs[7], $le_longs[8]);
728
+ for ($i = 0, $j = 1; $i < 40; $i+= 2, $j+= 2) {
729
+ $A = $m0[$q0[$q0[$q1[$q1[$i] ^ $key[25]] ^ $key[17]] ^ $key[ 9]] ^ $key[1]] ^
730
+ $m1[$q0[$q1[$q1[$q0[$i] ^ $key[26]] ^ $key[18]] ^ $key[10]] ^ $key[2]] ^
731
+ $m2[$q1[$q0[$q0[$q0[$i] ^ $key[27]] ^ $key[19]] ^ $key[11]] ^ $key[3]] ^
732
+ $m3[$q1[$q1[$q0[$q1[$i] ^ $key[28]] ^ $key[20]] ^ $key[12]] ^ $key[4]];
733
+ $B = $m0[$q0[$q0[$q1[$q1[$j] ^ $key[29]] ^ $key[21]] ^ $key[13]] ^ $key[5]] ^
734
+ $m1[$q0[$q1[$q1[$q0[$j] ^ $key[30]] ^ $key[22]] ^ $key[14]] ^ $key[6]] ^
735
+ $m2[$q1[$q0[$q0[$q0[$j] ^ $key[31]] ^ $key[23]] ^ $key[15]] ^ $key[7]] ^
736
+ $m3[$q1[$q1[$q0[$q1[$j] ^ $key[32]] ^ $key[24]] ^ $key[16]] ^ $key[8]];
737
+ $B = ($B << 8) | ($B >> 24 & 0xff);
738
+ $K[] = $A+= $B;
739
+ $K[] = (($A+= $B) << 9 | $A >> 23 & 0x1ff);
740
+ }
741
+ for ($i = 0; $i < 256; ++$i) {
742
+ $S0[$i] = $m0[$q0[$q0[$q1[$q1[$i] ^ $sc] ^ $s8] ^ $s4] ^ $s0];
743
+ $S1[$i] = $m1[$q0[$q1[$q1[$q0[$i] ^ $sd] ^ $s9] ^ $s5] ^ $s1];
744
+ $S2[$i] = $m2[$q1[$q0[$q0[$q0[$i] ^ $se] ^ $sa] ^ $s6] ^ $s2];
745
+ $S3[$i] = $m3[$q1[$q1[$q0[$q1[$i] ^ $sf] ^ $sb] ^ $s7] ^ $s3];
746
+ }
747
+ }
748
+
749
+ $this->K = $K;
750
+ $this->S0 = $S0;
751
+ $this->S1 = $S1;
752
+ $this->S2 = $S2;
753
+ $this->S3 = $S3;
754
+ }
755
+
756
+ /**
757
+ * Sets the password.
758
+ *
759
+ * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows:
760
+ * {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2}:
761
+ * $hash, $salt, $count
762
+ *
763
+ * @param String $password
764
+ * @param optional String $method
765
+ * @access public
766
+ */
767
+ function setPassword($password, $method = 'pbkdf2')
768
+ {
769
+ $key = '';
770
+
771
+ switch ($method) {
772
+ default: // 'pbkdf2'
773
+ list(, , $hash, $salt, $count) = func_get_args();
774
+ if (!isset($hash)) {
775
+ $hash = 'sha1';
776
+ }
777
+ // WPA and WPA2 use the SSID as the salt
778
+ if (!isset($salt)) {
779
+ $salt = 'phpseclib/salt';
780
+ }
781
+ // RFC2898#section-4.2 uses 1,000 iterations by default
782
+ // WPA and WPA2 use 4,096.
783
+ if (!isset($count)) {
784
+ $count = 1000;
785
+ }
786
+
787
+ if (!class_exists('Crypt_Hash')) {
788
+ require_once('Crypt/Hash.php');
789
+ }
790
+
791
+ $i = 1;
792
+ while (strlen($key) < 32) {
793
+ $hmac = new Crypt_Hash();
794
+ $hmac->setHash($hash);
795
+ $hmac->setKey($password);
796
+ $f = $u = $hmac->hash($salt . pack('N', $i++));
797
+ for ($j = 2; $j <= $count; ++$j) {
798
+ $u = $hmac->hash($u);
799
+ $f^= $u;
800
+ }
801
+ $key.= $f;
802
+ }
803
+ }
804
+
805
+ $this->setKey($key);
806
+ }
807
+
808
+ /**
809
+ * Sets the initialization vector. (optional)
810
+ *
811
+ * SetIV is not required when CRYPT_TWOFISH_MODE_ECB is being used. If not explictly set, it'll be assumed
812
+ * to be all null bytes.
813
+ *
814
+ * @access public
815
+ * @param String $iv
816
+ */
817
+ function setIV($iv)
818
+ {
819
+ $this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($iv, 0, 16), 16, chr(0));
820
+ $this->enchanged = true;
821
+ $this->dechanged = true;
822
+ }
823
+
824
+ /**
825
+ * Encrypts a message.
826
+ *
827
+ * $plaintext will be padded with up to 16 additional bytes. Other Twofish implementations may or may not pad in the
828
+ * same manner. Other common approaches to padding and the reasons why it's necessary are discussed in the following
829
+ * URL:
830
+ *
831
+ * {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html}
832
+ *
833
+ * An alternative to padding is to, separately, send the length of the file. This is what SSH, in fact, does.
834
+ * strlen($plaintext) will still need to be a multiple of 16, however, arbitrary values can be added to make it that
835
+ * length.
836
+ *
837
+ * @see Crypt_Twofish::decrypt()
838
+ * @access public
839
+ * @param String $plaintext
840
+ */
841
+ function encrypt($plaintext)
842
+ {
843
+ if ( CRYPT_TWOFISH_MODE == CRYPT_TWOFISH_MODE_MCRYPT ) {
844
+ if ($this->paddable) {
845
+ $plaintext = $this->_pad($plaintext);
846
+ }
847
+
848
+ if ($this->enchanged) {
849
+ mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
850
+ if ($this->mode == 'ncfb') {
851
+ mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
852
+ }
853
+ $this->enchanged = false;
854
+ }
855
+
856
+ if ($this->mode != 'ncfb' || !$this->continuousBuffer) {
857
+ $ciphertext = mcrypt_generic($this->enmcrypt, $plaintext);
858
+ } else {
859
+ $iv = &$this->encryptIV;
860
+ $pos = &$this->enbuffer['pos'];
861
+ $len = strlen($plaintext);
862
+ $ciphertext = '';
863
+ $i = 0;
864
+ if ($pos) {
865
+ $orig_pos = $pos;
866
+ $max = 16 - $pos;
867
+ if ($len >= $max) {
868
+ $i = $max;
869
+ $len-= $max;
870
+ $pos = 0;
871
+ } else {
872
+ $i = $len;
873
+ $pos+= $len;
874
+ $len = 0;
875
+ }
876
+ $ciphertext = substr($iv, $orig_pos) ^ $plaintext;
877
+ $iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
878
+ $this->enbuffer['enmcrypt_init'] = true;
879
+ }
880
+ if ($len >= 16) {
881
+ if ($this->enbuffer['enmcrypt_init'] === false || $len > 600) {
882
+ if ($this->enbuffer['enmcrypt_init'] === true) {
883
+ mcrypt_generic_init($this->enmcrypt, $this->key, $iv);
884
+ $this->enbuffer['enmcrypt_init'] = false;
885
+ }
886
+ $ciphertext.= mcrypt_generic($this->enmcrypt, substr($plaintext, $i, $len - $len % 16));
887
+ $iv = substr($ciphertext, -16);
888
+ $len%= 16;
889
+ } else {
890
+ while ($len >= 16) {
891
+ $iv = mcrypt_generic($this->ecb, $iv) ^ substr($plaintext, $i, 16);
892
+ $ciphertext.= $iv;
893
+ $len-= 16;
894
+ $i+= 16;
895
+ }
896
+ }
897
+ }
898
+ if ($len) {
899
+ $iv = mcrypt_generic($this->ecb, $iv);
900
+ $block = $iv ^ substr($plaintext, -$len);
901
+ $iv = substr_replace($iv, $block, 0, $len);
902
+ $ciphertext.= $block;
903
+ $pos = $len;
904
+ }
905
+ return $ciphertext;
906
+ }
907
+
908
+ if (!$this->continuousBuffer) {
909
+ mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
910
+ }
911
+
912
+ return $ciphertext;
913
+ }
914
+
915
+ if (empty($this->K)) {
916
+ $this->setKey($this->key);
917
+ }
918
+
919
+ $inline = $this->inline_crypt;
920
+ return $inline('encrypt', $this, $plaintext);
921
+ }
922
+
923
+ /**
924
+ * Decrypts a message.
925
+ *
926
+ * If strlen($ciphertext) is not a multiple of 16, null bytes will be added to the end of the string until it is.
927
+ *
928
+ * @see Crypt_Twofish::encrypt()
929
+ * @access public
930
+ * @param String $ciphertext
931
+ */
932
+ function decrypt($ciphertext)
933
+ {
934
+ if ( CRYPT_TWOFISH_MODE == CRYPT_TWOFISH_MODE_MCRYPT ) {
935
+ if ($this->paddable) {
936
+ // we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic :
937
+ // "The data is padded with "\0" to make sure the length of the data is n * blocksize."
938
+ $ciphertext = str_pad($ciphertext, strlen($ciphertext) + (16 - strlen($ciphertext) % 16) % 16, chr(0));
939
+ }
940
+
941
+ if ($this->dechanged) {
942
+ mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
943
+ if ($this->mode == 'ncfb') {
944
+ mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
945
+ }
946
+ $this->dechanged = false;
947
+ }
948
+
949
+ if ($this->mode != 'ncfb' || !$this->continuousBuffer) {
950
+ $plaintext = mdecrypt_generic($this->demcrypt, $ciphertext);
951
+ } else {
952
+ $iv = &$this->decryptIV;
953
+ $pos = &$this->debuffer['pos'];
954
+ $len = strlen($ciphertext);
955
+ $plaintext = '';
956
+ $i = 0;
957
+ if ($pos) {
958
+ $orig_pos = $pos;
959
+ $max = 16 - $pos;
960
+ if ($len >= $max) {
961
+ $i = $max;
962
+ $len-= $max;
963
+ $pos = 0;
964
+ } else {
965
+ $i = $len;
966
+ $pos+= $len;
967
+ $len = 0;
968
+ }
969
+ $plaintext = substr($iv, $orig_pos) ^ $ciphertext;
970
+ $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
971
+ }
972
+ if ($len >= 16) {
973
+ $cb = substr($ciphertext, $i, $len - $len % 16);
974
+ $plaintext.= mcrypt_generic($this->ecb, $iv . $cb) ^ $cb;
975
+ $iv = substr($cb, -16);
976
+ $len%= 16;
977
+ }
978
+ if ($len) {
979
+ $iv = mcrypt_generic($this->ecb, $iv);
980
+ $plaintext.= $iv ^ substr($ciphertext, -$len);
981
+ $iv = substr_replace($iv, substr($ciphertext, -$len), 0, $len);
982
+ $pos = $len;
983
+ }
984
+ return $plaintext;
985
+ }
986
+
987
+ if (!$this->continuousBuffer) {
988
+ mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
989
+ }
990
+
991
+ return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
992
+ }
993
+
994
+ if (empty($this->K)) {
995
+ $this->setKey($this->key);
996
+ }
997
+
998
+ $inline = $this->inline_crypt;
999
+ return $inline('decrypt', $this, $ciphertext);
1000
+ }
1001
+
1002
+ /**
1003
+ * Treat consecutive "packets" as if they are a continuous buffer.
1004
+ *
1005
+ * @see Crypt_Twofish::disableContinuousBuffer()
1006
+ * @access public
1007
+ */
1008
+ function enableContinuousBuffer()
1009
+ {
1010
+ $this->continuousBuffer = true;
1011
+ }
1012
+
1013
+ /**
1014
+ * Treat consecutive packets as if they are a discontinuous buffer.
1015
+ *
1016
+ * The default behavior.
1017
+ *
1018
+ * @see Crypt_Twofish::enableContinuousBuffer()
1019
+ * @access public
1020
+ */
1021
+ function disableContinuousBuffer()
1022
+ {
1023
+ $this->continuousBuffer = false;
1024
+ $this->encryptIV = $this->iv;
1025
+ $this->decryptIV = $this->iv;
1026
+ $this->enbuffer = array('encrypted' => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true);
1027
+ $this->debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0, 'demcrypt_init' => true);
1028
+
1029
+ if (CRYPT_TWOFISH_MODE == CRYPT_TWOFISH_MODE_MCRYPT) {
1030
+ mcrypt_generic_init($this->enmcrypt, $this->key, $this->iv);
1031
+ mcrypt_generic_init($this->demcrypt, $this->key, $this->iv);
1032
+ }
1033
+ }
1034
+
1035
+ /**
1036
+ * Pad "packets".
1037
+ *
1038
+ * Twofish works by encrypting 16 bytes at a time. If you ever need to encrypt or decrypt something that's not
1039
+ * a multiple of 16, it becomes necessary to pad the input so that it's length is a multiple of eight.
1040
+ *
1041
+ * Padding is enabled by default. Sometimes, however, it is undesirable to pad strings. Such is the case in SSH1,
1042
+ * where "packets" are padded with random bytes before being encrypted. Unpad these packets and you risk stripping
1043
+ * away characters that shouldn't be stripped away. (SSH knows how many bytes are added because the length is
1044
+ * transmitted separately)
1045
+ *
1046
+ * @see Crypt_Twofish::disablePadding()
1047
+ * @access public
1048
+ */
1049
+ function enablePadding()
1050
+ {
1051
+ $this->padding = true;
1052
+ }
1053
+
1054
+ /**
1055
+ * Do not pad packets.
1056
+ *
1057
+ * @see Crypt_Twofish::enablePadding()
1058
+ * @access public
1059
+ */
1060
+ function disablePadding()
1061
+ {
1062
+ $this->padding = false;
1063
+ }
1064
+
1065
+ /**
1066
+ * Pads a string
1067
+ *
1068
+ * Pads a string using the RSA PKCS padding standards so that its length is a multiple of the blocksize (16).
1069
+ *
1070
+ * If padding is disabled and $text is not a multiple of the blocksize, the string will be padded regardless
1071
+ * and padding will, hence forth, be enabled.
1072
+ *
1073
+ * @see Crypt_Twofish::_unpad()
1074
+ * @access private
1075
+ */
1076
+ function _pad($text)
1077
+ {
1078
+ $length = strlen($text);
1079
+
1080
+ if (!$this->padding) {
1081
+ if ($length % 16 == 0) {
1082
+ return $text;
1083
+ } else {
1084
+ user_error("The plaintext's length ($length) is not a multiple of the block size (16)");
1085
+ $this->padding = true;
1086
+ }
1087
+ }
1088
+
1089
+ $pad = 16 - ($length % 16);
1090
+
1091
+ return str_pad($text, $length + $pad, chr($pad));
1092
+ }
1093
+
1094
+ /**
1095
+ * Unpads a string
1096
+ *
1097
+ * If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong
1098
+ * and false will be returned.
1099
+ *
1100
+ * @see Crypt_Twofish::_pad()
1101
+ * @access private
1102
+ */
1103
+ function _unpad($text)
1104
+ {
1105
+ if (!$this->padding) {
1106
+ return $text;
1107
+ }
1108
+
1109
+ $length = ord($text[strlen($text) - 1]);
1110
+
1111
+ if (!$length || $length > 16) {
1112
+ return false;
1113
+ }
1114
+
1115
+ return substr($text, 0, -$length);
1116
+ }
1117
+
1118
+ /**
1119
+ * String Shift
1120
+ *
1121
+ * Inspired by array_shift
1122
+ *
1123
+ * @param String $string
1124
+ * @return String
1125
+ * @access private
1126
+ */
1127
+ function _string_shift(&$string)
1128
+ {
1129
+ $substr = substr($string, 0, 16);
1130
+ $string = substr($string, 16);
1131
+ return $substr;
1132
+ }
1133
+
1134
+ /**
1135
+ * Generate CTR XOR encryption key
1136
+ *
1137
+ * Encrypt the output of this and XOR it against the ciphertext / plaintext to get the
1138
+ * plaintext / ciphertext in CTR mode.
1139
+ *
1140
+ * @see Crypt_Twofish::decrypt()
1141
+ * @see Crypt_Twofish::encrypt()
1142
+ * @access public
1143
+ * @param String $iv
1144
+ */
1145
+ function _generate_xor(&$iv)
1146
+ {
1147
+ $xor = $iv;
1148
+ for ($j = 4; $j <= 16; $j+=4) {
1149
+ $temp = substr($iv, -$j, 4);
1150
+ switch ($temp) {
1151
+ case "\xFF\xFF\xFF\xFF":
1152
+ $iv = substr_replace($iv, "\x00\x00\x00\x00", -$j, 4);
1153
+ break;
1154
+ case "\x7F\xFF\xFF\xFF":
1155
+ $iv = substr_replace($iv, "\x80\x00\x00\x00", -$j, 4);
1156
+ break 2;
1157
+ default:
1158
+ extract(unpack('Ncount', $temp));
1159
+ $iv = substr_replace($iv, pack('N', $count + 1), -$j, 4);
1160
+ break 2;
1161
+ }
1162
+ }
1163
+
1164
+ return $xor;
1165
+ }
1166
+
1167
+ /**
1168
+ * mds_rem function using by the twofish cipher algorithm
1169
+ *
1170
+ * @access private
1171
+ * @param String $A
1172
+ * @param String $B
1173
+ * @return Array
1174
+ */
1175
+ function mds_rem($A, $B)
1176
+ {
1177
+ // No gain by unrolling this loop.
1178
+ for ($i = 0; $i < 8; ++$i) {
1179
+ // Get most significant coefficient.
1180
+ $t = 0xff & ($B >> 24);
1181
+
1182
+ // Shift the others up.
1183
+ $B = ($B << 8) | (0xff & ($A >> 24));
1184
+ $A<<= 8;
1185
+
1186
+ $u = $t << 1;
1187
+
1188
+ // Subtract the modular polynomial on overflow.
1189
+ if ($t & 0x80) {
1190
+ $u^= 0x14d;
1191
+ }
1192
+
1193
+ // Remove t * (a * x^2 + 1).
1194
+ $B ^= $t ^ ($u << 16);
1195
+
1196
+ // Form u = a*t + t/a = t*(a + 1/a).
1197
+ $u^= 0x7fffffff & ($t >> 1);
1198
+
1199
+ // Add the modular polynomial on underflow.
1200
+ if ($t & 0x01) $u^= 0xa6 ;
1201
+
1202
+ // Remove t * (a + 1/a) * (x^3 + x).
1203
+ $B^= ($u << 24) | ($u << 8);
1204
+ }
1205
+
1206
+ return array(
1207
+ 0xff & $B >> 24,
1208
+ 0xff & $B >> 16,
1209
+ 0xff & $B >> 8,
1210
+ 0xff & $B);
1211
+ }
1212
+
1213
+ /**
1214
+ * Creates performance-optimized function for de/encrypt(), storing it in $this->inline_crypt
1215
+ *
1216
+ * @access private
1217
+ */
1218
+ function inline_crypt_setup()
1219
+ {
1220
+ $lambda_functions =& Crypt_Twofish::get_lambda_functions();
1221
+ $block_size = 16;
1222
+ $mode = $this->mode;
1223
+ $code_hash = "$mode";
1224
+
1225
+ if (!isset($lambda_functions[$code_hash])) {
1226
+ $init_cryptBlock = '
1227
+ $S0 = $self->S0;
1228
+ $S1 = $self->S1;
1229
+ $S2 = $self->S2;
1230
+ $S3 = $self->S3;
1231
+ extract($self->K, EXTR_PREFIX_ALL, "K");
1232
+ ';
1233
+
1234
+ // Generating encrypt code:
1235
+ $_encryptBlock = '
1236
+ $in = unpack("V4", $in);
1237
+ $R0 = $K_0 ^ $in[1];
1238
+ $R1 = $K_1 ^ $in[2];
1239
+ $R2 = $K_2 ^ $in[3];
1240
+ $R3 = $K_3 ^ $in[4];
1241
+ ';
1242
+ for ($ki = 7, $i = 0; $i < 8; ++$i) {
1243
+ $_encryptBlock.= '
1244
+ $t0 = $S0[ $R0 & 0xff] ^
1245
+ $S1[($R0 >> 8) & 0xff] ^
1246
+ $S2[($R0 >> 16) & 0xff] ^
1247
+ $S3[($R0 >> 24) & 0xff];
1248
+ $t1 = $S0[($R1 >> 24) & 0xff] ^
1249
+ $S1[ $R1 & 0xff] ^
1250
+ $S2[($R1 >> 8) & 0xff] ^
1251
+ $S3[($R1 >> 16) & 0xff];
1252
+ $R2^= ($t0 + $t1 + $K_'.(++$ki).');
1253
+ $R2 = ($R2 >> 1 & 0x7fffffff) | ($R2 << 31);
1254
+ $R3 = ((($R3 >> 31) & 1) | ($R3 << 1)) ^ ($t0 + ($t1 << 1) + $K_'.(++$ki).');
1255
+
1256
+ $t0 = $S0[ $R2 & 0xff] ^
1257
+ $S1[($R2 >> 8) & 0xff] ^
1258
+ $S2[($R2 >> 16) & 0xff] ^
1259
+ $S3[($R2 >> 24) & 0xff];
1260
+ $t1 = $S0[($R3 >> 24) & 0xff] ^
1261
+ $S1[ $R3 & 0xff] ^
1262
+ $S2[($R3 >> 8) & 0xff] ^
1263
+ $S3[($R3 >> 16) & 0xff];
1264
+ $R0^= ($t0 + $t1 + $K_'.(++$ki).');
1265
+ $R0 = ($R0 >> 1 & 0x7fffffff) | ($R0 << 31);
1266
+ $R1 = ((($R1 >> 31) & 1) | ($R1 << 1)) ^ ($t0 + ($t1 << 1) + $K_'.(++$ki).');
1267
+ ';
1268
+ }
1269
+ $_encryptBlock.= '
1270
+ $in = pack("V4", $K_4 ^ $R2,
1271
+ $K_5 ^ $R3,
1272
+ $K_6 ^ $R0,
1273
+ $K_7 ^ $R1);
1274
+ ';
1275
+
1276
+ // Generating decrypt code:
1277
+ $_decryptBlock = '
1278
+ $in = unpack("V4", $in);
1279
+ $R0 = $K_4 ^ $in[1];
1280
+ $R1 = $K_5 ^ $in[2];
1281
+ $R2 = $K_6 ^ $in[3];
1282
+ $R3 = $K_7 ^ $in[4];
1283
+ ';
1284
+ for ($ki = 40, $i = 0; $i < 8; ++$i) {
1285
+ $_decryptBlock.= '
1286
+ $t0 = $S0[$R0 & 0xff] ^
1287
+ $S1[$R0 >> 8 & 0xff] ^
1288
+ $S2[$R0 >> 16 & 0xff] ^
1289
+ $S3[$R0 >> 24 & 0xff];
1290
+ $t1 = $S0[$R1 >> 24 & 0xff] ^
1291
+ $S1[$R1 & 0xff] ^
1292
+ $S2[$R1 >> 8 & 0xff] ^
1293
+ $S3[$R1 >> 16 & 0xff];
1294
+ $R3^= $t0 + ($t1 << 1) + $K_'.(--$ki).';
1295
+ $R3 = $R3 >> 1 & 0x7fffffff | $R3 << 31;
1296
+ $R2 = ($R2 >> 31 & 0x1 | $R2 << 1) ^ ($t0 + $t1 + $K_'.(--$ki).');
1297
+
1298
+ $t0 = $S0[$R2 & 0xff] ^
1299
+ $S1[$R2 >> 8 & 0xff] ^
1300
+ $S2[$R2 >> 16 & 0xff] ^
1301
+ $S3[$R2 >> 24 & 0xff];
1302
+ $t1 = $S0[$R3 >> 24 & 0xff] ^
1303
+ $S1[$R3 & 0xff] ^
1304
+ $S2[$R3 >> 8 & 0xff] ^
1305
+ $S3[$R3 >> 16 & 0xff];
1306
+ $R1^= $t0 + ($t1 << 1) + $K_'.(--$ki).';
1307
+ $R1 = $R1 >> 1 & 0x7fffffff | $R1 << 31;
1308
+ $R0 = ($R0 >> 31 & 0x1 | $R0 << 1) ^ ($t0 + $t1 + $K_'.(--$ki).');
1309
+ ';
1310
+ }
1311
+ $_decryptBlock.= '
1312
+ $in = pack("V4", $K_0 ^ $R2,
1313
+ $K_1 ^ $R3,
1314
+ $K_2 ^ $R0,
1315
+ $K_3 ^ $R1);
1316
+ ';
1317
+
1318
+ // Generating mode of operation code:
1319
+ switch ($mode) {
1320
+ case CRYPT_TWOFISH_MODE_ECB:
1321
+ $encrypt = '
1322
+ $ciphertext = "";
1323
+ $text = $self->_pad($text);
1324
+ $plaintext_len = strlen($text);
1325
+
1326
+ for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') {
1327
+ $in = substr($text, $i, '.$block_size.');
1328
+ '.$_encryptBlock.'
1329
+ $ciphertext.= $in;
1330
+ }
1331
+
1332
+ return $ciphertext;
1333
+ ';
1334
+
1335
+ $decrypt = '
1336
+ $plaintext = "";
1337
+ $text = str_pad($text, strlen($text) + ('.$block_size.' - strlen($text) % '.$block_size.') % '.$block_size.', chr(0));
1338
+ $ciphertext_len = strlen($text);
1339
+
1340
+ for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') {
1341
+ $in = substr($text, $i, '.$block_size.');
1342
+ '.$_decryptBlock.'
1343
+ $plaintext.= $in;
1344
+ }
1345
+
1346
+ return $self->_unpad($plaintext);
1347
+ ';
1348
+ break;
1349
+ case CRYPT_TWOFISH_MODE_CBC:
1350
+ $encrypt = '
1351
+ $ciphertext = "";
1352
+ $text = $self->_pad($text);
1353
+ $plaintext_len = strlen($text);
1354
+
1355
+ $in = $self->encryptIV;
1356
+
1357
+ for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') {
1358
+ $in = substr($text, $i, '.$block_size.') ^ $in;
1359
+ '.$_encryptBlock.'
1360
+ $ciphertext.= $in;
1361
+ }
1362
+
1363
+ if ($self->continuousBuffer) {
1364
+ $self->encryptIV = $in;
1365
+ }
1366
+
1367
+ return $ciphertext;
1368
+ ';
1369
+
1370
+ $decrypt = '
1371
+ $plaintext = "";
1372
+ $text = str_pad($text, strlen($text) + ('.$block_size.' - strlen($text) % '.$block_size.') % '.$block_size.', chr(0));
1373
+ $ciphertext_len = strlen($text);
1374
+
1375
+ $iv = $self->decryptIV;
1376
+
1377
+ for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') {
1378
+ $in = $block = substr($text, $i, '.$block_size.');
1379
+ '.$_decryptBlock.'
1380
+ $plaintext.= $in ^ $iv;
1381
+ $iv = $block;
1382
+ }
1383
+
1384
+ if ($self->continuousBuffer) {
1385
+ $self->decryptIV = $iv;
1386
+ }
1387
+
1388
+ return $self->_unpad($plaintext);
1389
+ ';
1390
+ break;
1391
+ case CRYPT_TWOFISH_MODE_CTR:
1392
+ $encrypt = '
1393
+ $ciphertext = "";
1394
+ $plaintext_len = strlen($text);
1395
+ $xor = $self->encryptIV;
1396
+ $buffer = &$self->enbuffer;
1397
+
1398
+ if (strlen($buffer["encrypted"])) {
1399
+ for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') {
1400
+ $block = substr($text, $i, '.$block_size.');
1401
+ if (strlen($block) > strlen($buffer["encrypted"])) {
1402
+ $in = $self->_generate_xor($xor);
1403
+ '.$_encryptBlock.'
1404
+ $buffer["encrypted"].= $in;
1405
+ }
1406
+ $key = $self->_string_shift($buffer["encrypted"]);
1407
+ $ciphertext.= $block ^ $key;
1408
+ }
1409
+ } else {
1410
+ for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') {
1411
+ $block = substr($text, $i, '.$block_size.');
1412
+ $in = $self->_generate_xor($xor);
1413
+ '.$_encryptBlock.'
1414
+ $key = $in;
1415
+ $ciphertext.= $block ^ $key;
1416
+ }
1417
+ }
1418
+ if ($self->continuousBuffer) {
1419
+ $self->encryptIV = $xor;
1420
+ if ($start = $plaintext_len % '.$block_size.') {
1421
+ $buffer["encrypted"] = substr($key, $start) . $buffer["encrypted"];
1422
+ }
1423
+ }
1424
+
1425
+ return $ciphertext;
1426
+ ';
1427
+
1428
+ $decrypt = '
1429
+ $plaintext = "";
1430
+ $ciphertext_len = strlen($text);
1431
+ $xor = $self->decryptIV;
1432
+ $buffer = &$self->debuffer;
1433
+
1434
+ if (strlen($buffer["ciphertext"])) {
1435
+ for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') {
1436
+ $block = substr($text, $i, '.$block_size.');
1437
+ if (strlen($block) > strlen($buffer["ciphertext"])) {
1438
+ $in = $self->_generate_xor($xor);
1439
+ '.$_encryptBlock.'
1440
+ $buffer["ciphertext"].= $in;
1441
+ }
1442
+ $key = $self->_string_shift($buffer["ciphertext"]);
1443
+ $plaintext.= $block ^ $key;
1444
+ }
1445
+ } else {
1446
+ for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') {
1447
+ $block = substr($text, $i, '.$block_size.');
1448
+ $in = $self->_generate_xor($xor);
1449
+ '.$_encryptBlock.'
1450
+ $key = $in;
1451
+ $plaintext.= $block ^ $key;
1452
+ }
1453
+ }
1454
+ if ($self->continuousBuffer) {
1455
+ $self->decryptIV = $xor;
1456
+ if ($start = $ciphertext_len % '.$block_size.') {
1457
+ $buffer["ciphertext"] = substr($key, $start) . $buffer["ciphertext"];
1458
+ }
1459
+ }
1460
+
1461
+ return $plaintext;
1462
+ ';
1463
+ break;
1464
+ case CRYPT_TWOFISH_MODE_CFB:
1465
+ $encrypt = '
1466
+ $ciphertext = "";
1467
+ $buffer = &$self->enbuffer;
1468
+
1469
+ if ($self->continuousBuffer) {
1470
+ $iv = &$self->encryptIV;
1471
+ $pos = &$buffer["pos"];
1472
+ } else {
1473
+ $iv = $self->encryptIV;
1474
+ $pos = 0;
1475
+ }
1476
+ $len = strlen($text);
1477
+ $i = 0;
1478
+ if ($pos) {
1479
+ $orig_pos = $pos;
1480
+ $max = '.$block_size.' - $pos;
1481
+ if ($len >= $max) {
1482
+ $i = $max;
1483
+ $len-= $max;
1484
+ $pos = 0;
1485
+ } else {
1486
+ $i = $len;
1487
+ $pos+= $len;
1488
+ $len = 0;
1489
+ }
1490
+ $ciphertext = substr($iv, $orig_pos) ^ $text;
1491
+ $iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
1492
+ }
1493
+ while ($len >= '.$block_size.') {
1494
+ $in = $iv;
1495
+ '.$_encryptBlock.';
1496
+ $iv = $in ^ substr($text, $i, '.$block_size.');
1497
+ $ciphertext.= $iv;
1498
+ $len-= '.$block_size.';
1499
+ $i+= '.$block_size.';
1500
+ }
1501
+ if ($len) {
1502
+ $in = $iv;
1503
+ '.$_encryptBlock.'
1504
+ $iv = $in;
1505
+ $block = $iv ^ substr($text, $i);
1506
+ $iv = substr_replace($iv, $block, 0, $len);
1507
+ $ciphertext.= $block;
1508
+ $pos = $len;
1509
+ }
1510
+ return $ciphertext;
1511
+ ';
1512
+
1513
+ $decrypt = '
1514
+ $plaintext = "";
1515
+ $buffer = &$self->debuffer;
1516
+
1517
+ if ($self->continuousBuffer) {
1518
+ $iv = &$self->decryptIV;
1519
+ $pos = &$buffer["pos"];
1520
+ } else {
1521
+ $iv = $self->decryptIV;
1522
+ $pos = 0;
1523
+ }
1524
+ $len = strlen($text);
1525
+ $i = 0;
1526
+ if ($pos) {
1527
+ $orig_pos = $pos;
1528
+ $max = '.$block_size.' - $pos;
1529
+ if ($len >= $max) {
1530
+ $i = $max;
1531
+ $len-= $max;
1532
+ $pos = 0;
1533
+ } else {
1534
+ $i = $len;
1535
+ $pos+= $len;
1536
+ $len = 0;
1537
+ }
1538
+ $plaintext = substr($iv, $orig_pos) ^ $text;
1539
+ $iv = substr_replace($iv, substr($text, 0, $i), $orig_pos, $i);
1540
+ }
1541
+ while ($len >= '.$block_size.') {
1542
+ $in = $iv;
1543
+ '.$_encryptBlock.'
1544
+ $iv = $in;
1545
+ $cb = substr($text, $i, '.$block_size.');
1546
+ $plaintext.= $iv ^ $cb;
1547
+ $iv = $cb;
1548
+ $len-= '.$block_size.';
1549
+ $i+= '.$block_size.';
1550
+ }
1551
+ if ($len) {
1552
+ $in = $iv;
1553
+ '.$_encryptBlock.'
1554
+ $iv = $in;
1555
+ $plaintext.= $iv ^ substr($text, $i);
1556
+ $iv = substr_replace($iv, substr($text, $i), 0, $len);
1557
+ $pos = $len;
1558
+ }
1559
+
1560
+ return $plaintext;
1561
+ ';
1562
+ break;
1563
+ case CRYPT_TWOFISH_MODE_OFB:
1564
+ $encrypt = '
1565
+ $ciphertext = "";
1566
+ $plaintext_len = strlen($text);
1567
+ $xor = $self->encryptIV;
1568
+ $buffer = &$self->enbuffer;
1569
+
1570
+ if (strlen($buffer["xor"])) {
1571
+ for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') {
1572
+ $block = substr($text, $i, '.$block_size.');
1573
+ if (strlen($block) > strlen($buffer["xor"])) {
1574
+ $in = $xor;
1575
+ '.$_encryptBlock.'
1576
+ $xor = $in;
1577
+ $buffer["xor"].= $xor;
1578
+ }
1579
+ $key = $self->_string_shift($buffer["xor"]);
1580
+ $ciphertext.= $block ^ $key;
1581
+ }
1582
+ } else {
1583
+ for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') {
1584
+ $in = $xor;
1585
+ '.$_encryptBlock.'
1586
+ $xor = $in;
1587
+ $ciphertext.= substr($text, $i, '.$block_size.') ^ $xor;
1588
+ }
1589
+ $key = $xor;
1590
+ }
1591
+ if ($self->continuousBuffer) {
1592
+ $self->encryptIV = $xor;
1593
+ if ($start = $plaintext_len % '.$block_size.') {
1594
+ $buffer["xor"] = substr($key, $start) . $buffer["xor"];
1595
+ }
1596
+ }
1597
+ return $ciphertext;
1598
+ ';
1599
+
1600
+ $decrypt = '
1601
+ $plaintext = "";
1602
+ $ciphertext_len = strlen($text);
1603
+ $xor = $self->decryptIV;
1604
+ $buffer = &$self->debuffer;
1605
+
1606
+ if (strlen($buffer["xor"])) {
1607
+ for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') {
1608
+ $block = substr($text, $i, '.$block_size.');
1609
+ if (strlen($block) > strlen($buffer["xor"])) {
1610
+ $in = $xor;
1611
+ '.$_encryptBlock.'
1612
+ $xor = $in;
1613
+ $buffer["xor"].= $xor;
1614
+ }
1615
+ $key = $self->_string_shift($buffer["xor"]);
1616
+ $plaintext.= $block ^ $key;
1617
+ }
1618
+ } else {
1619
+ for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') {
1620
+ $in = $xor;
1621
+ '.$_encryptBlock.'
1622
+ $xor = $in;
1623
+ $plaintext.= substr($text, $i, '.$block_size.') ^ $xor;
1624
+ }
1625
+ $key = $xor;
1626
+ }
1627
+ if ($self->continuousBuffer) {
1628
+ $self->decryptIV = $xor;
1629
+ if ($start = $ciphertext_len % '.$block_size.') {
1630
+ $buffer["xor"] = substr($key, $start) . $buffer["xor"];
1631
+ }
1632
+ }
1633
+ return $plaintext;
1634
+ ';
1635
+ break;
1636
+ }
1637
+ $fnc_head = '$action, &$self, $text';
1638
+ $fnc_body = $init_cryptBlock . 'if ($action == "encrypt") { ' . $encrypt . ' } else { ' . $decrypt . ' }';
1639
+
1640
+ if (function_exists('create_function') && is_callable('create_function')) {
1641
+ $lambda_functions[$code_hash] = create_function($fnc_head, $fnc_body);
1642
+ } else {
1643
+ eval('function ' . ($lambda_functions[$code_hash] = 'f' . md5(microtime())) . '(' . $fnc_head . ') { ' . $fnc_body . ' }');
1644
+ }
1645
+ }
1646
+ $this->inline_crypt = $lambda_functions[$code_hash];
1647
+ }
1648
+
1649
+ /**
1650
+ * Holds the lambda_functions table (classwide)
1651
+ *
1652
+ * @see inline_crypt_setup()
1653
+ * @return Array
1654
+ * @access private
1655
+ */
1656
+ function &get_lambda_functions()
1657
+ {
1658
+ static $functions = array();
1659
+ return $functions;
1660
+ }
1661
+ }
1662
+
1663
+ // vim: ts=4:sw=4:et:
1664
+ // vim6: fdl=1:
modules/phpseclib/File/ANSI.php ADDED
@@ -0,0 +1,560 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3
+
4
+ /**
5
+ * Pure-PHP ANSI Decoder
6
+ *
7
+ * PHP versions 4 and 5
8
+ *
9
+ * If you call read() in Net_SSH2 you may get {@link http://en.wikipedia.org/wiki/ANSI_escape_code ANSI escape codes} back.
10
+ * They'd look like chr(0x1B) . '[00m' or whatever (0x1B = ESC). They tell a
11
+ * {@link http://en.wikipedia.org/wiki/Terminal_emulator terminal emulator} how to format the characters, what
12
+ * color to display them in, etc. File_ANSI is a {@link http://en.wikipedia.org/wiki/VT100 VT100} terminal emulator.
13
+ *
14
+ * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
15
+ * of this software and associated documentation files (the "Software"), to deal
16
+ * in the Software without restriction, including without limitation the rights
17
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
18
+ * copies of the Software, and to permit persons to whom the Software is
19
+ * furnished to do so, subject to the following conditions:
20
+ *
21
+ * The above copyright notice and this permission notice shall be included in
22
+ * all copies or substantial portions of the Software.
23
+ *
24
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
30
+ * THE SOFTWARE.
31
+ *
32
+ * @category File
33
+ * @package File_ANSI
34
+ * @author Jim Wigginton <terrafrost@php.net>
35
+ * @copyright MMXII Jim Wigginton
36
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
37
+ * @link http://phpseclib.sourceforge.net
38
+ */
39
+
40
+ /**
41
+ * Pure-PHP ANSI Decoder
42
+ *
43
+ * @author Jim Wigginton <terrafrost@php.net>
44
+ * @version 0.3.0
45
+ * @access public
46
+ * @package File_ANSI
47
+ */
48
+ class File_ANSI {
49
+ /**
50
+ * Max Width
51
+ *
52
+ * @var Integer
53
+ * @access private
54
+ */
55
+ var $max_x;
56
+
57
+ /**
58
+ * Max Height
59
+ *
60
+ * @var Integer
61
+ * @access private
62
+ */
63
+ var $max_y;
64
+
65
+ /**
66
+ * Max History
67
+ *
68
+ * @var Integer
69
+ * @access private
70
+ */
71
+ var $max_history;
72
+
73
+ /**
74
+ * History
75
+ *
76
+ * @var Array
77
+ * @access private
78
+ */
79
+ var $history;
80
+
81
+ /**
82
+ * History Attributes
83
+ *
84
+ * @var Array
85
+ * @access private
86
+ */
87
+ var $history_attrs;
88
+
89
+ /**
90
+ * Current Column
91
+ *
92
+ * @var Integer
93
+ * @access private
94
+ */
95
+ var $x;
96
+
97
+ /**
98
+ * Current Row
99
+ *
100
+ * @var Integer
101
+ * @access private
102
+ */
103
+ var $y;
104
+
105
+ /**
106
+ * Old Column
107
+ *
108
+ * @var Integer
109
+ * @access private
110
+ */
111
+ var $old_x;
112
+
113
+ /**
114
+ * Old Row
115
+ *
116
+ * @var Integer
117
+ * @access private
118
+ */
119
+ var $old_y;
120
+
121
+ /**
122
+ * An empty attribute row
123
+ *
124
+ * @var Array
125
+ * @access private
126
+ */
127
+ var $attr_row;
128
+
129
+ /**
130
+ * The current screen text
131
+ *
132
+ * @var Array
133
+ * @access private
134
+ */
135
+ var $screen;
136
+
137
+ /**
138
+ * The current screen attributes
139
+ *
140
+ * @var Array
141
+ * @access private
142
+ */
143
+ var $attrs;
144
+
145
+ /**
146
+ * The current foreground color
147
+ *
148
+ * @var String
149
+ * @access private
150
+ */
151
+ var $foreground;
152
+
153
+ /**
154
+ * The current background color
155
+ *
156
+ * @var String
157
+ * @access private
158
+ */
159
+ var $background;
160
+
161
+ /**
162
+ * Bold flag
163
+ *
164
+ * @var Boolean
165
+ * @access private
166
+ */
167
+ var $bold;
168
+
169
+ /**
170
+ * Underline flag
171
+ *
172
+ * @var Boolean
173
+ * @access private
174
+ */
175
+ var $underline;
176
+
177
+ /**
178
+ * Blink flag
179
+ *
180
+ * @var Boolean
181
+ * @access private
182
+ */
183
+ var $blink;
184
+
185
+ /**
186
+ * Reverse flag
187
+ *
188
+ * @var Boolean
189
+ * @access private
190
+ */
191
+ var $reverse;
192
+
193
+ /**
194
+ * Color flag
195
+ *
196
+ * @var Boolean
197
+ * @access private
198
+ */
199
+ var $color;
200
+
201
+ /**
202
+ * Current ANSI code
203
+ *
204
+ * @var String
205
+ * @access private
206
+ */
207
+ var $ansi;
208
+
209
+ /**
210
+ * Default Constructor.
211
+ *
212
+ * @return File_ANSI
213
+ * @access public
214
+ */
215
+ function File_ANSI()
216
+ {
217
+ $this->setHistory(200);
218
+ $this->setDimensions(80, 24);
219
+ }
220
+
221
+ /**
222
+ * Set terminal width and height
223
+ *
224
+ * Resets the screen as well
225
+ *
226
+ * @param Integer $x
227
+ * @param Integer $y
228
+ * @access public
229
+ */
230
+ function setDimensions($x, $y)
231
+ {
232
+ $this->max_x = $x - 1;
233
+ $this->max_y = $y - 1;
234
+ $this->x = $this->y = 0;
235
+ $this->history = $this->history_attrs = array();
236
+ $this->attr_row = array_fill(0, $this->max_x + 1, '');
237
+ $this->screen = array_fill(0, $this->max_y + 1, '');
238
+ $this->attrs = array_fill(0, $this->max_y + 1, $this->attr_row);
239
+ $this->foreground = 'white';
240
+ $this->background = 'black';
241
+ $this->bold = false;
242
+ $this->underline = false;
243
+ $this->blink = false;
244
+ $this->reverse = false;
245
+ $this->color = false;
246
+
247
+ $this->ansi = '';
248
+ }
249
+
250
+ /**
251
+ * Set the number of lines that should be logged past the terminal height
252
+ *
253
+ * @param Integer $x
254
+ * @param Integer $y
255
+ * @access public
256
+ */
257
+ function setHistory($history)
258
+ {
259
+ $this->max_history = $history;
260
+ }
261
+
262
+ /**
263
+ * Load a string
264
+ *
265
+ * @param String $source
266
+ * @access public
267
+ */
268
+ function loadString($source)
269
+ {
270
+ $this->setDimensions($this->max_x + 1, $this->max_y + 1);
271
+ $this->appendString($source);
272
+ }
273
+
274
+ /**
275
+ * Appdend a string
276
+ *
277
+ * @param String $source
278
+ * @access public
279
+ */
280
+ function appendString($source)
281
+ {
282
+ for ($i = 0; $i < strlen($source); $i++) {
283
+ if (strlen($this->ansi)) {
284
+ $this->ansi.= $source[$i];
285
+ $chr = ord($source[$i]);
286
+ // http://en.wikipedia.org/wiki/ANSI_escape_code#Sequence_elements
287
+ // single character CSI's not currently supported
288
+ switch (true) {
289
+ case $this->ansi == "\x1B=":
290
+ $this->ansi = '';
291
+ continue 2;
292
+ case strlen($this->ansi) == 2 && $chr >= 64 && $chr <= 95 && $chr != ord('['):
293
+ case strlen($this->ansi) > 2 && $chr >= 64 && $chr <= 126:
294
+ break;
295
+ default:
296
+ continue 2;
297
+ }
298
+ // http://ascii-table.com/ansi-escape-sequences-vt-100.php
299
+ switch ($this->ansi) {
300
+ case "\x1B[H": // Move cursor to upper left corner
301
+ $this->old_x = $this->x;
302
+ $this->old_y = $this->y;
303
+ $this->x = $this->y = 0;
304
+ break;
305
+ case "\x1B[J": // Clear screen from cursor down
306
+ $this->history = array_merge($this->history, array_slice(array_splice($this->screen, $this->y + 1), 0, $this->old_y));
307
+ $this->screen = array_merge($this->screen, array_fill($this->y, $this->max_y, ''));
308
+
309
+ $this->history_attrs = array_merge($this->history_attrs, array_slice(array_splice($this->attrs, $this->y + 1), 0, $this->old_y));
310
+ $this->attrs = array_merge($this->attrs, array_fill($this->y, $this->max_y, $this->attr_row));
311
+
312
+ if (count($this->history) == $this->max_history) {
313
+ array_shift($this->history);
314
+ array_shift($this->history_attrs);
315
+ }
316
+ case "\x1B[K": // Clear screen from cursor right
317
+ $this->screen[$this->y] = substr($this->screen[$this->y], 0, $this->x);
318
+
319
+ array_splice($this->attrs[$this->y], $this->x + 1);
320
+ break;
321
+ case "\x1B[2K": // Clear entire line
322
+ $this->screen[$this->y] = str_repeat(' ', $this->x);
323
+ $this->attrs[$this->y] = $this->attr_row;
324
+ break;
325
+ case "\x1B[?1h": // set cursor key to application
326
+ case "\x1B[?25h": // show the cursor
327
+ break;
328
+ case "\x1BE": // Move to next line
329
+ $this->_newLine();
330
+ $this->x = 0;
331
+ break;
332
+ default:
333
+ switch (true) {
334
+ case preg_match('#\x1B\[(\d+);(\d+)H#', $this->ansi, $match): // Move cursor to screen location v,h
335
+ $this->old_x = $this->x;
336
+ $this->old_y = $this->y;
337
+ $this->x = $match[2] - 1;
338
+ $this->y = $match[1] - 1;
339
+ break;
340
+ case preg_match('#\x1B\[(\d+)C#', $this->ansi, $match): // Move cursor right n lines
341
+ $this->old_x = $this->x;
342
+ $x = $match[1] - 1;
343
+ break;
344
+ case preg_match('#\x1B\[(\d+);(\d+)r#', $this->ansi, $match): // Set top and bottom lines of a window
345
+ break;
346
+ case preg_match('#\x1B\[(\d*(?:;\d*)*)m#', $this->ansi, $match): // character attributes
347
+ $mods = explode(';', $match[1]);
348
+ foreach ($mods as $mod) {
349
+ switch ($mod) {
350
+ case 0: // Turn off character attributes
351
+ $this->attrs[$this->y][$this->x] = '';
352
+
353
+ if ($this->bold) $this->attrs[$this->y][$this->x].= '</b>';
354
+ if ($this->underline) $this->attrs[$this->y][$this->x].= '</underline>';
355
+ if ($this->blink) $this->attrs[$this->y][$this->x].= '</blink>';
356
+ if ($this->color) $this->attrs[$this->y][$this->x].= '</span>';
357
+
358
+ if ($this->reverse) {
359
+ $temp = $this->background;
360
+ $this->background = $this->foreground;
361
+ $this->foreground = $temp;
362
+ }
363
+
364
+ $this->bold = $this->underline = $this->blink = $this->color = $this->reverse = false;
365
+ break;
366
+ case 1: // Turn bold mode on
367
+ if (!$this->bold) {
368
+ $this->attrs[$this->y][$this->x] = '<b>';
369
+ $this->bold = true;
370
+ }
371
+ break;
372
+ case 4: // Turn underline mode on
373
+ if (!$this->underline) {
374
+ $this->attrs[$this->y][$this->x] = '<u>';
375
+ $this->underline = true;
376
+ }
377
+ break;
378
+ case 5: // Turn blinking mode on
379
+ if (!$this->blink) {
380
+ $this->attrs[$this->y][$this->x] = '<blink>';
381
+ $this->blink = true;
382
+ }
383
+ break;
384
+ case 7: // Turn reverse video on
385
+ $this->reverse = !$this->reverse;
386
+ $temp = $this->background;
387
+ $this->background = $this->foreground;
388
+ $this->foreground = $temp;
389
+ $this->attrs[$this->y][$this->x] = '<span style="color: ' . $this->foreground . '; background: ' . $this->background . '">';
390
+ if ($this->color) {
391
+ $this->attrs[$this->y][$this->x] = '</span>' . $this->attrs[$this->y][$this->x];
392
+ }
393
+ $this->color = true;
394
+ break;
395
+ default: // set colors
396
+ //$front = $this->reverse ? &$this->background : &$this->foreground;
397
+ $front = &$this->{ $this->reverse ? 'background' : 'foreground' };
398
+ //$back = $this->reverse ? &$this->foreground : &$this->background;
399
+ $back = &$this->{ $this->reverse ? 'foreground' : 'background' };
400
+ switch ($mod) {
401
+ case 30: $front = 'black'; break;
402
+ case 31: $front = 'red'; break;
403
+ case 32: $front = 'green'; break;
404
+ case 33: $front = 'yellow'; break;
405
+ case 34: $front = 'blue'; break;
406
+ case 35: $front = 'magenta'; break;
407
+ case 36: $front = 'cyan'; break;
408
+ case 37: $front = 'white'; break;
409
+
410
+ case 40: $back = 'black'; break;
411
+ case 41: $back = 'red'; break;
412
+ case 42: $back = 'green'; break;
413
+ case 43: $back = 'yellow'; break;
414
+ case 44: $back = 'blue'; break;
415
+ case 45: $back = 'magenta'; break;
416
+ case 46: $back = 'cyan'; break;
417
+ case 47: $back = 'white'; break;
418
+
419
+ default:
420
+ user_error('Unsupported attribute: ' . $mod);
421
+ $this->ansi = '';
422
+ break 2;
423
+ }
424
+
425
+ unset($temp);
426
+ $this->attrs[$this->y][$this->x] = '<span style="color: ' . $this->foreground . '; background: ' . $this->background . '">';
427
+ if ($this->color) {
428
+ $this->attrs[$this->y][$this->x] = '</span>' . $this->attrs[$this->y][$this->x];
429
+ }
430
+ $this->color = true;
431
+ }
432
+ }
433
+ break;
434
+ default:
435
+ user_error("{$this->ansi} unsupported\r\n");
436
+ }
437
+ }
438
+ $this->ansi = '';
439
+ continue;
440
+ }
441
+
442
+ switch ($source[$i]) {
443
+ case "\r":
444
+ $this->x = 0;
445
+ break;
446
+ case "\n":
447
+ $this->_newLine();
448
+ break;
449
+ case "\x0F": // shift
450
+ break;
451
+ case "\x1B": // start ANSI escape code
452
+ $this->ansi.= "\x1B";
453
+ break;
454
+ default:
455
+ $this->screen[$this->y] = substr_replace(
456
+ $this->screen[$this->y],
457
+ $source[$i],
458
+ $this->x,
459
+ 1
460
+ );
461
+
462
+ if ($this->x > $this->max_x) {
463
+ $this->x = 0;
464
+ $this->y++;
465
+ } else {
466
+ $this->x++;
467
+ }
468
+ }
469
+ }
470
+ }
471
+
472
+ /**
473
+ * Add a new line
474
+ *
475
+ * Also update the $this->screen and $this->history buffers
476
+ *
477
+ * @access private
478
+ */
479
+ function _newLine()
480
+ {
481
+ //if ($this->y < $this->max_y) {
482
+ // $this->y++;
483
+ //}
484
+
485
+ while ($this->y >= $this->max_y) {
486
+ $this->history = array_merge($this->history, array(array_shift($this->screen)));
487
+ $this->screen[] = '';
488
+
489
+ $this->history_attrs = array_merge($this->history_attrs, array(array_shift($this->attrs)));
490
+ $this->attrs[] = $this->attr_row;
491
+
492
+ if (count($this->history) >= $this->max_history) {
493
+ array_shift($this->history);
494
+ array_shift($this->history_attrs);
495
+ }
496
+
497
+ $this->y--;
498
+ }
499
+ $this->y++;
500
+ }
501
+
502
+ /**
503
+ * Returns the current screen without preformating
504
+ *
505
+ * @access private
506
+ * @return String
507
+ */
508
+ function _getScreen()
509
+ {
510
+ $output = '';
511
+ for ($i = 0; $i <= $this->max_y; $i++) {
512
+ for ($j = 0; $j <= $this->max_x + 1; $j++) {
513
+ if (isset($this->attrs[$i][$j])) {
514
+ $output.= $this->attrs[$i][$j];
515
+ }
516
+ if (isset($this->screen[$i][$j])) {
517
+ $output.= htmlspecialchars($this->screen[$i][$j]);
518
+ }
519
+ }
520
+ $output.= "\r\n";
521
+ }
522
+ return rtrim($output);
523
+ }
524
+
525
+ /**
526
+ * Returns the current screen
527
+ *
528
+ * @access public
529
+ * @return String
530
+ */
531
+ function getScreen()
532
+ {
533
+ return '<pre style="color: white; background: black" width="' . ($this->max_x + 1) . '">' . $this->_getScreen() . '</pre>';
534
+ }
535
+
536
+ /**
537
+ * Returns the current screen and the x previous lines
538
+ *
539
+ * @access public
540
+ * @return String
541
+ */
542
+ function getHistory()
543
+ {
544
+ $scrollback = '';
545
+ for ($i = 0; $i < count($this->history); $i++) {
546
+ for ($j = 0; $j <= $this->max_x + 1; $j++) {
547
+ if (isset($this->history_attrs[$i][$j])) {
548
+ $scrollback.= $this->history_attrs[$i][$j];
549
+ }
550
+ if (isset($this->history[$i][$j])) {
551
+ $scrollback.= htmlspecialchars($this->history[$i][$j]);
552
+ }
553
+ }
554
+ $scrollback.= "\r\n";
555
+ }
556
+ $scrollback.= $this->_getScreen();
557
+
558
+ return '<pre style="color: white; background: black" width="' . ($this->max_x + 1) . '">' . $scrollback . '</pre>';
559
+ }
560
+ }
modules/phpseclib/File/ASN1.php ADDED
@@ -0,0 +1,1293 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3
+
4
+ /**
5
+ * Pure-PHP ASN.1 Parser
6
+ *
7
+ * PHP versions 4 and 5
8
+ *
9
+ * ASN.1 provides the semantics for data encoded using various schemes. The most commonly
10
+ * utilized scheme is DER or the "Distinguished Encoding Rules". PEM's are base64 encoded
11
+ * DER blobs.
12
+ *
13
+ * File_ASN1 decodes and encodes DER formatted messages and places them in a semantic context.
14
+ *
15
+ * Uses the 1988 ASN.1 syntax.
16
+ *
17
+ * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
18
+ * of this software and associated documentation files (the "Software"), to deal
19
+ * in the Software without restriction, including without limitation the rights
20
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
21
+ * copies of the Software, and to permit persons to whom the Software is
22
+ * furnished to do so, subject to the following conditions:
23
+ *
24
+ * The above copyright notice and this permission notice shall be included in
25
+ * all copies or substantial portions of the Software.
26
+ *
27
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
30
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
31
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
32
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
33
+ * THE SOFTWARE.
34
+ *
35
+ * @category File
36
+ * @package File_ASN1
37
+ * @author Jim Wigginton <terrafrost@php.net>
38
+ * @copyright MMXII Jim Wigginton
39
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
40
+ * @link http://phpseclib.sourceforge.net
41
+ */
42
+
43
+ /**#@+
44
+ * Tag Classes
45
+ *
46
+ * @access private
47
+ * @link http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#page=12
48
+ */
49
+ define('FILE_ASN1_CLASS_UNIVERSAL', 0);
50
+ define('FILE_ASN1_CLASS_APPLICATION', 1);
51
+ define('FILE_ASN1_CLASS_CONTEXT_SPECIFIC', 2);
52
+ define('FILE_ASN1_CLASS_PRIVATE', 3);
53
+ /**#@-*/
54
+
55
+ /**#@+
56
+ * Tag Classes
57
+ *
58
+ * @access private
59
+ * @link http://www.obj-sys.com/asn1tutorial/node124.html
60
+ */
61
+ define('FILE_ASN1_TYPE_BOOLEAN', 1);
62
+ define('FILE_ASN1_TYPE_INTEGER', 2);
63
+ define('FILE_ASN1_TYPE_BIT_STRING', 3);
64
+ define('FILE_ASN1_TYPE_OCTET_STRING', 4);
65
+ define('FILE_ASN1_TYPE_NULL', 5);
66
+ define('FILE_ASN1_TYPE_OBJECT_IDENTIFIER',6);
67
+ //define('FILE_ASN1_TYPE_OBJECT_DESCRIPTOR',7);
68
+ //define('FILE_ASN1_TYPE_INSTANCE_OF', 8); // EXTERNAL
69
+ define('FILE_ASN1_TYPE_REAL', 9);
70
+ define('FILE_ASN1_TYPE_ENUMERATED', 10);
71
+ //define('FILE_ASN1_TYPE_EMBEDDED', 11);
72
+ define('FILE_ASN1_TYPE_UTF8_STRING', 12);
73
+ //define('FILE_ASN1_TYPE_RELATIVE_OID', 13);
74
+ define('FILE_ASN1_TYPE_SEQUENCE', 16); // SEQUENCE OF
75
+ define('FILE_ASN1_TYPE_SET', 17); // SET OF
76
+ /**#@-*/
77
+ /**#@+
78
+ * More Tag Classes
79
+ *
80
+ * @access private
81
+ * @link http://www.obj-sys.com/asn1tutorial/node10.html
82
+ */
83
+ define('FILE_ASN1_TYPE_NUMERIC_STRING', 18);
84
+ define('FILE_ASN1_TYPE_PRINTABLE_STRING',19);
85
+ define('FILE_ASN1_TYPE_TELETEX_STRING', 20); // T61String
86
+ define('FILE_ASN1_TYPE_VIDEOTEX_STRING', 21);
87
+ define('FILE_ASN1_TYPE_IA5_STRING', 22);
88
+ define('FILE_ASN1_TYPE_UTC_TIME', 23);
89
+ define('FILE_ASN1_TYPE_GENERALIZED_TIME',24);
90
+ define('FILE_ASN1_TYPE_GRAPHIC_STRING', 25);
91
+ define('FILE_ASN1_TYPE_VISIBLE_STRING', 26); // ISO646String
92
+ define('FILE_ASN1_TYPE_GENERAL_STRING', 27);
93
+ define('FILE_ASN1_TYPE_UNIVERSAL_STRING',28);
94
+ //define('FILE_ASN1_TYPE_CHARACTER_STRING',29);
95
+ define('FILE_ASN1_TYPE_BMP_STRING', 30);
96
+ /**#@-*/
97
+
98
+ /**#@+
99
+ * Tag Aliases
100
+ *
101
+ * These tags are kinda place holders for other tags.
102
+ *
103
+ * @access private
104
+ */
105
+ define('FILE_ASN1_TYPE_CHOICE', -1);
106
+ define('FILE_ASN1_TYPE_ANY', -2);
107
+ /**#@-*/
108
+
109
+ /**
110
+ * ASN.1 Element
111
+ *
112
+ * Bypass normal encoding rules in File_ASN1::encodeDER()
113
+ *
114
+ * @author Jim Wigginton <terrafrost@php.net>
115
+ * @version 0.3.0
116
+ * @access public
117
+ * @package File_ASN1
118
+ */
119
+ class File_ASN1_Element {
120
+ /**
121
+ * Raw element value
122
+ *
123
+ * @var String
124
+ * @access private
125
+ */
126
+ var $element;
127
+
128
+ /**
129
+ * Constructor
130
+ *
131
+ * @param String $encoded
132
+ * @return File_ASN1_Element
133
+ * @access public
134
+ */
135
+ function File_ASN1_Element($encoded)
136
+ {
137
+ $this->element = $encoded;
138
+ }
139
+ }
140
+
141
+ /**
142
+ * Pure-PHP ASN.1 Parser
143
+ *
144
+ * @author Jim Wigginton <terrafrost@php.net>
145
+ * @version 0.3.0
146
+ * @access public
147
+ * @package File_ASN1
148
+ */
149
+ class File_ASN1 {
150
+ /**
151
+ * ASN.1 object identifier
152
+ *
153
+ * @var Array
154
+ * @access private
155
+ * @link http://en.wikipedia.org/wiki/Object_identifier
156
+ */
157
+ var $oids = array();
158
+
159
+ /**
160
+ * Default date format
161
+ *
162
+ * @var String
163
+ * @access private
164
+ * @link http://php.net/class.datetime
165
+ */
166
+ var $format = 'D, d M y H:i:s O';
167
+
168
+ /**
169
+ * Default date format
170
+ *
171
+ * @var Array
172
+ * @access private
173
+ * @see File_ASN1::setTimeFormat()
174
+ * @see File_ASN1::asn1map()
175
+ * @link http://php.net/class.datetime
176
+ */
177
+ var $encoded;
178
+
179
+ /**
180
+ * Filters
181
+ *
182
+ * If the mapping type is FILE_ASN1_TYPE_ANY what do we actually encode it as?
183
+ *
184
+ * @var Array
185
+ * @access private
186
+ * @see File_ASN1::_encode_der()
187
+ */
188
+ var $filters;
189
+
190
+ /**
191
+ * Type mapping table for the ANY type.
192
+ *
193
+ * Structured or unknown types are mapped to a FILE_ASN1_Element.
194
+ * Unambiguous types get the direct mapping (int/real/bool).
195
+ * Others are mapped as a choice, with an extra indexing level.
196
+ *
197
+ * @var Array
198
+ * @access public
199
+ */
200
+ var $ANYmap = array(
201
+ FILE_ASN1_TYPE_BOOLEAN => true,
202
+ FILE_ASN1_TYPE_INTEGER => true,
203
+ FILE_ASN1_TYPE_BIT_STRING => 'bitString',
204
+ FILE_ASN1_TYPE_OCTET_STRING => 'octetString',
205
+ FILE_ASN1_TYPE_NULL => 'null',
206
+ FILE_ASN1_TYPE_OBJECT_IDENTIFIER => 'objectIdentifier',
207
+ FILE_ASN1_TYPE_REAL => true,
208
+ FILE_ASN1_TYPE_ENUMERATED => 'enumerated',
209
+ FILE_ASN1_TYPE_UTF8_STRING => 'utf8String',
210
+ FILE_ASN1_TYPE_NUMERIC_STRING => 'numericString',
211
+ FILE_ASN1_TYPE_PRINTABLE_STRING => 'printableString',
212
+ FILE_ASN1_TYPE_TELETEX_STRING => 'teletexString',
213
+ FILE_ASN1_TYPE_VIDEOTEX_STRING => 'videotexString',
214
+ FILE_ASN1_TYPE_IA5_STRING => 'ia5String',
215
+ FILE_ASN1_TYPE_UTC_TIME => 'utcTime',
216
+ FILE_ASN1_TYPE_GENERALIZED_TIME => 'generalTime',
217
+ FILE_ASN1_TYPE_GRAPHIC_STRING => 'graphicString',
218
+ FILE_ASN1_TYPE_VISIBLE_STRING => 'visibleString',
219
+ FILE_ASN1_TYPE_GENERAL_STRING => 'generalString',
220
+ FILE_ASN1_TYPE_UNIVERSAL_STRING => 'universalString',
221
+ //FILE_ASN1_TYPE_CHARACTER_STRING => 'characterString',
222
+ FILE_ASN1_TYPE_BMP_STRING => 'bmpString'
223
+ );
224
+
225
+ /**
226
+ * String type to character size mapping table.
227
+ *
228
+ * Non-convertable types are absent from this table.
229
+ * size == 0 indicates variable length encoding.
230
+ *
231
+ * @var Array
232
+ * @access public
233
+ */
234
+ var $stringTypeSize = array(
235
+ FILE_ASN1_TYPE_UTF8_STRING => 0,
236
+ FILE_ASN1_TYPE_BMP_STRING => 2,
237
+ FILE_ASN1_TYPE_UNIVERSAL_STRING => 4,
238
+ FILE_ASN1_TYPE_PRINTABLE_STRING => 1,
239
+ FILE_ASN1_TYPE_TELETEX_STRING => 1,
240
+ FILE_ASN1_TYPE_IA5_STRING => 1,
241
+ FILE_ASN1_TYPE_VISIBLE_STRING => 1,
242
+ );
243
+
244
+ /**
245
+ * Default Constructor.
246
+ *
247
+ * @access public
248
+ */
249
+ function File_ASN1()
250
+ {
251
+ static $static_init = null;
252
+ if (!$static_init) {
253
+ $static_init = true;
254
+ if (!class_exists('Math_BigInteger')) {
255
+ require_once('Math/BigInteger.php');
256
+ }
257
+ }
258
+ }
259
+
260
+ /**
261
+ * Parse BER-encoding
262
+ *
263
+ * Serves a similar purpose to openssl's asn1parse
264
+ *
265
+ * @param String $encoded
266
+ * @return Array
267
+ * @access public
268
+ */
269
+ function decodeBER($encoded)
270
+ {
271
+ if (is_object($encoded) && strtolower(get_class($encoded)) == 'file_asn1_element') {
272
+ $encoded = $encoded->element;
273
+ }
274
+
275
+ $this->encoded = $encoded;
276
+ return $this->_decode_ber($encoded);
277
+ }
278
+
279
+ /**
280
+ * Parse BER-encoding (Helper function)
281
+ *
282
+ * Sometimes we want to get the BER encoding of a particular tag. $start lets us do that without having to reencode.
283
+ * $encoded is passed by reference for the recursive calls done for FILE_ASN1_TYPE_BIT_STRING and
284
+ * FILE_ASN1_TYPE_OCTET_STRING. In those cases, the indefinite length is used.
285
+ *
286
+ * @param String $encoded
287
+ * @param Integer $start
288
+ * @return Array
289
+ * @access private
290
+ */
291
+ function _decode_ber(&$encoded, $start = 0)
292
+ {
293
+ $decoded = array();
294
+
295
+ while ( strlen($encoded) ) {
296
+ $current = array('start' => $start);
297
+
298
+ $type = ord($this->_string_shift($encoded));
299
+ $start++;
300
+
301
+ $constructed = ($type >> 5) & 1;
302
+
303
+ $tag = $type & 0x1F;
304
+ if ($tag == 0x1F) {
305
+ $tag = 0;
306
+ // process septets (since the eighth bit is ignored, it's not an octet)
307
+ do {
308
+ $loop = ord($encoded[0]) >> 7;
309
+ $tag <<= 7;
310
+ $tag |= ord($this->_string_shift($encoded)) & 0x7F;
311
+ $start++;
312
+ } while ( $loop );
313
+ }
314
+
315
+ // Length, as discussed in paragraph 8.1.3 of X.690-0207.pdf#page=13
316
+ $length = ord($this->_string_shift($encoded));
317
+ $start++;
318
+ if ( $length == 0x80 ) { // indefinite length
319
+ // "[A sender shall] use the indefinite form (see 8.1.3.6) if the encoding is constructed and is not all
320
+ // immediately available." -- paragraph 8.1.3.2.c
321
+ //if ( !$constructed ) {
322
+ // return false;
323
+ //}
324
+ $length = strlen($encoded);
325
+ } elseif ( $length & 0x80 ) { // definite length, long form
326
+ // technically, the long form of the length can be represented by up to 126 octets (bytes), but we'll only
327
+ // support it up to four.
328
+ $length&= 0x7F;
329
+ $temp = $this->_string_shift($encoded, $length);
330
+ // tags of indefinite length don't really have a header length; this length includes the tag
331
+ $current+= array('headerlength' => $length + 2);
332
+ $start+= $length;
333
+ extract(unpack('Nlength', substr(str_pad($temp, 4, chr(0), STR_PAD_LEFT), -4)));
334
+ } else {
335
+ $current+= array('headerlength' => 2);
336
+ }
337
+
338
+ // End-of-content, see paragraphs 8.1.1.3, 8.1.3.2, 8.1.3.6, 8.1.5, and (for an example) 8.6.4.2
339
+ if (!$type && !$length) {
340
+ return $decoded;
341
+ }
342
+ $content = $this->_string_shift($encoded, $length);
343
+
344
+ /* Class is UNIVERSAL, APPLICATION, PRIVATE, or CONTEXT-SPECIFIC. The UNIVERSAL class is restricted to the ASN.1
345
+ built-in types. It defines an application-independent data type that must be distinguishable from all other
346
+ data types. The other three classes are user defined. The APPLICATION class distinguishes data types that
347
+ have a wide, scattered use within a particular presentation context. PRIVATE distinguishes data types within
348
+ a particular organization or country. CONTEXT-SPECIFIC distinguishes members of a sequence or set, the
349
+ alternatives of a CHOICE, or universally tagged set members. Only the class number appears in braces for this
350
+ data type; the term CONTEXT-SPECIFIC does not appear.
351
+
352
+ -- http://www.obj-sys.com/asn1tutorial/node12.html */
353
+ $class = ($type >> 6) & 3;
354
+ switch ($class) {
355
+ case FILE_ASN1_CLASS_APPLICATION:
356
+ case FILE_ASN1_CLASS_PRIVATE:
357
+ case FILE_ASN1_CLASS_CONTEXT_SPECIFIC:
358
+ $decoded[] = array(
359
+ 'type' => $class,
360
+ 'constant' => $tag,
361
+ 'content' => $constructed ? $this->_decode_ber($content, $start) : $content,
362
+ 'length' => $length + $start - $current['start']
363
+ ) + $current;
364
+ $start+= $length;
365
+ continue 2;
366
+ }
367
+
368
+ $current+= array('type' => $tag);
369
+
370
+ // decode UNIVERSAL tags
371
+ switch ($tag) {
372
+ case FILE_ASN1_TYPE_BOOLEAN:
373
+ // "The contents octets shall consist of a single octet." -- paragraph 8.2.1
374
+ //if (strlen($content) != 1) {
375
+ // return false;
376
+ //}
377
+ $current['content'] = (bool) ord($content[0]);
378
+ break;
379
+ case FILE_ASN1_TYPE_INTEGER:
380
+ case FILE_ASN1_TYPE_ENUMERATED:
381
+ $current['content'] = new Math_BigInteger($content, -256);
382
+ break;
383
+ case FILE_ASN1_TYPE_REAL: // not currently supported
384
+ return false;
385
+ case FILE_ASN1_TYPE_BIT_STRING:
386
+ // The initial octet shall encode, as an unsigned binary integer with bit 1 as the least significant bit,
387
+ // the number of unused bits in the final subsequent octet. The number shall be in the range zero to
388
+ // seven.
389
+ if (!$constructed) {
390
+ $current['content'] = $content;
391
+ } else {
392
+ $temp = $this->_decode_ber($content, $start);
393
+ $length-= strlen($content);
394
+ $last = count($temp) - 1;
395
+ for ($i = 0; $i < $last; $i++) {
396
+ // all subtags should be bit strings
397
+ //if ($temp[$i]['type'] != FILE_ASN1_TYPE_BIT_STRING) {
398
+ // return false;
399
+ //}
400
+ $current['content'].= substr($temp[$i]['content'], 1);
401
+ }
402
+ // all subtags should be bit strings
403
+ //if ($temp[$last]['type'] != FILE_ASN1_TYPE_BIT_STRING) {
404
+ // return false;
405
+ //}
406
+ $current['content'] = $temp[$last]['content'][0] . $current['content'] . substr($temp[$i]['content'], 1);
407
+ }
408
+ break;
409
+ case FILE_ASN1_TYPE_OCTET_STRING:
410
+ if (!$constructed) {
411
+ $current['content'] = $content;
412
+ } else {
413
+ $temp = $this->_decode_ber($content, $start);
414
+ $length-= strlen($content);
415
+ for ($i = 0, $size = count($temp); $i < $size; $i++) {
416
+ // all subtags should be octet strings
417
+ //if ($temp[$i]['type'] != FILE_ASN1_TYPE_OCTET_STRING) {
418
+ // return false;
419
+ //}
420
+ $current['content'].= $temp[$i]['content'];
421
+ }
422
+ // $length =
423
+ }
424
+ break;
425
+ case FILE_ASN1_TYPE_NULL:
426
+ // "The contents octets shall not contain any octets." -- paragraph 8.8.2
427
+ //if (strlen($content)) {
428
+ // return false;
429
+ //}
430
+ break;
431
+ case FILE_ASN1_TYPE_SEQUENCE:
432
+ case FILE_ASN1_TYPE_SET:
433
+ $current['content'] = $this->_decode_ber($content, $start);
434
+ break;
435
+ case FILE_ASN1_TYPE_OBJECT_IDENTIFIER:
436
+ $temp = ord($this->_string_shift($content));
437
+ $current['content'] = sprintf('%d.%d', floor($temp / 40), $temp % 40);
438
+ $valuen = 0;
439
+ // process septets
440
+ while (strlen($content)) {
441
+ $temp = ord($this->_string_shift($content));
442
+ $valuen <<= 7;
443
+ $valuen |= $temp & 0x7F;
444
+ if (~$temp & 0x80) {
445
+ $current['content'].= ".$valuen";
446
+ $valuen = 0;
447
+ }
448
+ }
449
+ // the eighth bit of the last byte should not be 1
450
+ //if ($temp >> 7) {
451
+ // return false;
452
+ //}
453
+ break;
454
+ /* Each character string type shall be encoded as if it had been declared:
455
+ [UNIVERSAL x] IMPLICIT OCTET STRING
456
+
457
+ -- X.690-0207.pdf#page=23 (paragraph 8.21.3)
458
+
459
+ Per that, we're not going to do any validation. If there are any illegal characters in the string,
460
+ we don't really care */
461
+ case FILE_ASN1_TYPE_NUMERIC_STRING:
462
+ // 0,1,2,3,4,5,6,7,8,9, and space
463
+ case FILE_ASN1_TYPE_PRINTABLE_STRING:
464
+ // Upper and lower case letters, digits, space, apostrophe, left/right parenthesis, plus sign, comma,
465
+ // hyphen, full stop, solidus, colon, equal sign, question mark
466
+ case FILE_ASN1_TYPE_TELETEX_STRING:
467
+ // The Teletex character set in CCITT's T61, space, and delete
468
+ // see http://en.wikipedia.org/wiki/Teletex#Character_sets
469
+ case FILE_ASN1_TYPE_VIDEOTEX_STRING:
470
+ // The Videotex character set in CCITT's T.100 and T.101, space, and delete
471
+ case FILE_ASN1_TYPE_VISIBLE_STRING:
472
+ // Printing character sets of international ASCII, and space
473
+ case FILE_ASN1_TYPE_IA5_STRING:
474
+ // International Alphabet 5 (International ASCII)
475
+ case FILE_ASN1_TYPE_GRAPHIC_STRING:
476
+ // All registered G sets, and space
477
+ case FILE_ASN1_TYPE_GENERAL_STRING:
478
+ // All registered C and G sets, space and delete
479
+ case FILE_ASN1_TYPE_UTF8_STRING:
480
+ // ????
481
+ case FILE_ASN1_TYPE_BMP_STRING:
482
+ $current['content'] = $content;
483
+ break;
484
+ case FILE_ASN1_TYPE_UTC_TIME:
485
+ case FILE_ASN1_TYPE_GENERALIZED_TIME:
486
+ $current['content'] = $this->_decodeTime($content, $tag);
487
+ default:
488
+
489
+ }
490
+
491
+ $start+= $length;
492
+ $decoded[] = $current + array('length' => $start - $current['start']);
493
+ }
494
+
495
+ return $decoded;
496
+ }
497
+
498
+ /**
499
+ * ASN.1 Decode
500
+ *
501
+ * Provides an ASN.1 semantic mapping ($mapping) from a parsed BER-encoding to a human readable format.
502
+ *
503
+ * @param Array $decoded
504
+ * @param Array $mapping
505
+ * @return Array
506
+ * @access public
507
+ */
508
+ function asn1map($decoded, $mapping)
509
+ {
510
+ if (isset($mapping['explicit'])) {
511
+ $decoded = $decoded['content'][0];
512
+ }
513
+
514
+ switch (true) {
515
+ case $mapping['type'] == FILE_ASN1_TYPE_ANY:
516
+ $intype = $decoded['type'];
517
+ if (isset($decoded['constant']) || !isset($this->ANYmap[$intype]) || ($this->encoded[$decoded['start']] & 0x20)) {
518
+ return new File_ASN1_Element(substr($this->encoded, $decoded['start'], $decoded['length']));
519
+ }
520
+ $inmap = $this->ANYmap[$intype];
521
+ if (is_string($inmap)) {
522
+ return array($inmap => $this->asn1map($decoded, array('type' => $intype) + $mapping));
523
+ }
524
+ break;
525
+ case $mapping['type'] == FILE_ASN1_TYPE_CHOICE:
526
+ foreach ($mapping['children'] as $key => $option) {
527
+ switch (true) {
528
+ case isset($option['constant']) && $option['constant'] == $decoded['constant']:
529
+ case !isset($option['constant']) && $option['type'] == $decoded['type']:
530
+ $value = $this->asn1map($decoded, $option);
531
+ break;
532
+ case !isset($option['constant']) && $option['type'] == FILE_ASN1_TYPE_CHOICE:
533
+ $v = $this->asn1map($decoded, $option);
534
+ if (isset($v)) {
535
+ $value = $v;
536
+ }
537
+ }
538
+ if (isset($value)) {
539
+ return array($key => $value);
540
+ }
541
+ }
542
+ return NULL;
543
+ case isset($mapping['implicit']):
544
+ case isset($mapping['explicit']):
545
+ case $decoded['type'] == $mapping['type']:
546
+ break;
547
+ default:
548
+ return NULL;
549
+ }
550
+
551
+ if (isset($mapping['implicit'])) {
552
+ $decoded['type'] = $mapping['type'];
553
+ }
554
+
555
+ switch ($decoded['type']) {
556
+ case FILE_ASN1_TYPE_SEQUENCE:
557
+ $map = array();
558
+
559
+ // ignore the min and max
560
+ if (isset($mapping['min']) && isset($mapping['max'])) {
561
+ $child = $mapping['children'];
562
+ foreach ($decoded['content'] as $content) {
563
+ if (($map[] = $this->asn1map($content, $child)) === NULL) {
564
+ return NULL;
565
+ }
566
+ }
567
+
568
+ return $map;
569
+ }
570
+
571
+ $n = count($decoded['content']);
572
+ $i = 0;
573
+
574
+ foreach ($mapping['children'] as $key => $child) {
575
+ $maymatch = $i < $n; // Match only existing input.
576
+ if ($maymatch) {
577
+ $temp = $decoded['content'][$i];
578
+
579
+ if ($child['type'] != FILE_ASN1_TYPE_CHOICE) {
580
+ // Get the mapping and input class & constant.
581
+ $childClass = $tempClass = FILE_ASN1_CLASS_UNIVERSAL;
582
+ $constant = NULL;
583
+ if (isset($temp['constant'])) {
584
+ $tempClass = isset($temp['class']) ? $temp['class'] : FILE_ASN1_CLASS_CONTEXT_SPECIFIC;
585
+ }
586
+ if (isset($child['class'])) {
587
+ $childClass = $child['class'];
588
+ $constant = $child['cast'];
589
+ }
590
+ elseif (isset($child['constant'])) {
591
+ $childClass = FILE_ASN1_CLASS_CONTEXT_SPECIFIC;
592
+ $constant = $child['constant'];
593
+ }
594
+
595
+ if (isset($constant) && isset($temp['constant'])) {
596
+ // Can only match if constants and class match.
597
+ $maymatch = $constant == $temp['constant'] && $childClass == $tempClass;
598
+ } else {
599
+ // Can only match if no constant expected and type matches or is generic.
600
+ $maymatch = !isset($child['constant']) && array_search($child['type'], array($temp['type'], FILE_ASN1_TYPE_ANY, FILE_ASN1_TYPE_CHOICE)) !== false;
601
+ }
602
+ }
603
+ }
604
+
605
+ if ($maymatch) {
606
+ // Attempt submapping.
607
+ $candidate = $this->asn1map($temp, $child);
608
+ $maymatch = $candidate !== NULL;
609
+ }
610
+
611
+ if ($maymatch) {
612
+ // Got the match: use it.
613
+ $map[$key] = $candidate;
614
+ $i++;
615
+ } elseif (isset($child['default'])) {
616
+ $map[$key] = $child['default']; // Use default.
617
+ } elseif (!isset($child['optional'])) {
618
+ return NULL; // Syntax error.
619
+ }
620
+ }
621
+
622
+ // Fail mapping if all input items have not been consumed.
623
+ return $i < $n? NULL: $map;
624
+
625
+ // the main diff between sets and sequences is the encapsulation of the foreach in another for loop
626
+ case FILE_ASN1_TYPE_SET:
627
+ $map = array();
628
+
629
+ // ignore the min and max
630
+ if (isset($mapping['min']) && isset($mapping['max'])) {
631
+ $child = $mapping['children'];
632
+ foreach ($decoded['content'] as $content) {
633
+ if (($map[] = $this->asn1map($content, $child)) === NULL) {
634
+ return NULL;
635
+ }
636
+ }
637
+
638
+ return $map;
639
+ }
640
+
641
+ for ($i = 0; $i < count($decoded['content']); $i++) {
642
+ $temp = $decoded['content'][$i];
643
+ $tempClass = FILE_ASN1_CLASS_UNIVERSAL;
644
+ if (isset($temp['constant'])) {
645
+ $tempClass = isset($temp['class']) ? $temp['class'] : FILE_ASN1_CLASS_CONTEXT_SPECIFIC;
646
+ }
647
+
648
+ foreach ($mapping['children'] as $key => $child) {
649
+ if (isset($map[$key])) {
650
+ continue;
651
+ }
652
+ $maymatch = true;
653
+ if ($child['type'] != FILE_ASN1_TYPE_CHOICE) {
654
+ $childClass = FILE_ASN1_CLASS_UNIVERSAL;
655
+ $constant = NULL;
656
+ if (isset($child['class'])) {
657
+ $childClass = $child['class'];
658
+ $constant = $child['cast'];
659
+ }
660
+ elseif (isset($child['constant'])) {
661
+ $childClass = FILE_ASN1_CLASS_CONTEXT_SPECIFIC;
662
+ $constant = $child['constant'];
663
+ }
664
+
665
+ if (isset($constant) && isset($temp['constant'])) {
666
+ // Can only match if constants and class match.
667
+ $maymatch = $constant == $temp['constant'] && $childClass == $tempClass;
668
+ } else {
669
+ // Can only match if no constant expected and type matches or is generic.
670
+ $maymatch = !isset($child['constant']) && array_search($child['type'], array($temp['type'], FILE_ASN1_TYPE_ANY, FILE_ASN1_TYPE_CHOICE)) !== false;
671
+ }
672
+ }
673
+
674
+ if ($maymatch) {
675
+ // Attempt submapping.
676
+ $candidate = $this->asn1map($temp, $child);
677
+ $maymatch = $candidate !== NULL;
678
+ }
679
+
680
+ if (!$maymatch) {
681
+ break;
682
+ }
683
+
684
+ // Got the match: use it.
685
+ $map[$key] = $candidate;
686
+ break;
687
+ }
688
+ }
689
+
690
+ foreach ($mapping['children'] as $key => $child) {
691
+ if (!isset($map[$key])) {
692
+ if (isset($child['default'])) {
693
+ $map[$key] = $child['default'];
694
+ } elseif (!isset($child['optional'])) {
695
+ return NULL;
696
+ }
697
+ }
698
+ }
699
+ return $map;
700
+ case FILE_ASN1_TYPE_OBJECT_IDENTIFIER:
701
+ return isset($this->oids[$decoded['content']]) ? $this->oids[$decoded['content']] : $decoded['content'];
702
+ case FILE_ASN1_TYPE_UTC_TIME:
703
+ case FILE_ASN1_TYPE_GENERALIZED_TIME:
704
+ if (isset($mapping['implicit'])) {
705
+ $decoded['content'] = $this->_decodeTime($decoded['content'], $decoded['type']);
706
+ }
707
+ return @date($this->format, $decoded['content']);
708
+ case FILE_ASN1_TYPE_BIT_STRING:
709
+ if (isset($mapping['mapping'])) {
710
+ $offset = ord($decoded['content'][0]);
711
+ $size = (strlen($decoded['content']) - 1) * 8 - $offset;
712
+ /*
713
+ From X.680-0207.pdf#page=46 (21.7):
714
+
715
+ "When a "NamedBitList" is used in defining a bitstring type ASN.1 encoding rules are free to add (or remove)
716
+ arbitrarily any trailing 0 bits to (or from) values that are being encoded or decoded. Application designers should
717
+ therefore ensure that different semantics are not associated with such values which differ only in the number of trailing
718
+ 0 bits."
719
+ */
720
+ $bits = count($mapping['mapping']) == $size ? array() : array_fill(0, count($mapping['mapping']) - $size, false);
721
+ for ($i = strlen($decoded['content']) - 1; $i > 0; $i--) {
722
+ $current = ord($decoded['content'][$i]);
723
+ for ($j = $offset; $j < 8; $j++) {
724
+ $bits[] = (bool) ($current & (1 << $j));
725
+ }
726
+ $offset = 0;
727
+ }
728
+ $values = array();
729
+ $map = array_reverse($mapping['mapping']);
730
+ foreach ($map as $i => $value) {
731
+ if ($bits[$i]) {
732
+ $values[] = $value;
733
+ }
734
+ }
735
+ return $values;
736
+ }
737
+ case FILE_ASN1_TYPE_OCTET_STRING:
738
+ return base64_encode($decoded['content']);
739
+ case FILE_ASN1_TYPE_NULL:
740
+ return '';
741
+ case FILE_ASN1_TYPE_BOOLEAN:
742
+ return $decoded['content'];
743
+ case FILE_ASN1_TYPE_NUMERIC_STRING:
744
+ case FILE_ASN1_TYPE_PRINTABLE_STRING:
745
+ case FILE_ASN1_TYPE_TELETEX_STRING:
746
+ case FILE_ASN1_TYPE_VIDEOTEX_STRING:
747
+ case FILE_ASN1_TYPE_IA5_STRING:
748
+ case FILE_ASN1_TYPE_GRAPHIC_STRING:
749
+ case FILE_ASN1_TYPE_VISIBLE_STRING:
750
+ case FILE_ASN1_TYPE_GENERAL_STRING:
751
+ case FILE_ASN1_TYPE_UNIVERSAL_STRING:
752
+ case FILE_ASN1_TYPE_UTF8_STRING:
753
+ case FILE_ASN1_TYPE_BMP_STRING:
754
+ return $decoded['content'];
755
+ case FILE_ASN1_TYPE_INTEGER:
756
+ case FILE_ASN1_TYPE_ENUMERATED:
757
+ $temp = $decoded['content'];
758
+ if (isset($mapping['implicit'])) {
759
+ $temp = new Math_BigInteger($decoded['content'], -256);
760
+ }
761
+ if (isset($mapping['mapping'])) {
762
+ $temp = (int) $temp->toString();
763
+ return isset($mapping['mapping'][$temp]) ?
764
+ $mapping['mapping'][$temp] :
765
+ false;
766
+ }
767
+ return $temp;
768
+ }
769
+ }
770
+
771
+ /**
772
+ * ASN.1 Encode
773
+ *
774
+ * DER-encodes an ASN.1 semantic mapping ($mapping). Some libraries would probably call this function
775
+ * an ASN.1 compiler.
776
+ *
777
+ * @param String $source
778
+ * @param String $mapping
779
+ * @param Integer $idx
780
+ * @return String
781
+ * @access public
782
+ */
783
+ function encodeDER($source, $mapping)
784
+ {
785
+ $this->location = array();
786
+ return $this->_encode_der($source, $mapping);
787
+ }
788
+
789
+ /**
790
+ * ASN.1 Encode (Helper function)
791
+ *
792
+ * @param String $source
793
+ * @param String $mapping
794
+ * @param Integer $idx
795
+ * @return String
796
+ * @access private
797
+ */
798
+ function _encode_der($source, $mapping, $idx = NULL)
799
+ {
800
+ if (is_object($source) && strtolower(get_class($source)) == 'file_asn1_element') {
801
+ return $source->element;
802
+ }
803
+
804
+ // do not encode (implicitly optional) fields with value set to default
805
+ if (isset($mapping['default']) && $source === $mapping['default']) {
806
+ return '';
807
+ }
808
+
809
+ if (isset($idx)) {
810
+ $this->location[] = $idx;
811
+ }
812
+
813
+ $tag = $mapping['type'];
814
+
815
+ switch ($tag) {
816
+ case FILE_ASN1_TYPE_SET: // Children order is not important, thus process in sequence.
817
+ case FILE_ASN1_TYPE_SEQUENCE:
818
+ $tag|= 0x20; // set the constructed bit
819
+ $value = '';
820
+
821
+ // ignore the min and max
822
+ if (isset($mapping['min']) && isset($mapping['max'])) {
823
+ $child = $mapping['children'];
824
+
825
+ foreach ($source as $content) {
826
+ $temp = $this->_encode_der($content, $child);
827
+ if ($temp === false) {
828
+ return false;
829
+ }
830
+ $value.= $temp;
831
+ }
832
+ break;
833
+ }
834
+
835
+ foreach ($mapping['children'] as $key => $child) {
836
+ if (!isset($source[$key])) {
837
+ if (!isset($child['optional'])) {
838
+ return false;
839
+ }
840
+ continue;
841
+ }
842
+
843
+ $temp = $this->_encode_der($source[$key], $child, $key);
844
+ if ($temp === false) {
845
+ return false;
846
+ }
847
+
848
+ // An empty child encoding means it has been optimized out.
849
+ // Else we should have at least one tag byte.
850
+ if ($temp === '') {
851
+ continue;
852
+ }
853
+
854
+ // if isset($child['constant']) is true then isset($child['optional']) should be true as well
855
+ if (isset($child['constant'])) {
856
+ /*
857
+ From X.680-0207.pdf#page=58 (30.6):
858
+
859
+ "The tagging construction specifies explicit tagging if any of the following holds:
860
+ ...
861
+ c) the "Tag Type" alternative is used and the value of "TagDefault" for the module is IMPLICIT TAGS or
862
+ AUTOMATIC TAGS, but the type defined by "Type" is an untagged choice type, an untagged open type, or
863
+ an untagged "DummyReference" (see ITU-T Rec. X.683 | ISO/IEC 8824-4, 8.3)."
864
+ */
865
+ if (isset($child['explicit']) || $child['type'] == FILE_ASN1_TYPE_CHOICE) {
866
+ $subtag = chr((FILE_ASN1_CLASS_CONTEXT_SPECIFIC << 6) | 0x20 | $child['constant']);
867
+ $temp = $subtag . $this->_encodeLength(strlen($temp)) . $temp;
868
+ } else {
869
+ $subtag = chr((FILE_ASN1_CLASS_CONTEXT_SPECIFIC << 6) | (ord($temp[0]) & 0x20) | $child['constant']);
870
+ $temp = $subtag . substr($temp, 1);
871
+ }
872
+ }
873
+ $value.= $temp;
874
+ }
875
+ break;
876
+ case FILE_ASN1_TYPE_CHOICE:
877
+ $temp = false;
878
+
879
+ foreach ($mapping['children'] as $key => $child) {
880
+ if (!isset($source[$key])) {
881
+ continue;
882
+ }
883
+
884
+ $temp = $this->_encode_der($source[$key], $child, $key);
885
+ if ($temp === false) {
886
+ return false;
887
+ }
888
+
889
+ // An empty child encoding means it has been optimized out.
890
+ // Else we should have at least one tag byte.
891
+ if ($temp === '') {
892
+ continue;
893
+ }
894
+
895
+ $tag = ord($temp[0]);
896
+
897
+ // if isset($child['constant']) is true then isset($child['optional']) should be true as well
898
+ if (isset($child['constant'])) {
899
+ if (isset($child['explicit']) || $child['type'] == FILE_ASN1_TYPE_CHOICE) {
900
+ $subtag = chr((FILE_ASN1_CLASS_CONTEXT_SPECIFIC << 6) | 0x20 | $child['constant']);
901
+ $temp = $subtag . $this->_encodeLength(strlen($temp)) . $temp;
902
+ } else {
903
+ $subtag = chr((FILE_ASN1_CLASS_CONTEXT_SPECIFIC << 6) | (ord($temp[0]) & 0x20) | $child['constant']);
904
+ $temp = $subtag . substr($temp, 1);
905
+ }
906
+ }
907
+ }
908
+
909
+ if (isset($idx)) {
910
+ array_pop($this->location);
911
+ }
912
+
913
+ if ($temp && isset($mapping['cast'])) {
914
+ $temp[0] = chr(($mapping['class'] << 6) | ($tag & 0x20) | $mapping['cast']);
915
+ }
916
+
917
+ return $temp;
918
+ case FILE_ASN1_TYPE_INTEGER:
919
+ case FILE_ASN1_TYPE_ENUMERATED:
920
+ if (!isset($mapping['mapping'])) {
921
+ $value = $source->toBytes(true);
922
+ } else {
923
+ $value = array_search($source, $mapping['mapping']);
924
+ if ($value === false) {
925
+ return false;
926
+ }
927
+ $value = new Math_BigInteger($value);
928
+ $value = $value->toBytes(true);
929
+ if (!strlen($value)) {
930
+ $value = chr(0);
931
+ }
932
+ }
933
+ break;
934
+ case FILE_ASN1_TYPE_UTC_TIME:
935
+ case FILE_ASN1_TYPE_GENERALIZED_TIME:
936
+ $format = $mapping['type'] == FILE_ASN1_TYPE_UTC_TIME ? 'y' : 'Y';
937
+ $format.= 'mdHis';
938
+ $value = @gmdate($format, strtotime($source)) . 'Z';
939
+ break;
940
+ case FILE_ASN1_TYPE_BIT_STRING:
941
+ if (isset($mapping['mapping'])) {
942
+ $bits = array_fill(0, count($mapping['mapping']), 0);
943
+ $size = 0;
944
+ for ($i = 0; $i < count($mapping['mapping']); $i++) {
945
+ if (in_array($mapping['mapping'][$i], $source)) {
946
+ $bits[$i] = 1;
947
+ $size = $i;
948
+ }
949
+ }
950
+
951
+ $offset = 8 - (($size + 1) & 7);
952
+ $offset = $offset !== 8 ? $offset : 0;
953
+
954
+ $value = chr($offset);
955
+
956
+ for ($i = $size + 1; $i < count($mapping['mapping']); $i++) {
957
+ unset($bits[$i]);
958
+ }
959
+
960
+ $bits = implode('', array_pad($bits, $size + $offset + 1, 0));
961
+ $bytes = explode(' ', rtrim(chunk_split($bits, 8, ' ')));
962
+ foreach ($bytes as $byte) {
963
+ $value.= chr(bindec($byte));
964
+ }
965
+
966
+ break;
967
+ }
968
+ case FILE_ASN1_TYPE_OCTET_STRING:
969
+ /* The initial octet shall encode, as an unsigned binary integer with bit 1 as the least significant bit,
970
+ the number of unused bits in the final subsequent octet. The number shall be in the range zero to seven.
971
+
972
+ -- http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#page=16 */
973
+ $value = base64_decode($source);
974
+ break;
975
+ case FILE_ASN1_TYPE_OBJECT_IDENTIFIER:
976
+ $oid = preg_match('#(?:\d+\.)+#', $source) ? $source : array_search($source, $this->oids);
977
+ if ($oid === false) {
978
+ user_error('Invalid OID');
979
+ return false;
980
+ }
981
+ $value = '';
982
+ $parts = explode('.', $oid);
983
+ $value = chr(40 * $parts[0] + $parts[1]);
984
+ for ($i = 2; $i < count($parts); $i++) {
985
+ $temp = '';
986
+ if (!$parts[$i]) {
987
+ $temp = "\0";
988
+ } else {
989
+ while ($parts[$i]) {
990
+ $temp = chr(0x80 | ($parts[$i] & 0x7F)) . $temp;
991
+ $parts[$i] >>= 7;
992
+ }
993
+ $temp[strlen($temp) - 1] = $temp[strlen($temp) - 1] & chr(0x7F);
994
+ }
995
+ $value.= $temp;
996
+ }
997
+ break;
998
+ case FILE_ASN1_TYPE_ANY:
999
+ $loc = $this->location;
1000
+ if (isset($idx)) {
1001
+ array_pop($this->location);
1002
+ }
1003
+
1004
+ switch (true) {
1005
+ case !isset($source):
1006
+ return $this->_encode_der(NULL, array('type' => FILE_ASN1_TYPE_NULL) + $mapping);
1007
+ case is_int($source):
1008
+ case is_object($source) && strtolower(get_class($source)) == 'math_biginteger':
1009
+ return $this->_encode_der($source, array('type' => FILE_ASN1_TYPE_INTEGER) + $mapping);
1010
+ case is_float($source):
1011
+ return $this->_encode_der($source, array('type' => FILE_ASN1_TYPE_REAL) + $mapping);
1012
+ case is_bool($source):
1013
+ return $this->_encode_der($source, array('type' => FILE_ASN1_TYPE_BOOLEAN) + $mapping);
1014
+ case is_array($source) && count($source) == 1:
1015
+ $typename = implode('', array_keys($source));
1016
+ $outtype = array_search($typename, $this->ANYmap, true);
1017
+ if ($outtype !== false) {
1018
+ return $this->_encode_der($source[$typename], array('type' => $outtype) + $mapping);
1019
+ }
1020
+ }
1021
+
1022
+ $filters = $this->filters;
1023
+ foreach ($loc as $part) {
1024
+ if (!isset($filters[$part])) {
1025
+ $filters = false;
1026
+ break;
1027
+ }
1028
+ $filters = $filters[$part];
1029
+ }
1030
+ if ($filters === false) {
1031
+ user_error('No filters defined for ' . implode('/', $loc));
1032
+ return false;
1033
+ }
1034
+ return $this->_encode_der($source, $filters + $mapping);
1035
+ case FILE_ASN1_TYPE_NULL:
1036
+ $value = '';
1037
+ break;
1038
+ case FILE_ASN1_TYPE_NUMERIC_STRING:
1039
+ case FILE_ASN1_TYPE_TELETEX_STRING:
1040
+ case FILE_ASN1_TYPE_PRINTABLE_STRING:
1041
+ case FILE_ASN1_TYPE_UNIVERSAL_STRING:
1042
+ case FILE_ASN1_TYPE_UTF8_STRING:
1043
+ case FILE_ASN1_TYPE_BMP_STRING:
1044
+ case FILE_ASN1_TYPE_IA5_STRING:
1045
+ case FILE_ASN1_TYPE_VISIBLE_STRING:
1046
+ case FILE_ASN1_TYPE_VIDEOTEX_STRING:
1047
+ case FILE_ASN1_TYPE_GRAPHIC_STRING:
1048
+ case FILE_ASN1_TYPE_GENERAL_STRING:
1049
+ $value = $source;
1050
+ break;
1051
+ case FILE_ASN1_TYPE_BOOLEAN:
1052
+ $value = $source ? "\xFF" : "\x00";
1053
+ break;
1054
+ default:
1055
+ user_error('Mapping provides no type definition for ' . implode('/', $this->location));
1056
+ return false;
1057
+ }
1058
+
1059
+ if (isset($idx)) {
1060
+ array_pop($this->location);
1061
+ }
1062
+
1063
+ if (isset($mapping['cast'])) {
1064
+ $tag = ($mapping['class'] << 6) | ($tag & 0x20) | $mapping['cast'];
1065
+ }
1066
+
1067
+ return chr($tag) . $this->_encodeLength(strlen($value)) . $value;
1068
+ }
1069
+
1070
+ /**
1071
+ * DER-encode the length
1072
+ *
1073
+ * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See
1074
+ * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information.
1075
+ *
1076
+ * @access private
1077
+ * @param Integer $length
1078
+ * @return String
1079
+ */
1080
+ function _encodeLength($length)
1081
+ {
1082
+ if ($length <= 0x7F) {
1083
+ return chr($length);
1084
+ }
1085
+
1086
+ $temp = ltrim(pack('N', $length), chr(0));
1087
+ return pack('Ca*', 0x80 | strlen($temp), $temp);
1088
+ }
1089
+
1090
+ /**
1091
+ * BER-decode the time
1092
+ *
1093
+ * Called by _decode_ber() and in the case of implicit tags asn1map().
1094
+ *
1095
+ * @access private
1096
+ * @param String $content
1097
+ * @param Integer $tag
1098
+ * @return String
1099
+ */
1100
+ function _decodeTime($content, $tag)
1101
+ {
1102
+ /* UTCTime:
1103
+ http://tools.ietf.org/html/rfc5280#section-4.1.2.5.1
1104
+ http://www.obj-sys.com/asn1tutorial/node15.html
1105
+
1106
+ GeneralizedTime:
1107
+ http://tools.ietf.org/html/rfc5280#section-4.1.2.5.2
1108
+ http://www.obj-sys.com/asn1tutorial/node14.html */
1109
+
1110
+ $pattern = $tag == FILE_ASN1_TYPE_UTC_TIME ?
1111
+ '#(..)(..)(..)(..)(..)(..)(.*)#' :
1112
+ '#(....)(..)(..)(..)(..)(..).*([Z+-].*)$#';
1113
+
1114
+ preg_match($pattern, $content, $matches);
1115
+
1116
+ list(, $year, $month, $day, $hour, $minute, $second, $timezone) = $matches;
1117
+
1118
+ if ($tag == FILE_ASN1_TYPE_UTC_TIME) {
1119
+ $year = $year >= 50 ? "19$year" : "20$year";
1120
+ }
1121
+
1122
+ if ($timezone == 'Z') {
1123
+ $mktime = 'gmmktime';
1124
+ $timezone = 0;
1125
+ } elseif (preg_match('#([+-])(\d\d)(\d\d)#', $timezone, $matches)) {
1126
+ $mktime = 'gmmktime';
1127
+ $timezone = 60 * $matches[3] + 3600 * $matches[2];
1128
+ if ($matches[1] == '-') {
1129
+ $timezone = -$timezone;
1130
+ }
1131
+ } else {
1132
+ $mktime = 'mktime';
1133
+ $timezone = 0;
1134
+ }
1135
+
1136
+ return @$mktime($hour, $minute, $second, $month, $day, $year) + $timezone;
1137
+ }
1138
+
1139
+ /**
1140
+ * Set the time format
1141
+ *
1142
+ * Sets the time / date format for asn1map().
1143
+ *
1144
+ * @access public
1145
+ * @param String $format
1146
+ */
1147
+ function setTimeFormat($format)
1148
+ {
1149
+ $this->format = $format;
1150
+ }
1151
+
1152
+ /**
1153
+ * Load OIDs
1154
+ *
1155
+ * Load the relevant OIDs for a particular ASN.1 semantic mapping.
1156
+ *
1157
+ * @access public
1158
+ * @param Array $oids
1159
+ */
1160
+ function loadOIDs($oids)
1161
+ {
1162
+ $this->oids = $oids;
1163
+ }
1164
+
1165
+ /**
1166
+ * Load filters
1167
+ *
1168
+ * See File_X509, etc, for an example.
1169
+ *
1170
+ * @access public
1171
+ * @param Array $filters
1172
+ */
1173
+ function loadFilters($filters)
1174
+ {
1175
+ $this->filters = $filters;
1176
+ }
1177
+
1178
+ /**
1179
+ * String Shift
1180
+ *
1181
+ * Inspired by array_shift
1182
+ *
1183
+ * @param String $string
1184
+ * @param optional Integer $index
1185
+ * @return String
1186
+ * @access private
1187
+ */
1188
+ function _string_shift(&$string, $index = 1)
1189
+ {
1190
+ $substr = substr($string, 0, $index);
1191
+ $string = substr($string, $index);
1192
+ return $substr;
1193
+ }
1194
+
1195
+ /**
1196
+ * String type conversion
1197
+ *
1198
+ * This is a lazy conversion, dealing only with character size.
1199
+ * No real conversion table is used.
1200
+ *
1201
+ * @param String $in
1202
+ * @param optional Integer $from
1203
+ * @param optional Integer $to
1204
+ * @return String
1205
+ * @access public
1206
+ */
1207
+ function convert($in, $from = FILE_ASN1_TYPE_UTF8_STRING, $to = FILE_ASN1_TYPE_UTF8_STRING)
1208
+ {
1209
+ if (!isset($this->stringTypeSize[$from]) || !isset($this->stringTypeSize[$to])) {
1210
+ return false;
1211
+ }
1212
+ $insize = $this->stringTypeSize[$from];
1213
+ $outsize = $this->stringTypeSize[$to];
1214
+ $inlength = strlen($in);
1215
+ $out = '';
1216
+
1217
+ for ($i = 0; $i < $inlength;) {
1218
+ if ($inlength - $i < $insize) {
1219
+ return false;
1220
+ }
1221
+
1222
+ // Get an input character as a 32-bit value.
1223
+ $c = ord($in[$i++]);
1224
+ switch (true) {
1225
+ case $insize == 4:
1226
+ $c = ($c << 8) | ord($in[$i++]);
1227
+ $c = ($c << 8) | ord($in[$i++]);
1228
+ case $insize == 2:
1229
+ $c = ($c << 8) | ord($in[$i++]);
1230
+ case $insize == 1:
1231
+ break;
1232
+ case ($c & 0x80) == 0x00:
1233
+ break;
1234
+ case ($c & 0x40) == 0x00:
1235
+ return false;
1236
+ default:
1237
+ $bit = 6;
1238
+ do {
1239
+ if ($bit > 25 || $i >= $inlength || (ord($in[$i]) & 0xC0) != 0x80) {
1240
+ return false;
1241
+ }
1242
+ $c = ($c << 6) | (ord($in[$i++]) & 0x3F);
1243
+ $bit += 5;
1244
+ $mask = 1 << $bit;
1245
+ } while ($c & $bit);
1246
+ $c &= $mask - 1;
1247
+ break;
1248
+ }
1249
+
1250
+ // Convert and append the character to output string.
1251
+ $v = '';
1252
+ switch (true) {
1253
+ case $outsize == 4:
1254
+ $v .= chr($c & 0xFF);
1255
+ $c >>= 8;
1256
+ $v .= chr($c & 0xFF);
1257
+ $c >>= 8;
1258
+ case $outsize == 2:
1259
+ $v .= chr($c & 0xFF);
1260
+ $c >>= 8;
1261
+ case $outsize == 1:
1262
+ $v .= chr($c & 0xFF);
1263
+ $c >>= 8;
1264
+ if ($c) {
1265
+ return false;
1266
+ }
1267
+ break;
1268
+ case ($c & 0x80000000) != 0:
1269
+ return false;
1270
+ case $c >= 0x04000000:
1271
+ $v .= chr(0x80 | ($c & 0x3F));
1272
+ $c = ($c >> 6) | 0x04000000;
1273
+ case $c >= 0x00200000:
1274
+ $v .= chr(0x80 | ($c & 0x3F));
1275
+ $c = ($c >> 6) | 0x00200000;
1276
+ case $c >= 0x00010000:
1277
+ $v .= chr(0x80 | ($c & 0x3F));
1278
+ $c = ($c >> 6) | 0x00010000;
1279
+ case $c >= 0x00000800:
1280
+ $v .= chr(0x80 | ($c & 0x3F));
1281
+ $c = ($c >> 6) | 0x00000800;
1282
+ case $c >= 0x00000080:
1283
+ $v .= chr(0x80 | ($c & 0x3F));
1284
+ $c = ($c >> 6) | 0x000000C0;
1285
+ default:
1286
+ $v .= chr($c);
1287
+ break;
1288
+ }
1289
+ $out .= strrev($v);
1290
+ }
1291
+ return $out;
1292
+ }
1293
+ }
modules/phpseclib/File/X509.php ADDED
@@ -0,0 +1,4351 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3
+
4
+ /**
5
+ * Pure-PHP X.509 Parser
6
+ *
7
+ * PHP versions 4 and 5
8
+ *
9
+ * Encode and decode X.509 certificates.
10
+ *
11
+ * The extensions are from {@link http://tools.ietf.org/html/rfc5280 RFC5280} and
12
+ * {@link http://web.archive.org/web/19961027104704/http://www3.netscape.com/eng/security/cert-exts.html Netscape Certificate Extensions}.
13
+ *
14
+ * Note that loading an X.509 certificate and resaving it may invalidate the signature. The reason being that the signature is based on a
15
+ * portion of the certificate that contains optional parameters with default values. ie. if the parameter isn't there the default value is
16
+ * used. Problem is, if the parameter is there and it just so happens to have the default value there are two ways that that parameter can
17
+ * be encoded. It can be encoded explicitly or left out all together. This would effect the signature value and thus may invalidate the
18
+ * the certificate all together unless the certificate is re-signed.
19
+ *
20
+ * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
21
+ * of this software and associated documentation files (the "Software"), to deal
22
+ * in the Software without restriction, including without limitation the rights
23
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
24
+ * copies of the Software, and to permit persons to whom the Software is
25
+ * furnished to do so, subject to the following conditions:
26
+ *
27
+ * The above copyright notice and this permission notice shall be included in
28
+ * all copies or substantial portions of the Software.
29
+ *
30
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
31
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
32
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
33
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
34
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
35
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
36
+ * THE SOFTWARE.
37
+ *
38
+ * @category File
39
+ * @package File_X509
40
+ * @author Jim Wigginton <terrafrost@php.net>
41
+ * @copyright MMXII Jim Wigginton
42
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
43
+ * @link http://phpseclib.sourceforge.net
44
+ */
45
+
46
+ /**
47
+ * Include File_ASN1
48
+ */
49
+ if (!class_exists('File_ASN1')) {
50
+ require_once('ASN1.php');
51
+ }
52
+
53
+ /**
54
+ * Flag to only accept signatures signed by certificate authorities
55
+ *
56
+ * Not really used anymore but retained all the same to suppress E_NOTICEs from old installs
57
+ *
58
+ * @access public
59
+ */
60
+ define('FILE_X509_VALIDATE_SIGNATURE_BY_CA', 1);
61
+
62
+ /**#@+
63
+ * @access public
64
+ * @see File_X509::getDN()
65
+ */
66
+ /**
67
+ * Return internal array representation
68
+ */
69
+ define('FILE_X509_DN_ARRAY', 0);
70
+ /**
71
+ * Return string
72
+ */
73
+ define('FILE_X509_DN_STRING', 1);
74
+ /**
75
+ * Return ASN.1 name string
76
+ */
77
+ define('FILE_X509_DN_ASN1', 2);
78
+ /**
79
+ * Return OpenSSL compatible array
80
+ */
81
+ define('FILE_X509_DN_OPENSSL', 3);
82
+ /**
83
+ * Return canonical ASN.1 RDNs string
84
+ */
85
+ define('FILE_X509_DN_CANON', 4);
86
+ /**
87
+ * Return name hash for file indexing
88
+ */
89
+ define('FILE_X509_DN_HASH', 5);
90
+ /**#@-*/
91
+
92
+ /**#@+
93
+ * @access public
94
+ * @see File_X509::saveX509()
95
+ * @see File_X509::saveCSR()
96
+ * @see File_X509::saveCRL()
97
+ */
98
+ /**
99
+ * Save as PEM
100
+ *
101
+ * ie. a base64-encoded PEM with a header and a footer
102
+ */
103
+ define('FILE_X509_FORMAT_PEM', 0);
104
+ /**
105
+ * Save as DER
106
+ */
107
+ define('FILE_X509_FORMAT_DER', 1);
108
+ /**
109
+ * Save as a SPKAC
110
+ *
111
+ * Only works on CSRs. Not currently supported.
112
+ */
113
+ define('FILE_X509_FORMAT_SPKAC', 2);
114
+ /**#@-*/
115
+
116
+ /**
117
+ * Attribute value disposition.
118
+ * If disposition is >= 0, this is the index of the target value.
119
+ */
120
+ define('FILE_X509_ATTR_ALL', -1); // All attribute values (array).
121
+ define('FILE_X509_ATTR_APPEND', -2); // Add a value.
122
+ define('FILE_X509_ATTR_REPLACE', -3); // Clear first, then add a value.
123
+
124
+ /**
125
+ * Pure-PHP X.509 Parser
126
+ *
127
+ * @author Jim Wigginton <terrafrost@php.net>
128
+ * @version 0.3.1
129
+ * @access public
130
+ * @package File_X509
131
+ */
132
+ class File_X509 {
133
+ /**
134
+ * ASN.1 syntax for X.509 certificates
135
+ *
136
+ * @var Array
137
+ * @access private
138
+ */
139
+ var $Certificate;
140
+
141
+ /**#@+
142
+ * ASN.1 syntax for various extensions
143
+ *
144
+ * @access private
145
+ */
146
+ var $DirectoryString;
147
+ var $PKCS9String;
148
+ var $AttributeValue;
149
+ var $Extensions;
150
+ var $KeyUsage;
151
+ var $ExtKeyUsageSyntax;
152
+ var $BasicConstraints;
153
+ var $KeyIdentifier;
154
+ var $CRLDistributionPoints;
155
+ var $AuthorityKeyIdentifier;
156
+ var $CertificatePolicies;
157
+ var $AuthorityInfoAccessSyntax;
158
+ var $SubjectAltName;
159
+ var $PrivateKeyUsagePeriod;
160
+ var $IssuerAltName;
161
+ var $PolicyMappings;
162
+ var $NameConstraints;
163
+
164
+ var $CPSuri;
165
+ var $UserNotice;
166
+
167
+ var $netscape_cert_type;
168
+ var $netscape_comment;
169
+ var $netscape_ca_policy_url;
170
+
171
+ var $Name;
172
+ var $RelativeDistinguishedName;
173
+ var $CRLNumber;
174
+ var $CRLReason;
175
+ var $IssuingDistributionPoint;
176
+ var $InvalidityDate;
177
+ var $CertificateIssuer;
178
+ var $HoldInstructionCode;
179
+ var $SignedPublicKeyAndChallenge;
180
+ /**#@-*/
181
+
182
+ /**
183
+ * ASN.1 syntax for Certificate Signing Requests (RFC2986)
184
+ *
185
+ * @var Array
186
+ * @access private
187
+ */
188
+ var $CertificationRequest;
189
+
190
+ /**
191
+ * ASN.1 syntax for Certificate Revocation Lists (RFC5280)
192
+ *
193
+ * @var Array
194
+ * @access private
195
+ */
196
+ var $CertificateList;
197
+
198
+ /**
199
+ * Distinguished Name
200
+ *
201
+ * @var Array
202
+ * @access private
203
+ */
204
+ var $dn;
205
+
206
+ /**
207
+ * Public key
208
+ *
209
+ * @var String
210
+ * @access private
211
+ */
212
+ var $publicKey;
213
+
214
+ /**
215
+ * Private key
216
+ *
217
+ * @var String
218
+ * @access private
219
+ */
220
+ var $privateKey;
221
+
222
+ /**
223
+ * Object identifiers for X.509 certificates
224
+ *
225
+ * @var Array
226
+ * @access private
227
+ * @link http://en.wikipedia.org/wiki/Object_identifier
228
+ */
229
+ var $oids;
230
+
231
+ /**
232
+ * The certificate authorities
233
+ *
234
+ * @var Array
235
+ * @access private
236
+ */
237
+ var $CAs;
238
+
239
+ /**
240
+ * The currently loaded certificate
241
+ *
242
+ * @var Array
243
+ * @access private
244
+ */
245
+ var $currentCert;
246
+
247
+ /**
248
+ * The signature subject
249
+ *
250
+ * There's no guarantee File_X509 is going to reencode an X.509 cert in the same way it was originally
251
+ * encoded so we take save the portion of the original cert that the signature would have made for.
252
+ *
253
+ * @var String
254
+ * @access private
255
+ */
256
+ var $signatureSubject;
257
+
258
+ /**
259
+ * Certificate Start Date
260
+ *
261
+ * @var String
262
+ * @access private
263
+ */
264
+ var $startDate;
265
+
266
+ /**
267
+ * Certificate End Date
268
+ *
269
+ * @var String
270
+ * @access private
271
+ */
272
+ var $endDate;
273
+
274
+ /**
275
+ * Serial Number
276
+ *
277
+ * @var String
278
+ * @access private
279
+ */
280
+ var $serialNumber;
281
+
282
+ /**
283
+ * Key Identifier
284
+ *
285
+ * See {@link http://tools.ietf.org/html/rfc5280#section-4.2.1.1 RFC5280#section-4.2.1.1} and
286
+ * {@link http://tools.ietf.org/html/rfc5280#section-4.2.1.2 RFC5280#section-4.2.1.2}.
287
+ *
288
+ * @var String
289
+ * @access private
290
+ */
291
+ var $currentKeyIdentifier;
292
+
293
+ /**
294
+ * CA Flag
295
+ *
296
+ * @var Boolean
297
+ * @access private
298
+ */
299
+ var $caFlag = false;
300
+
301
+ /**
302
+ * Default Constructor.
303
+ *
304
+ * @return File_X509
305
+ * @access public
306
+ */
307
+ function File_X509()
308
+ {
309
+ // Explicitly Tagged Module, 1988 Syntax
310
+ // http://tools.ietf.org/html/rfc5280#appendix-A.1
311
+
312
+ $this->DirectoryString = array(
313
+ 'type' => FILE_ASN1_TYPE_CHOICE,
314
+ 'children' => array(
315
+ 'teletexString' => array('type' => FILE_ASN1_TYPE_TELETEX_STRING),
316
+ 'printableString' => array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING),
317
+ 'universalString' => array('type' => FILE_ASN1_TYPE_UNIVERSAL_STRING),
318
+ 'utf8String' => array('type' => FILE_ASN1_TYPE_UTF8_STRING),
319
+ 'bmpString' => array('type' => FILE_ASN1_TYPE_BMP_STRING)
320
+ )
321
+ );
322
+
323
+ $this->PKCS9String = array(
324
+ 'type' => FILE_ASN1_TYPE_CHOICE,
325
+ 'children' => array(
326
+ 'ia5String' => array('type' => FILE_ASN1_TYPE_IA5_STRING),
327
+ 'directoryString' => $this->DirectoryString
328
+ )
329
+ );
330
+
331
+ $this->AttributeValue = array('type' => FILE_ASN1_TYPE_ANY);
332
+
333
+ $AttributeType = array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER);
334
+
335
+ $AttributeTypeAndValue = array(
336
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
337
+ 'children' => array(
338
+ 'type' => $AttributeType,
339
+ 'value'=> $this->AttributeValue
340
+ )
341
+ );
342
+
343
+ /*
344
+ In practice, RDNs containing multiple name-value pairs (called "multivalued RDNs") are rare,
345
+ but they can be useful at times when either there is no unique attribute in the entry or you
346
+ want to ensure that the entry's DN contains some useful identifying information.
347
+
348
+ - https://www.opends.org/wiki/page/DefinitionRelativeDistinguishedName
349
+ */
350
+ $this->RelativeDistinguishedName = array(
351
+ 'type' => FILE_ASN1_TYPE_SET,
352
+ 'min' => 1,
353
+ 'max' => -1,
354
+ 'children' => $AttributeTypeAndValue
355
+ );
356
+
357
+ // http://tools.ietf.org/html/rfc5280#section-4.1.2.4
358
+ $RDNSequence = array(
359
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
360
+ // RDNSequence does not define a min or a max, which means it doesn't have one
361
+ 'min' => 0,
362
+ 'max' => -1,
363
+ 'children' => $this->RelativeDistinguishedName
364
+ );
365
+
366
+ $this->Name = array(
367
+ 'type' => FILE_ASN1_TYPE_CHOICE,
368
+ 'children' => array(
369
+ 'rdnSequence' => $RDNSequence
370
+ )
371
+ );
372
+
373
+ // http://tools.ietf.org/html/rfc5280#section-4.1.1.2
374
+ $AlgorithmIdentifier = array(
375
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
376
+ 'children' => array(
377
+ 'algorithm' => array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER),
378
+ 'parameters' => array(
379
+ 'type' => FILE_ASN1_TYPE_ANY,
380
+ 'optional' => true
381
+ )
382
+ )
383
+ );
384
+
385
+ /*
386
+ A certificate using system MUST reject the certificate if it encounters
387
+ a critical extension it does not recognize; however, a non-critical
388
+ extension may be ignored if it is not recognized.
389
+
390
+ http://tools.ietf.org/html/rfc5280#section-4.2
391
+ */
392
+ $Extension = array(
393
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
394
+ 'children' => array(
395
+ 'extnId' => array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER),
396
+ 'critical' => array(
397
+ 'type' => FILE_ASN1_TYPE_BOOLEAN,
398
+ 'optional' => true,
399
+ 'default' => false
400
+ ),
401
+ 'extnValue' => array('type' => FILE_ASN1_TYPE_OCTET_STRING)
402
+ )
403
+ );
404
+
405
+ $this->Extensions = array(
406
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
407
+ 'min' => 1,
408
+ // technically, it's MAX, but we'll assume anything < 0 is MAX
409
+ 'max' => -1,
410
+ // if 'children' isn't an array then 'min' and 'max' must be defined
411
+ 'children' => $Extension
412
+ );
413
+
414
+ $SubjectPublicKeyInfo = array(
415
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
416
+ 'children' => array(
417
+ 'algorithm' => $AlgorithmIdentifier,
418
+ 'subjectPublicKey' => array('type' => FILE_ASN1_TYPE_BIT_STRING)
419
+ )
420
+ );
421
+
422
+ $UniqueIdentifier = array('type' => FILE_ASN1_TYPE_BIT_STRING);
423
+
424
+ $Time = array(
425
+ 'type' => FILE_ASN1_TYPE_CHOICE,
426
+ 'children' => array(
427
+ 'utcTime' => array('type' => FILE_ASN1_TYPE_UTC_TIME),
428
+ 'generalTime' => array('type' => FILE_ASN1_TYPE_GENERALIZED_TIME)
429
+ )
430
+ );
431
+
432
+ // http://tools.ietf.org/html/rfc5280#section-4.1.2.5
433
+ $Validity = array(
434
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
435
+ 'children' => array(
436
+ 'notBefore' => $Time,
437
+ 'notAfter' => $Time
438
+ )
439
+ );
440
+
441
+ $CertificateSerialNumber = array('type' => FILE_ASN1_TYPE_INTEGER);
442
+
443
+ $Version = array(
444
+ 'type' => FILE_ASN1_TYPE_INTEGER,
445
+ 'mapping' => array('v1', 'v2', 'v3')
446
+ );
447
+
448
+ // assert($TBSCertificate['children']['signature'] == $Certificate['children']['signatureAlgorithm'])
449
+ $TBSCertificate = array(
450
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
451
+ 'children' => array(
452
+ // technically, default implies optional, but we'll define it as being optional, none-the-less, just to
453
+ // reenforce that fact
454
+ 'version' => array(
455
+ 'constant' => 0,
456
+ 'optional' => true,
457
+ 'explicit' => true,
458
+ 'default' => 'v1'
459
+ ) + $Version,
460
+ 'serialNumber' => $CertificateSerialNumber,
461
+ 'signature' => $AlgorithmIdentifier,
462
+ 'issuer' => $this->Name,
463
+ 'validity' => $Validity,
464
+ 'subject' => $this->Name,
465
+ 'subjectPublicKeyInfo' => $SubjectPublicKeyInfo,
466
+ // implicit means that the T in the TLV structure is to be rewritten, regardless of the type
467
+ 'issuerUniqueID' => array(
468
+ 'constant' => 1,
469
+ 'optional' => true,
470
+ 'implicit' => true
471
+ ) + $UniqueIdentifier,
472
+ 'subjectUniqueID' => array(
473
+ 'constant' => 2,
474
+ 'optional' => true,
475
+ 'implicit' => true
476
+ ) + $UniqueIdentifier,
477
+ // <http://tools.ietf.org/html/rfc2459#page-74> doesn't use the EXPLICIT keyword but if
478
+ // it's not IMPLICIT, it's EXPLICIT
479
+ 'extensions' => array(
480
+ 'constant' => 3,
481
+ 'optional' => true,
482
+ 'explicit' => true
483
+ ) + $this->Extensions
484
+ )
485
+ );
486
+
487
+ $this->Certificate = array(
488
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
489
+ 'children' => array(
490
+ 'tbsCertificate' => $TBSCertificate,
491
+ 'signatureAlgorithm' => $AlgorithmIdentifier,
492
+ 'signature' => array('type' => FILE_ASN1_TYPE_BIT_STRING)
493
+ )
494
+ );
495
+
496
+ $this->KeyUsage = array(
497
+ 'type' => FILE_ASN1_TYPE_BIT_STRING,
498
+ 'mapping' => array(
499
+ 'digitalSignature',
500
+ 'nonRepudiation',
501
+ 'keyEncipherment',
502
+ 'dataEncipherment',
503
+ 'keyAgreement',
504
+ 'keyCertSign',
505
+ 'cRLSign',
506
+ 'encipherOnly',
507
+ 'decipherOnly'
508
+ )
509
+ );
510
+
511
+ $this->BasicConstraints = array(
512
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
513
+ 'children' => array(
514
+ 'cA' => array(
515
+ 'type' => FILE_ASN1_TYPE_BOOLEAN,
516
+ 'optional' => true,
517
+ 'default' => false
518
+ ),
519
+ 'pathLenConstraint' => array(
520
+ 'type' => FILE_ASN1_TYPE_INTEGER,
521
+ 'optional' => true
522
+ )
523
+ )
524
+ );
525
+
526
+ $this->KeyIdentifier = array('type' => FILE_ASN1_TYPE_OCTET_STRING);
527
+
528
+ $OrganizationalUnitNames = array(
529
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
530
+ 'min' => 1,
531
+ 'max' => 4, // ub-organizational-units
532
+ 'children' => array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING)
533
+ );
534
+
535
+ $PersonalName = array(
536
+ 'type' => FILE_ASN1_TYPE_SET,
537
+ 'children' => array(
538
+ 'surname' => array(
539
+ 'type' => FILE_ASN1_TYPE_PRINTABLE_STRING,
540
+ 'constant' => 0,
541
+ 'optional' => true,
542
+ 'implicit' => true
543
+ ),
544
+ 'given-name' => array(
545
+ 'type' => FILE_ASN1_TYPE_PRINTABLE_STRING,
546
+ 'constant' => 1,
547
+ 'optional' => true,
548
+ 'implicit' => true
549
+ ),
550
+ 'initials' => array(
551
+ 'type' => FILE_ASN1_TYPE_PRINTABLE_STRING,
552
+ 'constant' => 2,
553
+ 'optional' => true,
554
+ 'implicit' => true
555
+ ),
556
+ 'generation-qualifier' => array(
557
+ 'type' => FILE_ASN1_TYPE_PRINTABLE_STRING,
558
+ 'constant' => 3,
559
+ 'optional' => true,
560
+ 'implicit' => true
561
+ )
562
+ )
563
+ );
564
+
565
+ $NumericUserIdentifier = array('type' => FILE_ASN1_TYPE_NUMERIC_STRING);
566
+
567
+ $OrganizationName = array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING);
568
+
569
+ $PrivateDomainName = array(
570
+ 'type' => FILE_ASN1_TYPE_CHOICE,
571
+ 'children' => array(
572
+ 'numeric' => array('type' => FILE_ASN1_TYPE_NUMERIC_STRING),
573
+ 'printable' => array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING)
574
+ )
575
+ );
576
+
577
+ $TerminalIdentifier = array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING);
578
+
579
+ $NetworkAddress = array('type' => FILE_ASN1_TYPE_NUMERIC_STRING);
580
+
581
+ $AdministrationDomainName = array(
582
+ 'type' => FILE_ASN1_TYPE_CHOICE,
583
+ // if class isn't present it's assumed to be FILE_ASN1_CLASS_UNIVERSAL or
584
+ // (if constant is present) FILE_ASN1_CLASS_CONTEXT_SPECIFIC
585
+ 'class' => FILE_ASN1_CLASS_APPLICATION,
586
+ 'cast' => 2,
587
+ 'children' => array(
588
+ 'numeric' => array('type' => FILE_ASN1_TYPE_NUMERIC_STRING),
589
+ 'printable' => array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING)
590
+ )
591
+ );
592
+
593
+ $CountryName = array(
594
+ 'type' => FILE_ASN1_TYPE_CHOICE,
595
+ // if class isn't present it's assumed to be FILE_ASN1_CLASS_UNIVERSAL or
596
+ // (if constant is present) FILE_ASN1_CLASS_CONTEXT_SPECIFIC
597
+ 'class' => FILE_ASN1_CLASS_APPLICATION,
598
+ 'cast' => 1,
599
+ 'children' => array(
600
+ 'x121-dcc-code' => array('type' => FILE_ASN1_TYPE_NUMERIC_STRING),
601
+ 'iso-3166-alpha2-code' => array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING)
602
+ )
603
+ );
604
+
605
+ $AnotherName = array(
606
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
607
+ 'children' => array(
608
+ 'type-id' => array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER),
609
+ 'value' => array(
610
+ 'type' => FILE_ASN1_TYPE_ANY,
611
+ 'constant' => 0,
612
+ 'optional' => true,
613
+ 'explicit' => true
614
+ )
615
+ )
616
+ );
617
+
618
+ $ExtensionAttribute = array(
619
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
620
+ 'children' => array(
621
+ 'extension-attribute-type' => array(
622
+ 'type' => FILE_ASN1_TYPE_PRINTABLE_STRING,
623
+ 'constant' => 0,
624
+ 'optional' => true,
625
+ 'implicit' => true
626
+ ),
627
+ 'extension-attribute-value' => array(
628
+ 'type' => FILE_ASN1_TYPE_ANY,
629
+ 'constant' => 1,
630
+ 'optional' => true,
631
+ 'explicit' => true
632
+ )
633
+ )
634
+ );
635
+
636
+ $ExtensionAttributes = array(
637
+ 'type' => FILE_ASN1_TYPE_SET,
638
+ 'min' => 1,
639
+ 'max' => 256, // ub-extension-attributes
640
+ 'children' => $ExtensionAttribute
641
+ );
642
+
643
+ $BuiltInDomainDefinedAttribute = array(
644
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
645
+ 'children' => array(
646
+ 'type' => array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING),
647
+ 'value' => array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING)
648
+ )
649
+ );
650
+
651
+ $BuiltInDomainDefinedAttributes = array(
652
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
653
+ 'min' => 1,
654
+ 'max' => 4, // ub-domain-defined-attributes
655
+ 'children' => $BuiltInDomainDefinedAttribute
656
+ );
657
+
658
+ $BuiltInStandardAttributes = array(
659
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
660
+ 'children' => array(
661
+ 'country-name' => array('optional' => true) + $CountryName,
662
+ 'administration-domain-name' => array('optional' => true) + $AdministrationDomainName,
663
+ 'network-address' => array(
664
+ 'constant' => 0,
665
+ 'optional' => true,
666
+ 'implicit' => true
667
+ ) + $NetworkAddress,
668
+ 'terminal-identifier' => array(
669
+ 'constant' => 1,
670
+ 'optional' => true,
671
+ 'implicit' => true
672
+ ) + $TerminalIdentifier,
673
+ 'private-domain-name' => array(
674
+ 'constant' => 2,
675
+ 'optional' => true,
676
+ 'explicit' => true
677
+ ) + $PrivateDomainName,
678
+ 'organization-name' => array(
679
+ 'constant' => 3,
680
+ 'optional' => true,
681
+ 'implicit' => true
682
+ ) + $OrganizationName,
683
+ 'numeric-user-identifier' => array(
684
+ 'constant' => 4,
685
+ 'optional' => true,
686
+ 'implicit' => true
687
+ ) + $NumericUserIdentifier,
688
+ 'personal-name' => array(
689
+ 'constant' => 5,
690
+ 'optional' => true,
691
+ 'implicit' => true
692
+ ) + $PersonalName,
693
+ 'organizational-unit-names' => array(
694
+ 'constant' => 6,
695
+ 'optional' => true,
696
+ 'implicit' => true
697
+ ) + $OrganizationalUnitNames
698
+ )
699
+ );
700
+
701
+ $ORAddress = array(
702
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
703
+ 'children' => array(
704
+ 'built-in-standard-attributes' => $BuiltInStandardAttributes,
705
+ 'built-in-domain-defined-attributes' => array('optional' => true) + $BuiltInDomainDefinedAttributes,
706
+ 'extension-attributes' => array('optional' => true) + $ExtensionAttributes
707
+ )
708
+ );
709
+
710
+ $EDIPartyName = array(
711
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
712
+ 'children' => array(
713
+ 'nameAssigner' => array(
714
+ 'constant' => 0,
715
+ 'optional' => true,
716
+ 'implicit' => true
717
+ ) + $this->DirectoryString,
718
+ // partyName is technically required but File_ASN1 doesn't currently support non-optional constants and
719
+ // setting it to optional gets the job done in any event.
720
+ 'partyName' => array(
721
+ 'constant' => 1,
722
+ 'optional' => true,
723
+ 'implicit' => true
724
+ ) + $this->DirectoryString
725
+ )
726
+ );
727
+
728
+ $GeneralName = array(
729
+ 'type' => FILE_ASN1_TYPE_CHOICE,
730
+ 'children' => array(
731
+ 'otherName' => array(
732
+ 'constant' => 0,
733
+ 'optional' => true,
734
+ 'implicit' => true
735
+ ) + $AnotherName,
736
+ 'rfc822Name' => array(
737
+ 'type' => FILE_ASN1_TYPE_IA5_STRING,
738
+ 'constant' => 1,
739
+ 'optional' => true,
740
+ 'implicit' => true
741
+ ),
742
+ 'dNSName' => array(
743
+ 'type' => FILE_ASN1_TYPE_IA5_STRING,
744
+ 'constant' => 2,
745
+ 'optional' => true,
746
+ 'implicit' => true
747
+ ),
748
+ 'x400Address' => array(
749
+ 'constant' => 3,
750
+ 'optional' => true,
751
+ 'implicit' => true
752
+ ) + $ORAddress,
753
+ 'directoryName' => array(
754
+ 'constant' => 4,
755
+ 'optional' => true,
756
+ 'explicit' => true
757
+ ) + $this->Name,
758
+ 'ediPartyName' => array(
759
+ 'constant' => 5,
760
+ 'optional' => true,
761
+ 'implicit' => true
762
+ ) + $EDIPartyName,
763
+ 'uniformResourceIdentifier' => array(
764
+ 'type' => FILE_ASN1_TYPE_IA5_STRING,
765
+ 'constant' => 6,
766
+ 'optional' => true,
767
+ 'implicit' => true
768
+ ),
769
+ 'iPAddress' => array(
770
+ 'type' => FILE_ASN1_TYPE_OCTET_STRING,
771
+ 'constant' => 7,
772
+ 'optional' => true,
773
+ 'implicit' => true
774
+ ),
775
+ 'registeredID' => array(
776
+ 'type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER,
777
+ 'constant' => 8,
778
+ 'optional' => true,
779
+ 'implicit' => true
780
+ )
781
+ )
782
+ );
783
+
784
+ $GeneralNames = array(
785
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
786
+ 'min' => 1,
787
+ 'max' => -1,
788
+ 'children' => $GeneralName
789
+ );
790
+
791
+ $this->IssuerAltName = $GeneralNames;
792
+
793
+ $ReasonFlags = array(
794
+ 'type' => FILE_ASN1_TYPE_BIT_STRING,
795
+ 'mapping' => array(
796
+ 'unused',
797
+ 'keyCompromise',
798
+ 'cACompromise',
799
+ 'affiliationChanged',
800
+ 'superseded',
801
+ 'cessationOfOperation',
802
+ 'certificateHold',
803
+ 'privilegeWithdrawn',
804
+ 'aACompromise'
805
+ )
806
+ );
807
+
808
+ $DistributionPointName = array(
809
+ 'type' => FILE_ASN1_TYPE_CHOICE,
810
+ 'children' => array(
811
+ 'fullName' => array(
812
+ 'constant' => 0,
813
+ 'optional' => true,
814
+ 'implicit' => true
815
+ ) + $GeneralNames,
816
+ 'nameRelativeToCRLIssuer' => array(
817
+ 'constant' => 1,
818
+ 'optional' => true,
819
+ 'implicit' => true
820
+ ) + $this->RelativeDistinguishedName
821
+ )
822
+ );
823
+
824
+ $DistributionPoint = array(
825
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
826
+ 'children' => array(
827
+ 'distributionPoint' => array(
828
+ 'constant' => 0,
829
+ 'optional' => true,
830
+ 'explicit' => true
831
+ ) + $DistributionPointName,
832
+ 'reasons' => array(
833
+ 'constant' => 1,
834
+ 'optional' => true,
835
+ 'implicit' => true
836
+ ) + $ReasonFlags,
837
+ 'cRLIssuer' => array(
838
+ 'constant' => 2,
839
+ 'optional' => true,
840
+ 'implicit' => true
841
+ ) + $GeneralNames
842
+ )
843
+ );
844
+
845
+ $this->CRLDistributionPoints = array(
846
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
847
+ 'min' => 1,
848
+ 'max' => -1,
849
+ 'children' => $DistributionPoint
850
+ );
851
+
852
+ $this->AuthorityKeyIdentifier = array(
853
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
854
+ 'children' => array(
855
+ 'keyIdentifier' => array(
856
+ 'constant' => 0,
857
+ 'optional' => true,
858
+ 'implicit' => true
859
+ ) + $this->KeyIdentifier,
860
+ 'authorityCertIssuer' => array(
861
+ 'constant' => 1,
862
+ 'optional' => true,
863
+ 'implicit' => true
864
+ ) + $GeneralNames,
865
+ 'authorityCertSerialNumber' => array(
866
+ 'constant' => 2,
867
+ 'optional' => true,
868
+ 'implicit' => true
869
+ ) + $CertificateSerialNumber
870
+ )
871
+ );
872
+
873
+ $PolicyQualifierId = array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER);
874
+
875
+ $PolicyQualifierInfo = array(
876
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
877
+ 'children' => array(
878
+ 'policyQualifierId' => $PolicyQualifierId,
879
+ 'qualifier' => array('type' => FILE_ASN1_TYPE_ANY)
880
+ )
881
+ );
882
+
883
+ $CertPolicyId = array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER);
884
+
885
+ $PolicyInformation = array(
886
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
887
+ 'children' => array(
888
+ 'policyIdentifier' => $CertPolicyId,
889
+ 'policyQualifiers' => array(
890
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
891
+ 'min' => 0,
892
+ 'max' => -1,
893
+ 'optional' => true,
894
+ 'children' => $PolicyQualifierInfo
895
+ )
896
+ )
897
+ );
898
+
899
+ $this->CertificatePolicies = array(
900
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
901
+ 'min' => 1,
902
+ 'max' => -1,
903
+ 'children' => $PolicyInformation
904
+ );
905
+
906
+ $this->PolicyMappings = array(
907
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
908
+ 'min' => 1,
909
+ 'max' => -1,
910
+ 'children' => array(
911
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
912
+ 'children' => array(
913
+ 'issuerDomainPolicy' => $CertPolicyId,
914
+ 'subjectDomainPolicy' => $CertPolicyId
915
+ )
916
+ )
917
+ );
918
+
919
+ $KeyPurposeId = array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER);
920
+
921
+ $this->ExtKeyUsageSyntax = array(
922
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
923
+ 'min' => 1,
924
+ 'max' => -1,
925
+ 'children' => $KeyPurposeId
926
+ );
927
+
928
+ $AccessDescription = array(
929
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
930
+ 'children' => array(
931
+ 'accessMethod' => array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER),
932
+ 'accessLocation' => $GeneralName
933
+ )
934
+ );
935
+
936
+ $this->AuthorityInfoAccessSyntax = array(
937
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
938
+ 'min' => 1,
939
+ 'max' => -1,
940
+ 'children' => $AccessDescription
941
+ );
942
+
943
+ $this->SubjectAltName = $GeneralNames;
944
+
945
+ $this->PrivateKeyUsagePeriod = array(
946
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
947
+ 'children' => array(
948
+ 'notBefore' => array(
949
+ 'constant' => 0,
950
+ 'optional' => true,
951
+ 'implicit' => true,
952
+ 'type' => FILE_ASN1_TYPE_GENERALIZED_TIME),
953
+ 'notAfter' => array(
954
+ 'constant' => 1,
955
+ 'optional' => true,
956
+ 'implicit' => true,
957
+ 'type' => FILE_ASN1_TYPE_GENERALIZED_TIME)
958
+ )
959
+ );
960
+
961
+ $BaseDistance = array('type' => FILE_ASN1_TYPE_INTEGER);
962
+
963
+ $GeneralSubtree = array(
964
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
965
+ 'children' => array(
966
+ 'base' => $GeneralName,
967
+ 'minimum' => array(
968
+ 'constant' => 0,
969
+ 'optional' => true,
970
+ 'implicit' => true,
971
+ 'default' => new Math_BigInteger(0)
972
+ ) + $BaseDistance,
973
+ 'maximum' => array(
974
+ 'constant' => 1,
975
+ 'optional' => true,
976
+ 'implicit' => true,
977
+ ) + $BaseDistance
978
+ )
979
+ );
980
+
981
+ $GeneralSubtrees = array(
982
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
983
+ 'min' => 1,
984
+ 'max' => -1,
985
+ 'children' => $GeneralSubtree
986
+ );
987
+
988
+ $this->NameConstraints = array(
989
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
990
+ 'children' => array(
991
+ 'permittedSubtrees' => array(
992
+ 'constant' => 0,
993
+ 'optional' => true,
994
+ 'implicit' => true
995
+ ) + $GeneralSubtrees,
996
+ 'excludedSubtrees' => array(
997
+ 'constant' => 1,
998
+ 'optional' => true,
999
+ 'implicit' => true
1000
+ ) + $GeneralSubtrees
1001
+ )
1002
+ );
1003
+
1004
+ $this->CPSuri = array('type' => FILE_ASN1_TYPE_IA5_STRING);
1005
+
1006
+ $DisplayText = array(
1007
+ 'type' => FILE_ASN1_TYPE_CHOICE,
1008
+ 'children' => array(
1009
+ 'ia5String' => array('type' => FILE_ASN1_TYPE_IA5_STRING),
1010
+ 'visibleString' => array('type' => FILE_ASN1_TYPE_VISIBLE_STRING),
1011
+ 'bmpString' => array('type' => FILE_ASN1_TYPE_BMP_STRING),
1012
+ 'utf8String' => array('type' => FILE_ASN1_TYPE_UTF8_STRING)
1013
+ )
1014
+ );
1015
+
1016
+ $NoticeReference = array(
1017
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
1018
+ 'children' => array(
1019
+ 'organization' => $DisplayText,
1020
+ 'noticeNumbers' => array(
1021
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
1022
+ 'min' => 1,
1023
+ 'max' => 200,
1024
+ 'children' => array('type' => FILE_ASN1_TYPE_INTEGER)
1025
+ )
1026
+ )
1027
+ );
1028
+
1029
+ $this->UserNotice = array(
1030
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
1031
+ 'children' => array(
1032
+ 'noticeRef' => array(
1033
+ 'optional' => true,
1034
+ 'implicit' => true
1035
+ ) + $NoticeReference,
1036
+ 'explicitText' => array(
1037
+ 'optional' => true,
1038
+ 'implicit' => true
1039
+ ) + $DisplayText
1040
+ )
1041
+ );
1042
+
1043
+ // mapping is from <http://www.mozilla.org/projects/security/pki/nss/tech-notes/tn3.html>
1044
+ $this->netscape_cert_type = array(
1045
+ 'type' => FILE_ASN1_TYPE_BIT_STRING,
1046
+ 'mapping' => array(
1047
+ 'SSLClient',
1048
+ 'SSLServer',
1049
+ 'Email',
1050
+ 'ObjectSigning',
1051
+ 'Reserved',
1052
+ 'SSLCA',
1053
+ 'EmailCA',
1054
+ 'ObjectSigningCA'
1055
+ )
1056
+ );
1057
+
1058
+ $this->netscape_comment = array('type' => FILE_ASN1_TYPE_IA5_STRING);
1059
+ $this->netscape_ca_policy_url = array('type' => FILE_ASN1_TYPE_IA5_STRING);
1060
+
1061
+ // attribute is used in RFC2986 but we're using the RFC5280 definition
1062
+
1063
+ $Attribute = array(
1064
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
1065
+ 'children' => array(
1066
+ 'type' => $AttributeType,
1067
+ 'value'=> array(
1068
+ 'type' => FILE_ASN1_TYPE_SET,
1069
+ 'min' => 1,
1070
+ 'max' => -1,
1071
+ 'children' => $this->AttributeValue
1072
+ )
1073
+ )
1074
+ );
1075
+
1076
+ // adapted from <http://tools.ietf.org/html/rfc2986>
1077
+
1078
+ $Attributes = array(
1079
+ 'type' => FILE_ASN1_TYPE_SET,
1080
+ 'min' => 1,
1081
+ 'max' => -1,
1082
+ 'children' => $Attribute
1083
+ );
1084
+
1085
+ $CertificationRequestInfo = array(
1086
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
1087
+ 'children' => array(
1088
+ 'version' => array(
1089
+ 'type' => FILE_ASN1_TYPE_INTEGER,
1090
+ 'mapping' => array('v1')
1091
+ ),
1092
+ 'subject' => $this->Name,
1093
+ 'subjectPKInfo' => $SubjectPublicKeyInfo,
1094
+ 'attributes' => array(
1095
+ 'constant' => 0,
1096
+ 'optional' => true,
1097
+ 'implicit' => true
1098
+ ) + $Attributes,
1099
+ )
1100
+ );
1101
+
1102
+ $this->CertificationRequest = array(
1103
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
1104
+ 'children' => array(
1105
+ 'certificationRequestInfo' => $CertificationRequestInfo,
1106
+ 'signatureAlgorithm' => $AlgorithmIdentifier,
1107
+ 'signature' => array('type' => FILE_ASN1_TYPE_BIT_STRING)
1108
+ )
1109
+ );
1110
+
1111
+ $RevokedCertificate = array(
1112
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
1113
+ 'children' => array(
1114
+ 'userCertificate' => $CertificateSerialNumber,
1115
+ 'revocationDate' => $Time,
1116
+ 'crlEntryExtensions' => array(
1117
+ 'optional' => true
1118
+ ) + $this->Extensions
1119
+ )
1120
+ );
1121
+
1122
+ $TBSCertList = array(
1123
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
1124
+ 'children' => array(
1125
+ 'version' => array(
1126
+ 'optional' => true,
1127
+ 'default' => 'v1'
1128
+ ) + $Version,
1129
+ 'signature' => $AlgorithmIdentifier,
1130
+ 'issuer' => $this->Name,
1131
+ 'thisUpdate' => $Time,
1132
+ 'nextUpdate' => array(
1133
+ 'optional' => true
1134
+ ) + $Time,
1135
+ 'revokedCertificates' => array(
1136
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
1137
+ 'optional' => true,
1138
+ 'min' => 0,
1139
+ 'max' => -1,
1140
+ 'children' => $RevokedCertificate
1141
+ ),
1142
+ 'crlExtensions' => array(
1143
+ 'constant' => 0,
1144
+ 'optional' => true,
1145
+ 'explicit' => true
1146
+ ) + $this->Extensions
1147
+ )
1148
+ );
1149
+
1150
+ $this->CertificateList = array(
1151
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
1152
+ 'children' => array(
1153
+ 'tbsCertList' => $TBSCertList,
1154
+ 'signatureAlgorithm' => $AlgorithmIdentifier,
1155
+ 'signature' => array('type' => FILE_ASN1_TYPE_BIT_STRING)
1156
+ )
1157
+ );
1158
+
1159
+ $this->CRLNumber = array('type' => FILE_ASN1_TYPE_INTEGER);
1160
+
1161
+ $this->CRLReason = array('type' => FILE_ASN1_TYPE_ENUMERATED,
1162
+ 'mapping' => array(
1163
+ 'unspecified',
1164
+ 'keyCompromise',
1165
+ 'cACompromise',
1166
+ 'affiliationChanged',
1167
+ 'superseded',
1168
+ 'cessationOfOperation',
1169
+ 'certificateHold',
1170
+ // Value 7 is not used.
1171
+ 8 => 'removeFromCRL',
1172
+ 'privilegeWithdrawn',
1173
+ 'aACompromise'
1174
+ )
1175
+ );
1176
+
1177
+ $this->IssuingDistributionPoint = array('type' => FILE_ASN1_TYPE_SEQUENCE,
1178
+ 'children' => array(
1179
+ 'distributionPoint' => array(
1180
+ 'constant' => 0,
1181
+ 'optional' => true,
1182
+ 'explicit' => true
1183
+ ) + $DistributionPointName,
1184
+ 'onlyContainsUserCerts' => array(
1185
+ 'type' => FILE_ASN1_TYPE_BOOLEAN,
1186
+ 'constant' => 1,
1187
+ 'optional' => true,
1188
+ 'default' => false,
1189
+ 'implicit' => true
1190
+ ),
1191
+ 'onlyContainsCACerts' => array(
1192
+ 'type' => FILE_ASN1_TYPE_BOOLEAN,
1193
+ 'constant' => 2,
1194
+ 'optional' => true,
1195
+ 'default' => false,
1196
+ 'implicit' => true
1197
+ ),
1198
+ 'onlySomeReasons' => array(
1199
+ 'constant' => 3,
1200
+ 'optional' => true,
1201
+ 'implicit' => true
1202
+ ) + $ReasonFlags,
1203
+ 'indirectCRL' => array(
1204
+ 'type' => FILE_ASN1_TYPE_BOOLEAN,
1205
+ 'constant' => 4,
1206
+ 'optional' => true,
1207
+ 'default' => false,
1208
+ 'implicit' => true
1209
+ ),
1210
+ 'onlyContainsAttributeCerts' => array(
1211
+ 'type' => FILE_ASN1_TYPE_BOOLEAN,
1212
+ 'constant' => 5,
1213
+ 'optional' => true,
1214
+ 'default' => false,
1215
+ 'implicit' => true
1216
+ )
1217
+ )
1218
+ );
1219
+
1220
+ $this->InvalidityDate = array('type' => FILE_ASN1_TYPE_GENERALIZED_TIME);
1221
+
1222
+ $this->CertificateIssuer = $GeneralNames;
1223
+
1224
+ $this->HoldInstructionCode = array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER);
1225
+
1226
+ $PublicKeyAndChallenge = array(
1227
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
1228
+ 'children' => array(
1229
+ 'spki' => $SubjectPublicKeyInfo,
1230
+ 'challenge' => array('type' => FILE_ASN1_TYPE_IA5_STRING)
1231
+ )
1232
+ );
1233
+
1234
+ $this->SignedPublicKeyAndChallenge = array(
1235
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
1236
+ 'children' => array(
1237
+ 'publicKeyAndChallenge' => $PublicKeyAndChallenge,
1238
+ 'signatureAlgorithm' => $AlgorithmIdentifier,
1239
+ 'signature' => array('type' => FILE_ASN1_TYPE_BIT_STRING)
1240
+ )
1241
+ );
1242
+
1243
+ // OIDs from RFC5280 and those RFCs mentioned in RFC5280#section-4.1.1.2
1244
+ $this->oids = array(
1245
+ '1.3.6.1.5.5.7' => 'id-pkix',
1246
+ '1.3.6.1.5.5.7.1' => 'id-pe',
1247
+ '1.3.6.1.5.5.7.2' => 'id-qt',
1248
+ '1.3.6.1.5.5.7.3' => 'id-kp',
1249
+ '1.3.6.1.5.5.7.48' => 'id-ad',
1250
+ '1.3.6.1.5.5.7.2.1' => 'id-qt-cps',
1251
+ '1.3.6.1.5.5.7.2.2' => 'id-qt-unotice',
1252
+ '1.3.6.1.5.5.7.48.1' =>'id-ad-ocsp',
1253
+ '1.3.6.1.5.5.7.48.2' => 'id-ad-caIssuers',
1254
+ '1.3.6.1.5.5.7.48.3' => 'id-ad-timeStamping',
1255
+ '1.3.6.1.5.5.7.48.5' => 'id-ad-caRepository',
1256
+ '2.5.4' => 'id-at',
1257
+ '2.5.4.41' => 'id-at-name',
1258
+ '2.5.4.4' => 'id-at-surname',
1259
+ '2.5.4.42' => 'id-at-givenName',
1260
+ '2.5.4.43' => 'id-at-initials',
1261
+ '2.5.4.44' => 'id-at-generationQualifier',
1262
+ '2.5.4.3' => 'id-at-commonName',
1263
+ '2.5.4.7' => 'id-at-localityName',
1264
+ '2.5.4.8' => 'id-at-stateOrProvinceName',
1265
+ '2.5.4.10' => 'id-at-organizationName',
1266
+ '2.5.4.11' => 'id-at-organizationalUnitName',
1267
+ '2.5.4.12' => 'id-at-title',
1268
+ '2.5.4.13' => 'id-at-description',
1269
+ '2.5.4.46' => 'id-at-dnQualifier',
1270
+ '2.5.4.6' => 'id-at-countryName',
1271
+ '2.5.4.5' => 'id-at-serialNumber',
1272
+ '2.5.4.65' => 'id-at-pseudonym',
1273
+ '2.5.4.17' => 'id-at-postalCode',
1274
+ '2.5.4.9' => 'id-at-streetAddress',
1275
+ '2.5.4.45' => 'id-at-uniqueIdentifier',
1276
+ '2.5.4.72' => 'id-at-role',
1277
+
1278
+ '0.9.2342.19200300.100.1.25' => 'id-domainComponent',
1279
+ '1.2.840.113549.1.9' => 'pkcs-9',
1280
+ '1.2.840.113549.1.9.1' => 'pkcs-9-at-emailAddress',
1281
+ '2.5.29' => 'id-ce',
1282
+ '2.5.29.35' => 'id-ce-authorityKeyIdentifier',
1283
+ '2.5.29.14' => 'id-ce-subjectKeyIdentifier',
1284
+ '2.5.29.15' => 'id-ce-keyUsage',
1285
+ '2.5.29.16' => 'id-ce-privateKeyUsagePeriod',
1286
+ '2.5.29.32' => 'id-ce-certificatePolicies',
1287
+ '2.5.29.32.0' => 'anyPolicy',
1288
+
1289
+ '2.5.29.33' => 'id-ce-policyMappings',
1290
+ '2.5.29.17' => 'id-ce-subjectAltName',
1291
+ '2.5.29.18' => 'id-ce-issuerAltName',
1292
+ '2.5.29.9' => 'id-ce-subjectDirectoryAttributes',
1293
+ '2.5.29.19' => 'id-ce-basicConstraints',
1294
+ '2.5.29.30' => 'id-ce-nameConstraints',
1295
+ '2.5.29.36' => 'id-ce-policyConstraints',
1296
+ '2.5.29.31' => 'id-ce-cRLDistributionPoints',
1297
+ '2.5.29.37' => 'id-ce-extKeyUsage',
1298
+ '2.5.29.37.0' => 'anyExtendedKeyUsage',
1299
+ '1.3.6.1.5.5.7.3.1' => 'id-kp-serverAuth',
1300
+ '1.3.6.1.5.5.7.3.2' => 'id-kp-clientAuth',
1301
+ '1.3.6.1.5.5.7.3.3' => 'id-kp-codeSigning',
1302
+ '1.3.6.1.5.5.7.3.4' => 'id-kp-emailProtection',
1303
+ '1.3.6.1.5.5.7.3.8' => 'id-kp-timeStamping',
1304
+ '1.3.6.1.5.5.7.3.9' => 'id-kp-OCSPSigning',
1305
+ '2.5.29.54' => 'id-ce-inhibitAnyPolicy',
1306
+ '2.5.29.46' => 'id-ce-freshestCRL',
1307
+ '1.3.6.1.5.5.7.1.1' => 'id-pe-authorityInfoAccess',
1308
+ '1.3.6.1.5.5.7.1.11' => 'id-pe-subjectInfoAccess',
1309
+ '2.5.29.20' => 'id-ce-cRLNumber',
1310
+ '2.5.29.28' => 'id-ce-issuingDistributionPoint',
1311
+ '2.5.29.27' => 'id-ce-deltaCRLIndicator',
1312
+ '2.5.29.21' => 'id-ce-cRLReasons',
1313
+ '2.5.29.29' => 'id-ce-certificateIssuer',
1314
+ '2.5.29.23' => 'id-ce-holdInstructionCode',
1315
+ '1.2.840.10040.2' => 'holdInstruction',
1316
+ '1.2.840.10040.2.1' => 'id-holdinstruction-none',
1317
+ '1.2.840.10040.2.2' => 'id-holdinstruction-callissuer',
1318
+ '1.2.840.10040.2.3' => 'id-holdinstruction-reject',
1319
+ '2.5.29.24' => 'id-ce-invalidityDate',
1320
+
1321
+ '1.2.840.113549.2.2' => 'md2',
1322
+ '1.2.840.113549.2.5' => 'md5',
1323
+ '1.3.14.3.2.26' => 'id-sha1',
1324
+ '1.2.840.10040.4.1' => 'id-dsa',
1325
+ '1.2.840.10040.4.3' => 'id-dsa-with-sha1',
1326
+ '1.2.840.113549.1.1' => 'pkcs-1',
1327
+ '1.2.840.113549.1.1.1' => 'rsaEncryption',
1328
+ '1.2.840.113549.1.1.2' => 'md2WithRSAEncryption',
1329
+ '1.2.840.113549.1.1.4' => 'md5WithRSAEncryption',
1330
+ '1.2.840.113549.1.1.5' => 'sha1WithRSAEncryption',
1331
+ '1.2.840.10046.2.1' => 'dhpublicnumber',
1332
+ '2.16.840.1.101.2.1.1.22' => 'id-keyExchangeAlgorithm',
1333
+ '1.2.840.10045' => 'ansi-X9-62',
1334
+ '1.2.840.10045.4' => 'id-ecSigType',
1335
+ '1.2.840.10045.4.1' => 'ecdsa-with-SHA1',
1336
+ '1.2.840.10045.1' => 'id-fieldType',
1337
+ '1.2.840.10045.1.1' => 'prime-field',
1338
+ '1.2.840.10045.1.2' => 'characteristic-two-field',
1339
+ '1.2.840.10045.1.2.3' => 'id-characteristic-two-basis',
1340
+ '1.2.840.10045.1.2.3.1' => 'gnBasis',
1341
+ '1.2.840.10045.1.2.3.2' => 'tpBasis',
1342
+ '1.2.840.10045.1.2.3.3' => 'ppBasis',
1343
+ '1.2.840.10045.2' => 'id-publicKeyType',
1344
+ '1.2.840.10045.2.1' => 'id-ecPublicKey',
1345
+ '1.2.840.10045.3' => 'ellipticCurve',
1346
+ '1.2.840.10045.3.0' => 'c-TwoCurve',
1347
+ '1.2.840.10045.3.0.1' => 'c2pnb163v1',
1348
+ '1.2.840.10045.3.0.2' => 'c2pnb163v2',
1349
+ '1.2.840.10045.3.0.3' => 'c2pnb163v3',
1350
+ '1.2.840.10045.3.0.4' => 'c2pnb176w1',
1351
+ '1.2.840.10045.3.0.5' => 'c2pnb191v1',
1352
+ '1.2.840.10045.3.0.6' => 'c2pnb191v2',
1353
+ '1.2.840.10045.3.0.7' => 'c2pnb191v3',
1354
+ '1.2.840.10045.3.0.8' => 'c2pnb191v4',
1355
+ '1.2.840.10045.3.0.9' => 'c2pnb191v5',
1356
+ '1.2.840.10045.3.0.10' => 'c2pnb208w1',
1357
+ '1.2.840.10045.3.0.11' => 'c2pnb239v1',
1358
+ '1.2.840.10045.3.0.12' => 'c2pnb239v2',
1359
+ '1.2.840.10045.3.0.13' => 'c2pnb239v3',
1360
+ '1.2.840.10045.3.0.14' => 'c2pnb239v4',
1361
+ '1.2.840.10045.3.0.15' => 'c2pnb239v5',
1362
+ '1.2.840.10045.3.0.16' => 'c2pnb272w1',
1363
+ '1.2.840.10045.3.0.17' => 'c2pnb304w1',
1364
+ '1.2.840.10045.3.0.18' => 'c2pnb359v1',
1365
+ '1.2.840.10045.3.0.19' => 'c2pnb368w1',
1366
+ '1.2.840.10045.3.0.20' => 'c2pnb431r1',
1367
+ '1.2.840.10045.3.1' => 'primeCurve',
1368
+ '1.2.840.10045.3.1.1' => 'prime192v1',
1369
+ '1.2.840.10045.3.1.2' => 'prime192v2',
1370
+ '1.2.840.10045.3.1.3' => 'prime192v3',
1371
+ '1.2.840.10045.3.1.4' => 'prime239v1',
1372
+ '1.2.840.10045.3.1.5' => 'prime239v2',
1373
+ '1.2.840.10045.3.1.6' => 'prime239v3',
1374
+ '1.2.840.10045.3.1.7' => 'prime256v1',
1375
+ '1.2.840.113549.1.1.7' => 'id-RSAES-OAEP',
1376
+ '1.2.840.113549.1.1.9' => 'id-pSpecified',
1377
+ '1.2.840.113549.1.1.10' => 'id-RSASSA-PSS',
1378
+ '1.2.840.113549.1.1.8' => 'id-mgf1',
1379
+ '1.2.840.113549.1.1.14' => 'sha224WithRSAEncryption',
1380
+ '1.2.840.113549.1.1.11' => 'sha256WithRSAEncryption',
1381
+ '1.2.840.113549.1.1.12' => 'sha384WithRSAEncryption',
1382
+ '1.2.840.113549.1.1.13' => 'sha512WithRSAEncryption',
1383
+ '2.16.840.1.101.3.4.2.4' => 'id-sha224',
1384
+ '2.16.840.1.101.3.4.2.1' => 'id-sha256',
1385
+ '2.16.840.1.101.3.4.2.2' => 'id-sha384',
1386
+ '2.16.840.1.101.3.4.2.3' => 'id-sha512',
1387
+ '1.2.643.2.2.4' => 'id-GostR3411-94-with-GostR3410-94',
1388
+ '1.2.643.2.2.3' => 'id-GostR3411-94-with-GostR3410-2001',
1389
+ '1.2.643.2.2.20' => 'id-GostR3410-2001',
1390
+ '1.2.643.2.2.19' => 'id-GostR3410-94',
1391
+ // Netscape Object Identifiers from "Netscape Certificate Extensions"
1392
+ '2.16.840.1.113730' => 'netscape',
1393
+ '2.16.840.1.113730.1' => 'netscape-cert-extension',
1394
+ '2.16.840.1.113730.1.1' => 'netscape-cert-type',
1395
+ '2.16.840.1.113730.1.13' => 'netscape-comment',
1396
+ '2.16.840.1.113730.1.8' => 'netscape-ca-policy-url',
1397
+ // the following are X.509 extensions not supported by phpseclib
1398
+ '1.3.6.1.5.5.7.1.12' => 'id-pe-logotype',
1399
+ '1.2.840.113533.7.65.0' => 'entrustVersInfo',
1400
+ '2.16.840.1.113733.1.6.9' => 'verisignPrivate',
1401
+ // for Certificate Signing Requests
1402
+ // see http://tools.ietf.org/html/rfc2985
1403
+ '1.2.840.113549.1.9.2' => 'pkcs-9-at-unstructuredName', // PKCS #9 unstructured name
1404
+ '1.2.840.113549.1.9.7' => 'pkcs-9-at-challengePassword', // Challenge password for certificate revocations
1405
+ '1.2.840.113549.1.9.14' => 'pkcs-9-at-extensionRequest' // Certificate extension request
1406
+ );
1407
+ }
1408
+
1409
+ /**
1410
+ * Load X.509 certificate
1411
+ *
1412
+ * Returns an associative array describing the X.509 cert or a false if the cert failed to load
1413
+ *
1414
+ * @param String $cert
1415
+ * @access public
1416
+ * @return Mixed
1417
+ */
1418
+ function loadX509($cert)
1419
+ {
1420
+ if (is_array($cert) && isset($cert['tbsCertificate'])) {
1421
+ unset($this->currentCert);
1422
+ unset($this->currentKeyIdentifier);
1423
+ $this->dn = $cert['tbsCertificate']['subject'];
1424
+ if (!isset($this->dn)) {
1425
+ return false;
1426
+ }
1427
+ $this->currentCert = $cert;
1428
+
1429
+ $currentKeyIdentifier = $this->getExtension('id-ce-subjectKeyIdentifier');
1430
+ $this->currentKeyIdentifier = is_string($currentKeyIdentifier) ? $currentKeyIdentifier : NULL;
1431
+
1432
+ unset($this->signatureSubject);
1433
+
1434
+ return $cert;
1435
+ }
1436
+
1437
+ $asn1 = new File_ASN1();
1438
+
1439
+ $cert = $this->_extractBER($cert);
1440
+
1441
+ if ($cert === false) {
1442
+ $this->currentCert = false;
1443
+ return false;
1444
+ }
1445
+
1446
+ $asn1->loadOIDs($this->oids);
1447
+ $decoded = $asn1->decodeBER($cert);
1448
+
1449
+ if (!empty($decoded)) {
1450
+ $x509 = $asn1->asn1map($decoded[0], $this->Certificate);
1451
+ }
1452
+ if (!isset($x509) || $x509 === false) {
1453
+ $this->currentCert = false;
1454
+ return false;
1455
+ }
1456
+
1457
+ $this->signatureSubject = substr($cert, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']);
1458
+
1459
+ $this->_mapInExtensions($x509, 'tbsCertificate/extensions', $asn1);
1460
+
1461
+ $key = &$x509['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'];
1462
+ $key = $this->_reformatKey($x509['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['algorithm'], $key);
1463
+
1464
+ $this->currentCert = $x509;
1465
+ $this->dn = $x509['tbsCertificate']['subject'];
1466
+
1467
+ $currentKeyIdentifier = $this->getExtension('id-ce-subjectKeyIdentifier');
1468
+ $this->currentKeyIdentifier = is_string($currentKeyIdentifier) ? $currentKeyIdentifier : NULL;
1469
+
1470
+ return $x509;
1471
+ }
1472
+
1473
+ /**
1474
+ * Save X.509 certificate
1475
+ *
1476
+ * @param Array $cert
1477
+ * @param Integer $format optional
1478
+ * @access public
1479
+ * @return String
1480
+ */
1481
+ function saveX509($cert, $format = FILE_X509_FORMAT_PEM)
1482
+ {
1483
+ if (!is_array($cert) || !isset($cert['tbsCertificate'])) {
1484
+ return false;
1485
+ }
1486
+
1487
+ switch (true) {
1488
+ // "case !$a: case !$b: break; default: whatever();" is the same thing as "if ($a && $b) whatever()"
1489
+ case !($algorithm = $this->_subArray($cert, 'tbsCertificate/subjectPublicKeyInfo/algorithm/algorithm')):
1490
+ case is_object($cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey']):
1491
+ break;
1492
+ default:
1493
+ switch ($algorithm) {
1494
+ case 'rsaEncryption':
1495
+ $cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'] =
1496
+ base64_encode("\0" . base64_decode(preg_replace('#-.+-|[\r\n]#', '', $cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'])));
1497
+ }
1498
+ }
1499
+
1500
+ $asn1 = new File_ASN1();
1501
+
1502
+ $asn1->loadOIDs($this->oids);
1503
+
1504
+ $filters = array();
1505
+ $filters['tbsCertificate']['signature']['parameters'] =
1506
+ $filters['tbsCertificate']['signature']['issuer']['rdnSequence']['value'] =
1507
+ $filters['tbsCertificate']['issuer']['rdnSequence']['value'] =
1508
+ $filters['tbsCertificate']['subject']['rdnSequence']['value'] =
1509
+ $filters['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['parameters'] =
1510
+ $filters['signatureAlgorithm']['parameters'] =
1511
+ $filters['authorityCertIssuer']['directoryName']['rdnSequence']['value'] =
1512
+ //$filters['policyQualifiers']['qualifier'] =
1513
+ $filters['distributionPoint']['fullName']['directoryName']['rdnSequence']['value'] =
1514
+ $filters['directoryName']['rdnSequence']['value'] =
1515
+ array('type' => FILE_ASN1_TYPE_UTF8_STRING);
1516
+ /* in the case of policyQualifiers/qualifier, the type has to be FILE_ASN1_TYPE_IA5_STRING.
1517
+ FILE_ASN1_TYPE_PRINTABLE_STRING will cause OpenSSL's X.509 parser to spit out random
1518
+ characters.
1519
+ */
1520
+ $filters['policyQualifiers']['qualifier'] =
1521
+ array('type' => FILE_ASN1_TYPE_IA5_STRING);
1522
+
1523
+ $asn1->loadFilters($filters);
1524
+
1525
+ $this->_mapOutExtensions($cert, 'tbsCertificate/extensions', $asn1);
1526
+
1527
+ $cert = $asn1->encodeDER($cert, $this->Certificate);
1528
+
1529
+ switch ($format) {
1530
+ case FILE_X509_FORMAT_DER:
1531
+ return $cert;
1532
+ // case FILE_X509_FORMAT_PEM:
1533
+ default:
1534
+ return "-----BEGIN CERTIFICATE-----\r\n" . chunk_split(base64_encode($cert), 64) . '-----END CERTIFICATE-----';
1535
+ }
1536
+ }
1537
+
1538
+ /**
1539
+ * Map extension values from octet string to extension-specific internal
1540
+ * format.
1541
+ *
1542
+ * @param Array ref $root
1543
+ * @param String $path
1544
+ * @param Object $asn1
1545
+ * @access private
1546
+ */
1547
+ function _mapInExtensions(&$root, $path, $asn1)
1548
+ {
1549
+ $extensions = &$this->_subArray($root, $path);
1550
+
1551
+ if (is_array($extensions)) {
1552
+ for ($i = 0; $i < count($extensions); $i++) {
1553
+ $id = $extensions[$i]['extnId'];
1554
+ $value = &$extensions[$i]['extnValue'];
1555
+ $value = base64_decode($value);
1556
+ $decoded = $asn1->decodeBER($value);
1557
+ /* [extnValue] contains the DER encoding of an ASN.1 value
1558
+ corresponding to the extension type identified by extnID */
1559
+ $map = $this->_getMapping($id);
1560
+ if (!is_bool($map)) {
1561
+ $mapped = $asn1->asn1map($decoded[0], $map);
1562
+ $value = $mapped === false ? $decoded[0] : $mapped;
1563
+
1564
+ if ($id == 'id-ce-certificatePolicies') {
1565
+ for ($j = 0; $j < count($value); $j++) {
1566
+ if (!isset($value[$j]['policyQualifiers'])) {
1567
+ continue;
1568
+ }
1569
+ for ($k = 0; $k < count($value[$j]['policyQualifiers']); $k++) {
1570
+ $subid = $value[$j]['policyQualifiers'][$k]['policyQualifierId'];
1571
+ $map = $this->_getMapping($subid);
1572
+ $subvalue = &$value[$j]['policyQualifiers'][$k]['qualifier'];
1573
+ if ($map !== false) {
1574
+ $decoded = $asn1->decodeBER($subvalue);
1575
+ $mapped = $asn1->asn1map($decoded[0], $map);
1576
+ $subvalue = $mapped === false ? $decoded[0] : $mapped;
1577
+ }
1578
+ }
1579
+ }
1580
+ }
1581
+ } elseif ($map) {
1582
+ $value = base64_encode($value);
1583
+ }
1584
+ }
1585
+ }
1586
+ }
1587
+
1588
+ /**
1589
+ * Map extension values from extension-specific internal format to
1590
+ * octet string.
1591
+ *
1592
+ * @param Array ref $root
1593
+ * @param String $path
1594
+ * @param Object $asn1
1595
+ * @access private
1596
+ */
1597
+ function _mapOutExtensions(&$root, $path, $asn1)
1598
+ {
1599
+ $extensions = &$this->_subArray($root, $path);
1600
+
1601
+ if (is_array($extensions)) {
1602
+ $size = count($extensions);
1603
+ for ($i = 0; $i < $size; $i++) {
1604
+ $id = $extensions[$i]['extnId'];
1605
+ $value = &$extensions[$i]['extnValue'];
1606
+
1607
+ switch ($id) {
1608
+ case 'id-ce-certificatePolicies':
1609
+ for ($j = 0; $j < count($value); $j++) {
1610
+ if (!isset($value[$j]['policyQualifiers'])) {
1611
+ continue;
1612
+ }
1613
+ for ($k = 0; $k < count($value[$j]['policyQualifiers']); $k++) {
1614
+ $subid = $value[$j]['policyQualifiers'][$k]['policyQualifierId'];
1615
+ $map = $this->_getMapping($subid);
1616
+ $subvalue = &$value[$j]['policyQualifiers'][$k]['qualifier'];
1617
+ if ($map !== false) {
1618
+ // by default File_ASN1 will try to render qualifier as a FILE_ASN1_TYPE_IA5_STRING since it's
1619
+ // actual type is FILE_ASN1_TYPE_ANY
1620
+ $subvalue = new File_ASN1_Element($asn1->encodeDER($subvalue, $map));
1621
+ }
1622
+ }
1623
+ }
1624
+ break;
1625
+ case 'id-ce-authorityKeyIdentifier': // use 00 as the serial number instead of an empty string
1626
+ if (isset($value['authorityCertSerialNumber'])) {
1627
+ if ($value['authorityCertSerialNumber']->toBytes() == '') {
1628
+ $temp = chr((FILE_ASN1_CLASS_CONTEXT_SPECIFIC << 6) | 2) . "\1\0";
1629
+ $value['authorityCertSerialNumber'] = new File_ASN1_Element($temp);
1630
+ }
1631
+ }
1632
+ }
1633
+
1634
+ /* [extnValue] contains the DER encoding of an ASN.1 value
1635
+ corresponding to the extension type identified by extnID */
1636
+ $map = $this->_getMapping($id);
1637
+ if (is_bool($map)) {
1638
+ if (!$map) {
1639
+ user_error($id . ' is not a currently supported extension');
1640
+ unset($extensions[$i]);
1641
+ }
1642
+ } else {
1643
+ $temp = $asn1->encodeDER($value, $map);
1644
+ $value = base64_encode($temp);
1645
+ }
1646
+ }
1647
+ }
1648
+ }
1649
+
1650
+ /**
1651
+ * Map attribute values from ANY type to attribute-specific internal
1652
+ * format.
1653
+ *
1654
+ * @param Array ref $root
1655
+ * @param String $path
1656
+ * @param Object $asn1
1657
+ * @access private
1658
+ */
1659
+ function _mapInAttributes(&$root, $path, $asn1)
1660
+ {
1661
+ $attributes = &$this->_subArray($root, $path);
1662
+
1663
+ if (is_array($attributes)) {
1664
+ for ($i = 0; $i < count($attributes); $i++) {
1665
+ $id = $attributes[$i]['type'];
1666
+ /* $value contains the DER encoding of an ASN.1 value
1667
+ corresponding to the attribute type identified by type */
1668
+ $map = $this->_getMapping($id);
1669
+ if (is_array($attributes[$i]['value'])) {
1670
+ $values = &$attributes[$i]['value'];
1671
+ for ($j = 0; $j < count($values); $j++) {
1672
+ $value = $asn1->encodeDER($values[$j], $this->AttributeValue);
1673
+ $decoded = $asn1->decodeBER($value);
1674
+ if (!is_bool($map)) {
1675
+ $mapped = $asn1->asn1map($decoded[0], $map);
1676
+ if ($mapped !== false) {
1677
+ $values[$j] = $mapped;
1678
+ }
1679
+ if ($id == 'pkcs-9-at-extensionRequest') {
1680
+ $this->_mapInExtensions($values, $j, $asn1);
1681
+ }
1682
+ } elseif ($map) {
1683
+ $values[$j] = base64_encode($value);
1684
+ }
1685
+ }
1686
+ }
1687
+ }
1688
+ }
1689
+ }
1690
+
1691
+ /**
1692
+ * Map attribute values from attribute-specific internal format to
1693
+ * ANY type.
1694
+ *
1695
+ * @param Array ref $root
1696
+ * @param String $path
1697
+ * @param Object $asn1
1698
+ * @access private
1699
+ */
1700
+ function _mapOutAttributes(&$root, $path, $asn1)
1701
+ {
1702
+ $attributes = &$this->_subArray($root, $path);
1703
+
1704
+ if (is_array($attributes)) {
1705
+ $size = count($attributes);
1706
+ for ($i = 0; $i < $size; $i++) {
1707
+ /* [value] contains the DER encoding of an ASN.1 value
1708
+ corresponding to the attribute type identified by type */
1709
+ $id = $attributes[$i]['type'];
1710
+ $map = $this->_getMapping($id);
1711
+ if ($map === false) {
1712
+ user_error($id . ' is not a currently supported attribute', E_USER_NOTICE);
1713
+ unset($attributes[$i]);
1714
+ }
1715
+ elseif (is_array($attributes[$i]['value'])) {
1716
+ $values = &$attributes[$i]['value'];
1717
+ for ($j = 0; $j < count($values); $j++) {
1718
+ switch ($id) {
1719
+ case 'pkcs-9-at-extensionRequest':
1720
+ $this->_mapOutExtensions($values, $j, $asn1);
1721
+ break;
1722
+ }
1723
+
1724
+ if (!is_bool($map)) {
1725
+ $temp = $asn1->encodeDER($values[$j], $map);
1726
+ $decoded = $asn1->decodeBER($temp);
1727
+ $values[$j] = $asn1->asn1map($decoded[0], $this->AttributeValue);
1728
+ }
1729
+ }
1730
+ }
1731
+ }
1732
+ }
1733
+ }
1734
+
1735
+ /**
1736
+ * Associate an extension ID to an extension mapping
1737
+ *
1738
+ * @param String $extnId
1739
+ * @access private
1740
+ * @return Mixed
1741
+ */
1742
+ function _getMapping($extnId)
1743
+ {
1744
+ if (!is_string($extnId)) { // eg. if it's a File_ASN1_Element object
1745
+ return true;
1746
+ }
1747
+
1748
+ switch ($extnId) {
1749
+ case 'id-ce-keyUsage':
1750
+ return $this->KeyUsage;
1751
+ case 'id-ce-basicConstraints':
1752
+ return $this->BasicConstraints;
1753
+ case 'id-ce-subjectKeyIdentifier':
1754
+ return $this->KeyIdentifier;
1755
+ case 'id-ce-cRLDistributionPoints':
1756
+ return $this->CRLDistributionPoints;
1757
+ case 'id-ce-authorityKeyIdentifier':
1758
+ return $this->AuthorityKeyIdentifier;
1759
+ case 'id-ce-certificatePolicies':
1760
+ return $this->CertificatePolicies;
1761
+ case 'id-ce-extKeyUsage':
1762
+ return $this->ExtKeyUsageSyntax;
1763
+ case 'id-pe-authorityInfoAccess':
1764
+ return $this->AuthorityInfoAccessSyntax;
1765
+ case 'id-ce-subjectAltName':
1766
+ return $this->SubjectAltName;
1767
+ case 'id-ce-privateKeyUsagePeriod':
1768
+ return $this->PrivateKeyUsagePeriod;
1769
+ case 'id-ce-issuerAltName':
1770
+ return $this->IssuerAltName;
1771
+ case 'id-ce-policyMappings':
1772
+ return $this->PolicyMappings;
1773
+ case 'id-ce-nameConstraints':
1774
+ return $this->NameConstraints;
1775
+
1776
+ case 'netscape-cert-type':
1777
+ return $this->netscape_cert_type;
1778
+ case 'netscape-comment':
1779
+ return $this->netscape_comment;
1780
+ case 'netscape-ca-policy-url':
1781
+ return $this->netscape_ca_policy_url;
1782
+
1783
+ // since id-qt-cps isn't a constructed type it will have already been decoded as a string by the time it gets
1784
+ // back around to asn1map() and we don't want it decoded again.
1785
+ //case 'id-qt-cps':
1786
+ // return $this->CPSuri;
1787
+ case 'id-qt-unotice':
1788
+ return $this->UserNotice;
1789
+
1790
+ // the following OIDs are unsupported but we don't want them to give notices when calling saveX509().
1791
+ case 'id-pe-logotype': // http://www.ietf.org/rfc/rfc3709.txt
1792
+ case 'entrustVersInfo':
1793
+ // http://support.microsoft.com/kb/287547
1794
+ case '1.3.6.1.4.1.311.20.2': // szOID_ENROLL_CERTTYPE_EXTENSION
1795
+ case '1.3.6.1.4.1.311.21.1': // szOID_CERTSRV_CA_VERSION
1796
+ // "SET Secure Electronic Transaction Specification"
1797
+ // http://www.maithean.com/docs/set_bk3.pdf
1798
+ case '2.23.42.7.0': // id-set-hashedRootKey
1799
+ return true;
1800
+
1801
+ // CSR attributes
1802
+ case 'pkcs-9-at-unstructuredName':
1803
+ return $this->PKCS9String;
1804
+ case 'pkcs-9-at-challengePassword':
1805
+ return $this->DirectoryString;
1806
+ case 'pkcs-9-at-extensionRequest':
1807
+ return $this->Extensions;
1808
+
1809
+ // CRL extensions.
1810
+ case 'id-ce-cRLNumber':
1811
+ return $this->CRLNumber;
1812
+ case 'id-ce-deltaCRLIndicator':
1813
+ return $this->CRLNumber;
1814
+ case 'id-ce-issuingDistributionPoint':
1815
+ return $this->IssuingDistributionPoint;
1816
+ case 'id-ce-freshestCRL':
1817
+ return $this->CRLDistributionPoints;
1818
+ case 'id-ce-cRLReasons':
1819
+ return $this->CRLReason;
1820
+ case 'id-ce-invalidityDate':
1821
+ return $this->InvalidityDate;
1822
+ case 'id-ce-certificateIssuer':
1823
+ return $this->CertificateIssuer;
1824
+ case 'id-ce-holdInstructionCode':
1825
+ return $this->HoldInstructionCode;
1826
+ }
1827
+
1828
+ return false;
1829
+ }
1830
+
1831
+ /**
1832
+ * Load an X.509 certificate as a certificate authority
1833
+ *
1834
+ * @param String $cert
1835
+ * @access public
1836
+ * @return Boolean
1837
+ */
1838
+ function loadCA($cert)
1839
+ {
1840
+ $olddn = $this->dn;
1841
+ $oldcert = $this->currentCert;
1842
+ $oldsigsubj = $this->signatureSubject;
1843
+ $oldkeyid = $this->currentKeyIdentifier;
1844
+
1845
+ $cert = $this->loadX509($cert);
1846
+ if (!$cert) {
1847
+ $this->dn = $olddn;
1848
+ $this->currentCert = $oldcert;
1849
+ $this->signatureSubject = $oldsigsubj;
1850
+ $this->currentKeyIdentifier = $oldkeyid;
1851
+
1852
+ return false;
1853
+ }
1854
+
1855
+ /* From RFC5280 "PKIX Certificate and CRL Profile":
1856
+
1857
+ If the keyUsage extension is present, then the subject public key
1858
+ MUST NOT be used to verify signatures on certificates or CRLs unless
1859
+ the corresponding keyCertSign or cRLSign bit is set. */
1860
+ //$keyUsage = $this->getExtension('id-ce-keyUsage');
1861
+ //if ($keyUsage && !in_array('keyCertSign', $keyUsage)) {
1862
+ // return false;
1863
+ //}
1864
+
1865
+ /* From RFC5280 "PKIX Certificate and CRL Profile":
1866
+
1867
+ The cA boolean indicates whether the certified public key may be used
1868
+ to verify certificate signatures. If the cA boolean is not asserted,
1869
+ then the keyCertSign bit in the key usage extension MUST NOT be
1870
+ asserted. If the basic constraints extension is not present in a
1871
+ version 3 certificate, or the extension is present but the cA boolean
1872
+ is not asserted, then the certified public key MUST NOT be used to
1873
+ verify certificate signatures. */
1874
+ //$basicConstraints = $this->getExtension('id-ce-basicConstraints');
1875
+ //if (!$basicConstraints || !$basicConstraints['cA']) {
1876
+ // return false;
1877
+ //}
1878
+
1879
+ $this->CAs[] = $cert;
1880
+
1881
+ $this->dn = $olddn;
1882
+ $this->currentCert = $oldcert;
1883
+ $this->signatureSubject = $oldsigsubj;
1884
+
1885
+ return true;
1886
+ }
1887
+
1888
+ /**
1889
+ * Validate an X.509 certificate against a URL
1890
+ *
1891
+ * From RFC2818 "HTTP over TLS":
1892
+ *
1893
+ * Matching is performed using the matching rules specified by
1894
+ * [RFC2459]. If more than one identity of a given type is present in
1895
+ * the certificate (e.g., more than one dNSName name, a match in any one
1896
+ * of the set is considered acceptable.) Names may contain the wildcard
1897
+ * character * which is considered to match any single domain name
1898
+ * component or component fragment. E.g., *.a.com matches foo.a.com but
1899
+ * not bar.foo.a.com. f*.com matches foo.com but not bar.com.
1900
+ *
1901
+ * @param String $url
1902
+ * @access public
1903
+ * @return Boolean
1904
+ */
1905
+ function validateURL($url)
1906
+ {
1907
+ if (!is_array($this->currentCert) || !isset($this->currentCert['tbsCertificate'])) {
1908
+ return false;
1909
+ }
1910
+
1911
+ $components = parse_url($url);
1912
+ if (!isset($components['host'])) {
1913
+ return false;
1914
+ }
1915
+
1916
+ if ($names = $this->getExtension('id-ce-subjectAltName')) {
1917
+ foreach ($names as $key => $value) {
1918
+ $value = str_replace(array('.', '*'), array('\.', '[^.]*'), $value);
1919
+ switch ($key) {
1920
+ case 'dNSName':
1921
+ /* From RFC2818 "HTTP over TLS":
1922
+
1923
+ If a subjectAltName extension of type dNSName is present, that MUST
1924
+ be used as the identity. Otherwise, the (most specific) Common Name
1925
+ field in the Subject field of the certificate MUST be used. Although
1926
+ the use of the Common Name is existing practice, it is deprecated and
1927
+ Certification Authorities are encouraged to use the dNSName instead. */
1928
+ if (preg_match('#^' . $value . '$#', $components['host'])) {
1929
+ return true;
1930
+ }
1931
+ break;
1932
+ case 'iPAddress':
1933
+ /* From RFC2818 "HTTP over TLS":
1934
+
1935
+ In some cases, the URI is specified as an IP address rather than a
1936
+ hostname. In this case, the iPAddress subjectAltName must be present
1937
+ in the certificate and must exactly match the IP in the URI. */
1938
+ if (preg_match('#(?:\d{1-3}\.){4}#', $components['host'] . '.') && preg_match('#^' . $value . '$#', $components['host'])) {
1939
+ return true;
1940
+ }
1941
+ }
1942
+ }
1943
+ return false;
1944
+ }
1945
+
1946
+ if ($value = $this->getDNProp('id-at-commonName')) {
1947
+ $value = str_replace(array('.', '*'), array('\.', '[^.]*'), $value[0]);
1948
+ return preg_match('#^' . $value . '$#', $components['host']);
1949
+ }
1950
+
1951
+ return false;
1952
+ }
1953
+
1954
+ /**
1955
+ * Validate a date
1956
+ *
1957
+ * If $date isn't defined it is assumed to be the current date.
1958
+ *
1959
+ * @param Integer $date optional
1960
+ * @access public
1961
+ */
1962
+ function validateDate($date = NULL)
1963
+ {
1964
+ if (!is_array($this->currentCert) || !isset($this->currentCert['tbsCertificate'])) {
1965
+ return false;
1966
+ }
1967
+
1968
+ if (!isset($date)) {
1969
+ $date = time();
1970
+ }
1971
+
1972
+ $notBefore = $this->currentCert['tbsCertificate']['validity']['notBefore'];
1973
+ $notBefore = isset($notBefore['generalTime']) ? $notBefore['generalTime'] : $notBefore['utcTime'];
1974
+
1975
+ $notAfter = $this->currentCert['tbsCertificate']['validity']['notAfter'];
1976
+ $notAfter = isset($notAfter['generalTime']) ? $notAfter['generalTime'] : $notAfter['utcTime'];
1977
+
1978
+ switch (true) {
1979
+ case $date < @strtotime($notBefore):
1980
+ case $date > @strtotime($notAfter):
1981
+ return false;
1982
+ }
1983
+
1984
+ return true;
1985
+ }
1986
+
1987
+ /**
1988
+ * Validate a signature
1989
+ *
1990
+ * Works on X.509 certs, CSR's and CRL's.
1991
+ * Returns true if the signature is verified, false if it is not correct or NULL on error
1992
+ *
1993
+ * By default returns false for self-signed certs. Call validateSignature(false) to make this support
1994
+ * self-signed.
1995
+ *
1996
+ * The behavior of this function is inspired by {@link http://php.net/openssl-verify openssl_verify}.
1997
+ *
1998
+ * @param Boolean $caonly optional
1999
+ * @access public
2000
+ * @return Mixed
2001
+ */
2002
+ function validateSignature($caonly = true)
2003
+ {
2004
+ if (!is_array($this->currentCert) || !isset($this->signatureSubject)) {
2005
+ return 0;
2006
+ }
2007
+
2008
+ /* TODO:
2009
+ "emailAddress attribute values are not case-sensitive (e.g., "subscriber@example.com" is the same as "SUBSCRIBER@EXAMPLE.COM")."
2010
+ -- http://tools.ietf.org/html/rfc5280#section-4.1.2.6
2011
+
2012
+ implement pathLenConstraint in the id-ce-basicConstraints extension */
2013
+
2014
+ switch (true) {
2015
+ case isset($this->currentCert['tbsCertificate']):
2016
+ // self-signed cert
2017
+ if ($this->currentCert['tbsCertificate']['issuer'] === $this->currentCert['tbsCertificate']['subject']) {
2018
+ $authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier');
2019
+ $subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier');
2020
+ switch (true) {
2021
+ case !is_array($authorityKey):
2022
+ case is_array($authorityKey) && isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
2023
+ $signingCert = $this->currentCert; // working cert
2024
+ }
2025
+ }
2026
+
2027
+ if (!empty($this->CAs)) {
2028
+ for ($i = 0; $i < count($this->CAs); $i++) {
2029
+ // even if the cert is a self-signed one we still want to see if it's a CA;
2030
+ // if not, we'll conditionally return an error
2031
+ $ca = $this->CAs[$i];
2032
+ if ($this->currentCert['tbsCertificate']['issuer'] === $ca['tbsCertificate']['subject']) {
2033
+ $authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier');
2034
+ $subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier', $ca);
2035
+ switch (true) {
2036
+ case !is_array($authorityKey):
2037
+ case is_array($authorityKey) && isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
2038
+ $signingCert = $ca; // working cert
2039
+ break 2;
2040
+ }
2041
+ }
2042
+ }
2043
+ if (count($this->CAs) == $i && $caonly) {
2044
+ return false;
2045
+ }
2046
+ } elseif (!isset($signingCert) || $caonly) {
2047
+ return false;
2048
+ }
2049
+ return $this->_validateSignature(
2050
+ $signingCert['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['algorithm'],
2051
+ $signingCert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'],
2052
+ $this->currentCert['signatureAlgorithm']['algorithm'],
2053
+ substr(base64_decode($this->currentCert['signature']), 1),
2054
+ $this->signatureSubject
2055
+ );
2056
+ case isset($this->currentCert['certificationRequestInfo']):
2057
+ return $this->_validateSignature(
2058
+ $this->currentCert['certificationRequestInfo']['subjectPKInfo']['algorithm']['algorithm'],
2059
+ $this->currentCert['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'],
2060
+ $this->currentCert['signatureAlgorithm']['algorithm'],
2061
+ substr(base64_decode($this->currentCert['signature']), 1),
2062
+ $this->signatureSubject
2063
+ );
2064
+ case isset($this->currentCert['publicKeyAndChallenge']):
2065
+ return $this->_validateSignature(
2066
+ $this->currentCert['publicKeyAndChallenge']['spki']['algorithm']['algorithm'],
2067
+ $this->currentCert['publicKeyAndChallenge']['spki']['subjectPublicKey'],
2068
+ $this->currentCert['signatureAlgorithm']['algorithm'],
2069
+ substr(base64_decode($this->currentCert['signature']), 1),
2070
+ $this->signatureSubject
2071
+ );
2072
+ case isset($this->currentCert['tbsCertList']):
2073
+ if (!empty($this->CAs)) {
2074
+ for ($i = 0; $i < count($this->CAs); $i++) {
2075
+ $ca = $this->CAs[$i];
2076
+ if ($this->currentCert['tbsCertList']['issuer'] === $ca['tbsCertificate']['subject']) {
2077
+ $authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier');
2078
+ $subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier', $ca);
2079
+ switch (true) {
2080
+ case !is_array($authorityKey):
2081
+ case is_array($authorityKey) && isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
2082
+ $signingCert = $ca; // working cert
2083
+ break 2;
2084
+ }
2085
+ }
2086
+ }
2087
+ }
2088
+ if (!isset($signingCert)) {
2089
+ return false;
2090
+ }
2091
+ return $this->_validateSignature(
2092
+ $signingCert['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['algorithm'],
2093
+ $signingCert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'],
2094
+ $this->currentCert['signatureAlgorithm']['algorithm'],
2095
+ substr(base64_decode($this->currentCert['signature']), 1),
2096
+ $this->signatureSubject
2097
+ );
2098
+ default:
2099
+ return false;
2100
+ }
2101
+ }
2102
+
2103
+ /**
2104
+ * Validates a signature
2105
+ *
2106
+ * Returns true if the signature is verified, false if it is not correct or NULL on error
2107
+ *
2108
+ * @param String $publicKeyAlgorithm
2109
+ * @param String $publicKey
2110
+ * @param String $signatureAlgorithm
2111
+ * @param String $signature
2112
+ * @param String $signatureSubject
2113
+ * @access private
2114
+ * @return Integer
2115
+ */
2116
+ function _validateSignature($publicKeyAlgorithm, $publicKey, $signatureAlgorithm, $signature, $signatureSubject)
2117
+ {
2118
+ switch ($publicKeyAlgorithm) {
2119
+ case 'rsaEncryption':
2120
+ if (!class_exists('Crypt_RSA')) {
2121
+ require_once('Crypt/RSA.php');
2122
+ }
2123
+ $rsa = new Crypt_RSA();
2124
+ $rsa->loadKey($publicKey);
2125
+
2126
+ switch ($signatureAlgorithm) {
2127
+ case 'md2WithRSAEncryption':
2128
+ case 'md5WithRSAEncryption':
2129
+ case 'sha1WithRSAEncryption':
2130
+ case 'sha224WithRSAEncryption':
2131
+ case 'sha256WithRSAEncryption':
2132
+ case 'sha384WithRSAEncryption':
2133
+ case 'sha512WithRSAEncryption':
2134
+ $rsa->setHash(preg_replace('#WithRSAEncryption$#', '', $signatureAlgorithm));
2135
+ $rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);
2136
+ if (!@$rsa->verify($signatureSubject, $signature)) {
2137
+ return false;
2138
+ }
2139
+ break;
2140
+ default:
2141
+ return NULL;
2142
+ }
2143
+ break;
2144
+ default:
2145
+ return NULL;
2146
+ }
2147
+
2148
+ return true;
2149
+ }
2150
+
2151
+ /**
2152
+ * Reformat public keys
2153
+ *
2154
+ * Reformats a public key to a format supported by phpseclib (if applicable)
2155
+ *
2156
+ * @param String $algorithm
2157
+ * @param String $key
2158
+ * @access private
2159
+ * @return String
2160
+ */
2161
+ function _reformatKey($algorithm, $key)
2162
+ {
2163
+ switch ($algorithm) {
2164
+ case 'rsaEncryption':
2165
+ return
2166
+ "-----BEGIN PUBLIC KEY-----\r\n" .
2167
+ // subjectPublicKey is stored as a bit string in X.509 certs. the first byte of a bit string represents how many bits
2168
+ // in the last byte should be ignored. the following only supports non-zero stuff but as none of the X.509 certs Firefox
2169
+ // uses as a cert authority actually use a non-zero bit I think it's safe to assume that none do.
2170
+ chunk_split(base64_encode(substr(base64_decode($key), 1)), 64) .
2171
+ '-----END PUBLIC KEY-----';
2172
+ default:
2173
+ return $key;
2174
+ }
2175
+ }
2176
+
2177
+ /**
2178
+ * "Normalizes" a Distinguished Name property
2179
+ *
2180
+ * @param String $propName
2181
+ * @access private
2182
+ * @return Mixed
2183
+ */
2184
+ function _translateDNProp($propName)
2185
+ {
2186
+ switch (strtolower($propName)) {
2187
+ case 'id-at-countryname':
2188
+ case 'countryname':
2189
+ case 'c':
2190
+ return 'id-at-countryName';
2191
+ case 'id-at-organizationname':
2192
+ case 'organizationname':
2193
+ case 'o':
2194
+ return 'id-at-organizationName';
2195
+ case 'id-at-dnqualifier':
2196
+ case 'dnqualifier':
2197
+ return 'id-at-dnQualifier';
2198
+ case 'id-at-commonname':
2199
+ case 'commonname':
2200
+ case 'cn':
2201
+ return 'id-at-commonName';
2202
+ case 'id-at-stateorprovinceName':
2203
+ case 'stateorprovincename':
2204
+ case 'state':
2205
+ case 'province':
2206
+ case 'provincename':
2207
+ case 'st':
2208
+ return 'id-at-stateOrProvinceName';
2209
+ case 'id-at-localityname':
2210
+ case 'localityname':
2211
+ case 'l':
2212
+ return 'id-at-localityName';
2213
+ case 'id-emailaddress':
2214
+ case 'emailaddress':
2215
+ return 'pkcs-9-at-emailAddress';
2216
+ case 'id-at-serialnumber':
2217
+ case 'serialnumber':
2218
+ return 'id-at-serialNumber';
2219
+ case 'id-at-postalcode':
2220
+ case 'postalcode':
2221
+ return 'id-at-postalCode';
2222
+ case 'id-at-streetaddress':
2223
+ case 'streetaddress':
2224
+ return 'id-at-streetAddress';
2225
+ case 'id-at-name':
2226
+ case 'name':
2227
+ return 'id-at-name';
2228
+ case 'id-at-givenname':
2229
+ case 'givenname':
2230
+ return 'id-at-givenName';
2231
+ case 'id-at-surname':
2232
+ case 'surname':
2233
+ case 'sn':
2234
+ return 'id-at-surname';
2235
+ case 'id-at-initials':
2236
+ case 'initials':
2237
+ return 'id-at-initials';
2238
+ case 'id-at-generationqualifier':
2239
+ case 'generationqualifier':
2240
+ return 'id-at-generationQualifier';
2241
+ case 'id-at-organizationalunitname':
2242
+ case 'organizationalunitname':
2243
+ case 'ou':
2244
+ return 'id-at-organizationalUnitName';
2245
+ case 'id-at-pseudonym':
2246
+ case 'pseudonym':
2247
+ return 'id-at-pseudonym';
2248
+ case 'id-at-title':
2249
+ case 'title':
2250
+ return 'id-at-title';
2251
+ case 'id-at-description':
2252
+ case 'description':
2253
+ return 'id-at-description';
2254
+ case 'id-at-role':
2255
+ case 'role':
2256
+ return 'id-at-role';
2257
+ case 'id-at-uniqueidentifier':
2258
+ case 'uniqueidentifier':
2259
+ case 'x500uniqueidentifier':
2260
+ return 'id-at-uniqueIdentifier';
2261
+ default:
2262
+ return false;
2263
+ }
2264
+ }
2265
+
2266
+ /**
2267
+ * Set a Distinguished Name property
2268
+ *
2269
+ * @param String $propName
2270
+ * @param Mixed $propValue
2271
+ * @param String $type optional
2272
+ * @access public
2273
+ * @return Boolean
2274
+ */
2275
+ function setDNProp($propName, $propValue, $type = 'utf8String')
2276
+ {
2277
+ if (empty($this->dn)) {
2278
+ $this->dn = array('rdnSequence' => array());
2279
+ }
2280
+
2281
+ if (($propName = $this->_translateDNProp($propName)) === false) {
2282
+ return false;
2283
+ }
2284
+
2285
+ foreach ((array) $propValue as $v) {
2286
+ if (!is_array($v) && isset($type)) {
2287
+ $v = array($type => $v);
2288
+ }
2289
+ $this->dn['rdnSequence'][] = array(
2290
+ array(
2291
+ 'type' => $propName,
2292
+ 'value'=> $v
2293
+ )
2294
+ );
2295
+ }
2296
+
2297
+ return true;
2298
+ }
2299
+
2300
+ /**
2301
+ * Remove Distinguished Name properties
2302
+ *
2303
+ * @param String $propName
2304
+ * @access public
2305
+ */
2306
+ function removeDNProp($propName)
2307
+ {
2308
+ if (empty($this->dn)) {
2309
+ return;
2310
+ }
2311
+
2312
+ if (($propName = $this->_translateDNProp($propName)) === false) {
2313
+ return;
2314
+ }
2315
+
2316
+ $dn = &$this->dn['rdnSequence'];
2317
+ $size = count($dn);
2318
+ for ($i = 0; $i < $size; $i++) {
2319
+ if ($dn[$i][0]['type'] == $propName) {
2320
+ unset($dn[$i]);
2321
+ }
2322
+ }
2323
+
2324
+ $dn = array_values($dn);
2325
+ }
2326
+
2327
+ /**
2328
+ * Get Distinguished Name properties
2329
+ *
2330
+ * @param String $propName
2331
+ * @param Array $dn optional
2332
+ * @param Boolean $withType optional
2333
+ * @return Mixed
2334
+ * @access public
2335
+ */
2336
+ function getDNProp($propName, $dn = NULL, $withType = false)
2337
+ {
2338
+ if (!isset($dn)) {
2339
+ $dn = $this->dn;
2340
+ }
2341
+
2342
+ if (empty($dn)) {
2343
+ return false;
2344
+ }
2345
+
2346
+ if (($propName = $this->_translateDNProp($propName)) === false) {
2347
+ return false;
2348
+ }
2349
+
2350
+ $dn = $dn['rdnSequence'];
2351
+ $result = array();
2352
+ $asn1 = new File_ASN1();
2353
+ for ($i = 0; $i < count($dn); $i++) {
2354
+ if ($dn[$i][0]['type'] == $propName) {
2355
+ $v = $dn[$i][0]['value'];
2356
+ if (!$withType && is_array($v)) {
2357
+ foreach ($v as $type => $s) {
2358
+ $type = array_search($type, $asn1->ANYmap, true);
2359
+ if ($type !== false && isset($asn1->stringTypeSize[$type])) {
2360
+ $s = $asn1->convert($s, $type);
2361
+ if ($s !== false) {
2362
+ $v = $s;
2363
+ break;
2364
+ }
2365
+ }
2366
+ }
2367
+ if (is_array($v)) {
2368
+ $v = array_pop($v); // Always strip data type.
2369
+ }
2370
+ }
2371
+ $result[] = $v;
2372
+ }
2373
+ }
2374
+
2375
+ return $result;
2376
+ }
2377
+
2378
+ /**
2379
+ * Set a Distinguished Name
2380
+ *
2381
+ * @param Mixed $dn
2382
+ * @param Boolean $merge optional
2383
+ * @param String $type optional
2384
+ * @access public
2385
+ * @return Boolean
2386
+ */
2387
+ function setDN($dn, $merge = false, $type = 'utf8String')
2388
+ {
2389
+ if (!$merge) {
2390
+ $this->dn = NULL;
2391
+ }
2392
+
2393
+ if (is_array($dn)) {
2394
+ if (isset($dn['rdnSequence'])) {
2395
+ $this->dn = $dn; // No merge here.
2396
+ return true;
2397
+ }
2398
+
2399
+ // handles stuff generated by openssl_x509_parse()
2400
+ foreach ($dn as $prop => $value) {
2401
+ if (!$this->setDNProp($prop, $value, $type)) {
2402
+ return false;
2403
+ }
2404
+ }
2405
+ return true;
2406
+ }
2407
+
2408
+ // handles everything else
2409
+ $results = preg_split('#((?:^|, *|/)(?:C=|O=|OU=|CN=|L=|ST=|SN=|postalCode=|streetAddress=|emailAddress=|serialNumber=|organizationalUnitName=|title=|description=|role=|x500UniqueIdentifier=))#', $dn, -1, PREG_SPLIT_DELIM_CAPTURE);
2410
+ for ($i = 1; $i < count($results); $i+=2) {
2411
+ $prop = trim($results[$i], ', =/');
2412
+ $value = $results[$i + 1];
2413
+ if (!$this->setDNProp($prop, $value, $type)) {
2414
+ return false;
2415
+ }
2416
+ }
2417
+
2418
+ return true;
2419
+ }
2420
+
2421
+ /**
2422
+ * Get the Distinguished Name for a certificates subject
2423
+ *
2424
+ * @param Mixed $format optional
2425
+ * @param Array $dn optional
2426
+ * @access public
2427
+ * @return Boolean
2428
+ */
2429
+ function getDN($format = FILE_X509_DN_ARRAY, $dn = NULL)
2430
+ {
2431
+ if (!isset($dn)) {
2432
+ $dn = isset($this->currentCert['tbsCertList']) ? $this->currentCert['tbsCertList']['issuer'] : $this->dn;
2433
+ }
2434
+
2435
+ switch ((int) $format) {
2436
+ case FILE_X509_DN_ARRAY:
2437
+ return $dn;
2438
+ case FILE_X509_DN_ASN1:
2439
+ $asn1 = new File_ASN1();
2440
+ $asn1->loadOIDs($this->oids);
2441
+ $filters = array();
2442
+ $filters['rdnSequence']['value'] = array('type' => FILE_ASN1_TYPE_UTF8_STRING);
2443
+ $asn1->loadFilters($filters);
2444
+ return $asn1->encodeDER($dn, $this->Name);
2445
+ case FILE_X509_DN_OPENSSL:
2446
+ $dn = $this->getDN(FILE_X509_DN_STRING, $dn);
2447
+ if ($dn === false) {
2448
+ return false;
2449
+ }
2450
+ $attrs = preg_split('#((?:^|, *|/)[a-z][a-z0-9]*=)#i', $dn, -1, PREG_SPLIT_DELIM_CAPTURE);
2451
+ $dn = array();
2452
+ for ($i = 1; $i < count($attrs); $i += 2) {
2453
+ $prop = trim($attrs[$i], ', =/');
2454
+ $value = $attrs[$i + 1];
2455
+ if (!isset($dn[$prop])) {
2456
+ $dn[$prop] = $value;
2457
+ } else {
2458
+ $dn[$prop] = array_merge((array) $dn[$prop], array($value));
2459
+ }
2460
+ }
2461
+ return $dn;
2462
+ case FILE_X509_DN_CANON:
2463
+ // No SEQUENCE around RDNs and all string values normalized as
2464
+ // trimmed lowercase UTF-8 with all spacing as one blank.
2465
+ $asn1 = new File_ASN1();
2466
+ $asn1->loadOIDs($this->oids);
2467
+ $filters = array();
2468
+ $filters['value'] = array('type' => FILE_ASN1_TYPE_UTF8_STRING);
2469
+ $asn1->loadFilters($filters);
2470
+ $result = '';
2471
+ foreach ($dn['rdnSequence'] as $rdn) {
2472
+ foreach ($rdn as &$attr) {
2473
+ if (is_array($attr['value'])) {
2474
+ foreach ($attr['value'] as $type => $v) {
2475
+ $type = array_search($type, $asn1->ANYmap, true);
2476
+ if ($type !== false && isset($asn1->stringTypeSize[$type])) {
2477
+ $v = $asn1->convert($v, $type);
2478
+ if ($v !== false) {
2479
+ $v = preg_replace('/\s+/', ' ', $v);
2480
+ $attr['value'] = strtolower(trim($v));
2481
+ break;
2482
+ }
2483
+ }
2484
+ }
2485
+ }
2486
+ }
2487
+ $result .= $asn1->encodeDER($rdn, $this->RelativeDistinguishedName);
2488
+ }
2489
+ return $result;
2490
+ case FILE_X509_DN_HASH:
2491
+ $dn = $this->getDN(FILE_X509_DN_CANON, $dn);
2492
+ if (!class_exists('Crypt_Hash')) {
2493
+ require_once('Crypt/Hash.php');
2494
+ }
2495
+ $hash = new Crypt_Hash('sha1');
2496
+ $hash = $hash->hash($dn);
2497
+ extract(unpack('Vhash', $hash));
2498
+ return strtolower(bin2hex(pack('N', $hash)));
2499
+ }
2500
+
2501
+ // Defaut is to return a string.
2502
+ $start = true;
2503
+ $output = '';
2504
+ $asn1 = new File_ASN1();
2505
+ foreach ($dn['rdnSequence'] as $field) {
2506
+ $prop = $field[0]['type'];
2507
+ $value = $field[0]['value'];
2508
+
2509
+ $delim = ', ';
2510
+ switch ($prop) {
2511
+ case 'id-at-countryName':
2512
+ $desc = 'C=';
2513
+ break;
2514
+ case 'id-at-stateOrProvinceName':
2515
+ $desc = 'ST=';
2516
+ break;
2517
+ case 'id-at-organizationName':
2518
+ $desc = 'O=';
2519
+ break;
2520
+ case 'id-at-organizationalUnitName':
2521
+ $desc = 'OU=';
2522
+ break;
2523
+ case 'id-at-commonName':
2524
+ $desc = 'CN=';
2525
+ break;
2526
+ case 'id-at-localityName':
2527
+ $desc = 'L=';
2528
+ break;
2529
+ case 'id-at-surname':
2530
+ $desc = 'SN=';
2531
+ break;
2532
+ case 'id-at-uniqueIdentifier':
2533
+ $delim = '/';
2534
+ $desc = 'x500UniqueIdentifier=';
2535
+ break;
2536
+ default:
2537
+ $delim = '/';
2538
+ $desc = preg_replace('#.+-([^-]+)$#', '$1', $prop) . '=';
2539
+ }
2540
+
2541
+ if (!$start) {
2542
+ $output.= $delim;
2543
+ }
2544
+ if (is_array($value)) {
2545
+ foreach ($value as $type => $v) {
2546
+ $type = array_search($type, $asn1->ANYmap, true);
2547
+ if ($type !== false && isset($asn1->stringTypeSize[$type])) {
2548
+ $v = $asn1->convert($v, $type);
2549
+ if ($v !== false) {
2550
+ $value = $v;
2551
+ break;
2552
+ }
2553
+ }
2554
+ }
2555
+ if (is_array($value)) {
2556
+ $value = array_pop($value); // Always strip data type.
2557
+ }
2558
+ }
2559
+ $output.= $desc . $value;
2560
+ $start = false;
2561
+ }
2562
+
2563
+ return $output;
2564
+ }
2565
+
2566
+ /**
2567
+ * Get the Distinguished Name for a certificate/crl issuer
2568
+ *
2569
+ * @param Integer $format optional
2570
+ * @access public
2571
+ * @return Mixed
2572
+ */
2573
+ function getIssuerDN($format = FILE_X509_DN_ARRAY)
2574
+ {
2575
+ switch (true) {
2576
+ case !isset($this->currentCert) || !is_array($this->currentCert):
2577
+ break;
2578
+ case isset($this->currentCert['tbsCertificate']):
2579
+ return $this->getDN($format, $this->currentCert['tbsCertificate']['issuer']);
2580
+ case isset($this->currentCert['tbsCertList']):
2581
+ return $this->getDN($format, $this->currentCert['tbsCertList']['issuer']);
2582
+ }
2583
+
2584
+ return false;
2585
+ }
2586
+
2587
+ /**
2588
+ * Get the Distinguished Name for a certificate/csr subject
2589
+ * Alias of getDN()
2590
+ *
2591
+ * @param Integer $format optional
2592
+ * @access public
2593
+ * @return Mixed
2594
+ */
2595
+ function getSubjectDN($format = FILE_X509_DN_ARRAY)
2596
+ {
2597
+ switch (true) {
2598
+ case !empty($this->dn):
2599
+ return $this->getDN($format);
2600
+ case !isset($this->currentCert) || !is_array($this->currentCert):
2601
+ break;
2602
+ case isset($this->currentCert['tbsCertificate']):
2603
+ return $this->getDN($format, $this->currentCert['tbsCertificate']['subject']);
2604
+ case isset($this->currentCert['certificationRequestInfo']):
2605
+ return $this->getDN($format, $this->currentCert['certificationRequestInfo']['subject']);
2606
+ }
2607
+
2608
+ return false;
2609
+ }
2610
+
2611
+ /**
2612
+ * Get an individual Distinguished Name property for a certificate/crl issuer
2613
+ *
2614
+ * @param String $propName
2615
+ * @param Boolean $withType optional
2616
+ * @access public
2617
+ * @return Mixed
2618
+ */
2619
+ function getIssuerDNProp($propName, $withType = false)
2620
+ {
2621
+ switch (true) {
2622
+ case !isset($this->currentCert) || !is_array($this->currentCert):
2623
+ break;
2624
+ case isset($this->currentCert['tbsCertificate']):
2625
+ return $this->getDNProp($propName, $this->currentCert['tbsCertificate']['issuer'], $withType);
2626
+ case isset($this->currentCert['tbsCertList']):
2627
+ return $this->getDNProp($propName, $this->currentCert['tbsCertList']['issuer'], $withType);
2628
+ }
2629
+
2630
+ return false;
2631
+ }
2632
+
2633
+ /**
2634
+ * Get an individual Distinguished Name property for a certificate/csr subject
2635
+ *
2636
+ * @param String $propName
2637
+ * @param Boolean $withType optional
2638
+ * @access public
2639
+ * @return Mixed
2640
+ */
2641
+ function getSubjectDNProp($propName, $withType = false)
2642
+ {
2643
+ switch (true) {
2644
+ case !empty($this->dn):
2645
+ return $this->getDNProp($propName, NULL, $withType);
2646
+ case !isset($this->currentCert) || !is_array($this->currentCert):
2647
+ break;
2648
+ case isset($this->currentCert['tbsCertificate']):
2649
+ return $this->getDNProp($propName, $this->currentCert['tbsCertificate']['subject'], $withType);
2650
+ case isset($this->currentCert['certificationRequestInfo']):
2651
+ return $this->getDNProp($propName, $this->currentCert['certificationRequestInfo']['subject'], $withType);
2652
+ }
2653
+
2654
+ return false;
2655
+ }
2656
+
2657
+ /**
2658
+ * Get the certificate chain for the current cert
2659
+ *
2660
+ * @access public
2661
+ * @return Mixed
2662
+ */
2663
+ function getChain()
2664
+ {
2665
+ $chain = array($this->currentCert);
2666
+
2667
+ if (!is_array($this->currentCert) || !isset($this->currentCert['tbsCertificate'])) {
2668
+ return false;
2669
+ }
2670
+ if (empty($this->CAs)) {
2671
+ return $chain;
2672
+ }
2673
+ while (true) {
2674
+ $currentCert = $chain[count($chain) - 1];
2675
+ for ($i = 0; $i < count($this->CAs); $i++) {
2676
+ $ca = $this->CAs[$i];
2677
+ if ($currentCert['tbsCertificate']['issuer'] === $ca['tbsCertificate']['subject']) {
2678
+ $authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier', $currentCert);
2679
+ $subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier', $ca);
2680
+ switch (true) {
2681
+ case !is_array($authorityKey):
2682
+ case is_array($authorityKey) && isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
2683
+ if ($currentCert === $ca) {
2684
+ break 3;
2685
+ }
2686
+ $chain[] = $ca;
2687
+ break 2;
2688
+ }
2689
+ }
2690
+ }
2691
+ if ($i == count($this->CAs)) {
2692
+ break;
2693
+ }
2694
+ }
2695
+ foreach ($chain as $key=>$value) {
2696
+ $chain[$key] = new File_X509();
2697
+ $chain[$key]->loadX509($value);
2698
+ }
2699
+ return $chain;
2700
+ }
2701
+
2702
+ /**
2703
+ * Set public key
2704
+ *
2705
+ * Key needs to be a Crypt_RSA object
2706
+ *
2707
+ * @param Object $key
2708
+ * @access public
2709
+ * @return Boolean
2710
+ */
2711
+ function setPublicKey($key)
2712
+ {
2713
+ $this->publicKey = $key;
2714
+ }
2715
+
2716
+ /**
2717
+ * Set private key
2718
+ *
2719
+ * Key needs to be a Crypt_RSA object
2720
+ *
2721
+ * @param Object $key
2722
+ * @access public
2723
+ */
2724
+ function setPrivateKey($key)
2725
+ {
2726
+ $this->privateKey = $key;
2727
+ }
2728
+
2729
+ /**
2730
+ * Gets the public key
2731
+ *
2732
+ * Returns a Crypt_RSA object or a false.
2733
+ *
2734
+ * @access public
2735
+ * @return Mixed
2736
+ */
2737
+ function getPublicKey()
2738
+ {
2739
+ if (isset($this->publicKey)) {
2740
+ return $this->publicKey;
2741
+ }
2742
+
2743
+ if (isset($this->currentCert) && is_array($this->currentCert)) {
2744
+ foreach (array('tbsCertificate/subjectPublicKeyInfo', 'certificationRequestInfo/subjectPKInfo') as $path) {
2745
+ $keyinfo = $this->_subArray($this->currentCert, $path);
2746
+ if (!empty($keyinfo)) {
2747
+ break;
2748
+ }
2749
+ }
2750
+ }
2751
+ if (empty($keyinfo)) {
2752
+ return false;
2753
+ }
2754
+
2755
+ $key = $keyinfo['subjectPublicKey'];
2756
+
2757
+ switch ($keyinfo['algorithm']['algorithm']) {
2758
+ case 'rsaEncryption':
2759
+ if (!class_exists('Crypt_RSA')) {
2760
+ require_once('Crypt/RSA.php');
2761
+ }
2762
+ $publicKey = new Crypt_RSA();
2763
+ $publicKey->loadKey($key);
2764
+ $publicKey->setPublicKey();
2765
+ break;
2766
+ default:
2767
+ return false;
2768
+ }
2769
+
2770
+ return $publicKey;
2771
+ }
2772
+
2773
+ /**
2774
+ * Load a Certificate Signing Request
2775
+ *
2776
+ * @param String $csr
2777
+ * @access public
2778
+ * @return Mixed
2779
+ */
2780
+ function loadCSR($csr)
2781
+ {
2782
+ if (is_array($csr) && isset($csr['certificationRequestInfo'])) {
2783
+ unset($this->currentCert);
2784
+ unset($this->currentKeyIdentifier);
2785
+ unset($this->signatureSubject);
2786
+ $this->dn = $csr['certificationRequestInfo']['subject'];
2787
+ if (!isset($this->dn)) {
2788
+ return false;
2789
+ }
2790
+
2791
+ $this->currentCert = $csr;
2792
+ return $csr;
2793
+ }
2794
+
2795
+ // see http://tools.ietf.org/html/rfc2986
2796
+
2797
+ $asn1 = new File_ASN1();
2798
+
2799
+ $csr = $this->_extractBER($csr);
2800
+ $orig = $csr;
2801
+
2802
+ if ($csr === false) {
2803
+ $this->currentCert = false;
2804
+ return false;
2805
+ }
2806
+
2807
+ $asn1->loadOIDs($this->oids);
2808
+ $decoded = $asn1->decodeBER($csr);
2809
+
2810
+ if (empty($decoded)) {
2811
+ $this->currentCert = false;
2812
+ return false;
2813
+ }
2814
+
2815
+ $csr = $asn1->asn1map($decoded[0], $this->CertificationRequest);
2816
+ if (!isset($csr) || $csr === false) {
2817
+ $this->currentCert = false;
2818
+ return false;
2819
+ }
2820
+
2821
+ $this->dn = $csr['certificationRequestInfo']['subject'];
2822
+ $this->_mapInAttributes($csr, 'certificationRequestInfo/attributes', $asn1);
2823
+
2824
+ $this->signatureSubject = substr($orig, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']);
2825
+
2826
+ $algorithm = &$csr['certificationRequestInfo']['subjectPKInfo']['algorithm']['algorithm'];
2827
+ $key = &$csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'];
2828
+ $key = $this->_reformatKey($algorithm, $key);
2829
+
2830
+ switch ($algorithm) {
2831
+ case 'rsaEncryption':
2832
+ if (!class_exists('Crypt_RSA')) {
2833
+ require_once('Crypt/RSA.php');
2834
+ }
2835
+ $this->publicKey = new Crypt_RSA();
2836
+ $this->publicKey->loadKey($key);
2837
+ $this->publicKey->setPublicKey();
2838
+ break;
2839
+ default:
2840
+ $this->publicKey = NULL;
2841
+ }
2842
+
2843
+ $this->currentKeyIdentifier = NULL;
2844
+ $this->currentCert = $csr;
2845
+
2846
+ return $csr;
2847
+ }
2848
+
2849
+ /**
2850
+ * Save CSR request
2851
+ *
2852
+ * @param Array $csr
2853
+ * @param Integer $format optional
2854
+ * @access public
2855
+ * @return String
2856
+ */
2857
+ function saveCSR($csr, $format = FILE_X509_FORMAT_PEM)
2858
+ {
2859
+ if (!is_array($csr) || !isset($csr['certificationRequestInfo'])) {
2860
+ return false;
2861
+ }
2862
+
2863
+ switch (true) {
2864
+ case !($algorithm = $this->_subArray($csr, 'certificationRequestInfo/subjectPKInfo/algorithm/algorithm')):
2865
+ case is_object($csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey']);
2866
+ break;
2867
+ default:
2868
+ switch ($algorithm) {
2869
+ case 'rsaEncryption':
2870
+ $csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'] =
2871
+ base64_encode("\0" . base64_decode(preg_replace('#-.+-|[\r\n]#', '', $csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'])));
2872
+ }
2873
+ }
2874
+
2875
+ $asn1 = new File_ASN1();
2876
+
2877
+ $asn1->loadOIDs($this->oids);
2878
+
2879
+ $filters = array();
2880
+ $filters['certificationRequestInfo']['subject']['rdnSequence']['value'] =
2881
+ array('type' => FILE_ASN1_TYPE_UTF8_STRING);
2882
+
2883
+ $asn1->loadFilters($filters);
2884
+
2885
+ $this->_mapOutAttributes($csr, 'certificationRequestInfo/attributes', $asn1);
2886
+ $csr = $asn1->encodeDER($csr, $this->CertificationRequest);
2887
+
2888
+ switch ($format) {
2889
+ case FILE_X509_FORMAT_DER:
2890
+ return $csr;
2891
+ // case FILE_X509_FORMAT_PEM:
2892
+ default:
2893
+ return "-----BEGIN CERTIFICATE REQUEST-----\r\n" . chunk_split(base64_encode($csr), 64) . '-----END CERTIFICATE REQUEST-----';
2894
+ }
2895
+ }
2896
+
2897
+ /**
2898
+ * Load a SPKAC CSR
2899
+ *
2900
+ * SPKAC's are produced by the HTML5 keygen element:
2901
+ *
2902
+ * https://developer.mozilla.org/en-US/docs/HTML/Element/keygen
2903
+ *
2904
+ * @param String $csr
2905
+ * @access public
2906
+ * @return Mixed
2907
+ */
2908
+ function loadSPKAC($csr)
2909
+ {
2910
+ if (is_array($csr) && isset($csr['publicKeyAndChallenge'])) {
2911
+ unset($this->currentCert);
2912
+ unset($this->currentKeyIdentifier);
2913
+ unset($this->signatureSubject);
2914
+ $this->currentCert = $csr;
2915
+ return $csr;
2916
+ }
2917
+
2918
+ // see http://www.w3.org/html/wg/drafts/html/master/forms.html#signedpublickeyandchallenge
2919
+
2920
+ $asn1 = new File_ASN1();
2921
+
2922
+ $temp = preg_replace('#(?:^[^=]+=)|[\r\n\\\]#', '', $csr);
2923
+ $temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? base64_decode($temp) : false;
2924
+ if ($temp != false) {
2925
+ $csr = $temp;
2926
+ }
2927
+ $orig = $csr;
2928
+
2929
+ if ($csr === false) {
2930
+ $this->currentCert = false;
2931
+ return false;
2932
+ }
2933
+
2934
+ $asn1->loadOIDs($this->oids);
2935
+ $decoded = $asn1->decodeBER($csr);
2936
+
2937
+ if (empty($decoded)) {
2938
+ $this->currentCert = false;
2939
+ return false;
2940
+ }
2941
+
2942
+ $csr = $asn1->asn1map($decoded[0], $this->SignedPublicKeyAndChallenge);
2943
+
2944
+ if (!isset($csr) || $csr === false) {
2945
+ $this->currentCert = false;
2946
+ return false;
2947
+ }
2948
+
2949
+ $this->signatureSubject = substr($orig, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']);
2950
+
2951
+ $algorithm = &$csr['publicKeyAndChallenge']['spki']['algorithm']['algorithm'];
2952
+ $key = &$csr['publicKeyAndChallenge']['spki']['subjectPublicKey'];
2953
+ $key = $this->_reformatKey($algorithm, $key);
2954
+
2955
+ switch ($algorithm) {
2956
+ case 'rsaEncryption':
2957
+ if (!class_exists('Crypt_RSA')) {
2958
+ require_once('Crypt/RSA.php');
2959
+ }
2960
+ $this->publicKey = new Crypt_RSA();
2961
+ $this->publicKey->loadKey($key);
2962
+ $this->publicKey->setPublicKey();
2963
+ break;
2964
+ default:
2965
+ $this->publicKey = NULL;
2966
+ }
2967
+
2968
+ $this->currentKeyIdentifier = NULL;
2969
+ $this->currentCert = $csr;
2970
+
2971
+ return $csr;
2972
+ }
2973
+
2974
+ /**
2975
+ * Load a Certificate Revocation List
2976
+ *
2977
+ * @param String $crl
2978
+ * @access public
2979
+ * @return Mixed
2980
+ */
2981
+ function loadCRL($crl)
2982
+ {
2983
+ if (is_array($crl) && isset($crl['tbsCertList'])) {
2984
+ $this->currentCert = $crl;
2985
+ unset($this->signatureSubject);
2986
+ return $crl;
2987
+ }
2988
+
2989
+ $asn1 = new File_ASN1();
2990
+
2991
+ $crl = $this->_extractBER($crl);
2992
+ $orig = $crl;
2993
+
2994
+ if ($crl === false) {
2995
+ $this->currentCert = false;
2996
+ return false;
2997
+ }
2998
+
2999
+ $asn1->loadOIDs($this->oids);
3000
+ $decoded = $asn1->decodeBER($crl);
3001
+
3002
+ if (empty($decoded)) {
3003
+ $this->currentCert = false;
3004
+ return false;
3005
+ }
3006
+
3007
+ $crl = $asn1->asn1map($decoded[0], $this->CertificateList);
3008
+ if (!isset($crl) || $crl === false) {
3009
+ $this->currentCert = false;
3010
+ return false;
3011
+ }
3012
+
3013
+ $this->signatureSubject = substr($orig, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']);
3014
+
3015
+ $this->_mapInExtensions($crl, 'tbsCertList/crlExtensions', $asn1);
3016
+ $rclist = &$this->_subArray($crl,'tbsCertList/revokedCertificates');
3017
+ if (is_array($rclist)) {
3018
+ foreach ($rclist as $i => $extension) {
3019
+ $this->_mapInExtensions($rclist, "$i/crlEntryExtensions", $asn1);
3020
+ }
3021
+ }
3022
+
3023
+ $this->currentKeyIdentifier = NULL;
3024
+ $this->currentCert = $crl;
3025
+
3026
+ return $crl;
3027
+ }
3028
+
3029
+ /**
3030
+ * Save Certificate Revocation List.
3031
+ *
3032
+ * @param Array $crl
3033
+ * @param Integer $format optional
3034
+ * @access public
3035
+ * @return String
3036
+ */
3037
+ function saveCRL($crl, $format = FILE_X509_FORMAT_PEM)
3038
+ {
3039
+ if (!is_array($crl) || !isset($crl['tbsCertList'])) {
3040
+ return false;
3041
+ }
3042
+
3043
+ $asn1 = new File_ASN1();
3044
+
3045
+ $asn1->loadOIDs($this->oids);
3046
+
3047
+ $filters = array();
3048
+ $filters['tbsCertList']['issuer']['rdnSequence']['value'] =
3049
+ $filters['tbsCertList']['signature']['parameters'] =
3050
+ $filters['signatureAlgorithm']['parameters'] =
3051
+ array('type' => FILE_ASN1_TYPE_UTF8_STRING);
3052
+
3053
+ if (empty($crl['tbsCertList']['signature']['parameters'])) {
3054
+ $filters['tbsCertList']['signature']['parameters'] =
3055
+ array('type' => FILE_ASN1_TYPE_NULL);
3056
+ }
3057
+
3058
+ if (empty($crl['signatureAlgorithm']['parameters'])) {
3059
+ $filters['signatureAlgorithm']['parameters'] =
3060
+ array('type' => FILE_ASN1_TYPE_NULL);
3061
+ }
3062
+
3063
+ $asn1->loadFilters($filters);
3064
+
3065
+ $this->_mapOutExtensions($crl, 'tbsCertList/crlExtensions', $asn1);
3066
+ $rclist = &$this->_subArray($crl,'tbsCertList/revokedCertificates');
3067
+ if (is_array($rclist)) {
3068
+ foreach ($rclist as $i => $extension) {
3069
+ $this->_mapOutExtensions($rclist, "$i/crlEntryExtensions", $asn1);
3070
+ }
3071
+ }
3072
+
3073
+ $crl = $asn1->encodeDER($crl, $this->CertificateList);
3074
+
3075
+ switch ($format) {
3076
+ case FILE_X509_FORMAT_DER:
3077
+ return $crl;
3078
+ // case FILE_X509_FORMAT_PEM:
3079
+ default:
3080
+ return "-----BEGIN X509 CRL-----\r\n" . chunk_split(base64_encode($crl), 64) . '-----END X509 CRL-----';
3081
+ }
3082
+ }
3083
+
3084
+ /**
3085
+ * Sign an X.509 certificate
3086
+ *
3087
+ * $issuer's private key needs to be loaded.
3088
+ * $subject can be either an existing X.509 cert (if you want to resign it),
3089
+ * a CSR or something with the DN and public key explicitly set.
3090
+ *
3091
+ * @param File_X509 $issuer
3092
+ * @param File_X509 $subject
3093
+ * @param String $signatureAlgorithm optional
3094
+ * @access public
3095
+ * @return Mixed
3096
+ */
3097
+ function sign($issuer, $subject, $signatureAlgorithm = 'sha1WithRSAEncryption')
3098
+ {
3099
+ if (!is_object($issuer->privateKey) || empty($issuer->dn)) {
3100
+ return false;
3101
+ }
3102
+
3103
+ if (isset($subject->publicKey) && !($subjectPublicKey = $subject->_formatSubjectPublicKey())) {
3104
+ return false;
3105
+ }
3106
+
3107
+ $currentCert = isset($this->currentCert) ? $this->currentCert : NULL;
3108
+ $signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject: NULL;
3109
+
3110
+ if (isset($subject->currentCert) && is_array($subject->currentCert) && isset($subject->currentCert['tbsCertificate'])) {
3111
+ $this->currentCert = $subject->currentCert;
3112
+ $this->currentCert['tbsCertificate']['signature']['algorithm'] =
3113
+ $this->currentCert['signatureAlgorithm']['algorithm'] =
3114
+ $signatureAlgorithm;
3115
+ if (!empty($this->startDate)) {
3116
+ $this->currentCert['tbsCertificate']['validity']['notBefore']['generalTime'] = $this->startDate;
3117
+ unset($this->currentCert['tbsCertificate']['validity']['notBefore']['utcTime']);
3118
+ }
3119
+ if (!empty($this->endDate)) {
3120
+ $this->currentCert['tbsCertificate']['validity']['notAfter']['generalTime'] = $this->endDate;
3121
+ unset($this->currentCert['tbsCertificate']['validity']['notAfter']['utcTime']);
3122
+ }
3123
+ if (!empty($this->serialNumber)) {
3124
+ $this->currentCert['tbsCertificate']['serialNumber'] = $this->serialNumber;
3125
+ }
3126
+ if (!empty($subject->dn)) {
3127
+ $this->currentCert['tbsCertificate']['subject'] = $subject->dn;
3128
+ }
3129
+ if (!empty($subject->publicKey)) {
3130
+ $this->currentCert['tbsCertificate']['subjectPublicKeyInfo'] = $subjectPublicKey;
3131
+ }
3132
+ $this->removeExtension('id-ce-authorityKeyIdentifier');
3133
+ if (isset($subject->domains)) {
3134
+ $this->removeExtension('id-ce-subjectAltName');
3135
+ }
3136
+ } else if (isset($subjec