Migration, Backup, Staging – WPvivid - Version 0.9.9

Version Description

Fixed a packaging error which might cause the failure of activating the plugin.

Download this release

Release Info

Developer wpvivid
Plugin Icon 128x128 Migration, Backup, Staging – WPvivid
Version 0.9.9
Comparing to
See all releases

Code changes from version 0.9.8 to 0.9.9

Files changed (43) hide show
  1. includes/class-wpvivid-setting.php +9 -6
  2. includes/customclass/class-wpvivid-base-dropbox.php +162 -0
  3. includes/customclass/class-wpvivid-dropbox.php +526 -0
  4. includes/customclass/class-wpvivid-google-drive.php +777 -0
  5. includes/customclass/class-wpvivid-one-drive.php +1077 -0
  6. includes/customclass/client_secrets.json +1 -0
  7. includes/lib/google-api-php-client/src/Google/AccessToken/Revoke.php +78 -0
  8. includes/lib/google-api-php-client/src/Google/AccessToken/Verify.php +273 -0
  9. includes/lib/google-api-php-client/src/Google/AuthHandler/AuthHandlerFactory.php +42 -0
  10. includes/lib/google-api-php-client/src/Google/AuthHandler/Guzzle5AuthHandler.php +99 -0
  11. includes/lib/google-api-php-client/src/Google/AuthHandler/Guzzle6AuthHandler.php +106 -0
  12. includes/lib/google-api-php-client/src/Google/Client.php +1128 -0
  13. includes/lib/google-api-php-client/src/Google/Collection.php +100 -0
  14. includes/lib/google-api-php-client/src/Google/Exception.php +20 -0
  15. includes/lib/google-api-php-client/src/Google/Http/Batch.php +249 -0
  16. includes/lib/google-api-php-client/src/Google/Http/MediaFileUpload.php +351 -0
  17. includes/lib/google-api-php-client/src/Google/Http/REST.php +182 -0
  18. includes/lib/google-api-php-client/src/Google/Model.php +317 -0
  19. includes/lib/google-api-php-client/src/Google/Service.php +56 -0
  20. includes/lib/google-api-php-client/src/Google/Service/Exception.php +68 -0
  21. includes/lib/google-api-php-client/src/Google/Service/README.md +5 -0
  22. includes/lib/google-api-php-client/src/Google/Service/Resource.php +302 -0
  23. includes/lib/google-api-php-client/src/Google/Task/Exception.php +20 -0
  24. includes/lib/google-api-php-client/src/Google/Task/Retryable.php +24 -0
  25. includes/lib/google-api-php-client/src/Google/Task/Runner.php +281 -0
  26. includes/lib/google-api-php-client/src/Google/Utils/UriTemplate.php +333 -0
  27. includes/lib/google-api-php-client/src/Google/autoload.php +21 -0
  28. includes/phpseclib/Crypt/AES.php +0 -197
  29. includes/phpseclib/Crypt/Base.php +0 -2611
  30. includes/phpseclib/Crypt/Blowfish.php +0 -671
  31. includes/phpseclib/Crypt/DES.php +0 -1516
  32. includes/phpseclib/Crypt/Hash.php +0 -861
  33. includes/phpseclib/Crypt/RC2.php +0 -761
  34. includes/phpseclib/Crypt/RC4.php +0 -363
  35. includes/phpseclib/Crypt/RSA.php +0 -3133
  36. includes/phpseclib/Crypt/Random.php +0 -334
  37. includes/phpseclib/Crypt/Rijndael.php +0 -1050
  38. includes/phpseclib/Crypt/TripleDES.php +0 -517
  39. includes/phpseclib/Crypt/Twofish.php +0 -881
  40. includes/phpseclib/File/ANSI.php +0 -601
  41. includes/phpseclib/File/ASN1.php +0 -1407
  42. includes/phpseclib/File/X509.php +0 -4884
  43. includes/phpseclib/Math/BigInteger.php +0 -1334
includes/class-wpvivid-setting.php CHANGED
@@ -137,12 +137,15 @@ class WPvivid_Setting
137
 
138
  public static function get_last_backup_message($option_name, $default = array()){
139
  $message = get_option($option_name, $default);
140
- $ret['id']=$message['id'];
141
- $ret['status']=$message['status'];
142
- $ret['status']['start_time']=date("M d, Y H:i",$ret['status']['start_time']);
143
- $ret['status']['run_time']=date("M d, Y H:i",$ret['status']['run_time']);
144
- $ret['status']['timeout']=date("M d, Y H:i",$ret['status']['timeout']);
145
- $ret['log_file_name']=$message['options']['log_file_name'];
 
 
 
146
  return $ret;
147
  }
148
 
137
 
138
  public static function get_last_backup_message($option_name, $default = array()){
139
  $message = get_option($option_name, $default);
140
+ $ret = array();
141
+ if(!empty($message['id'])) {
142
+ $ret['id'] = $message['id'];
143
+ $ret['status'] = $message['status'];
144
+ $ret['status']['start_time'] = date("M d, Y H:i", $ret['status']['start_time']);
145
+ $ret['status']['run_time'] = date("M d, Y H:i", $ret['status']['run_time']);
146
+ $ret['status']['timeout'] = date("M d, Y H:i", $ret['status']['timeout']);
147
+ $ret['log_file_name'] = $message['options']['log_file_name'];
148
+ }
149
  return $ret;
150
  }
151
 
includes/customclass/class-wpvivid-base-dropbox.php ADDED
@@ -0,0 +1,162 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if (!defined('WPVIVID_PLUGIN_DIR')){
3
+ die;
4
+ }
5
+
6
+ class Dropbox_Base{
7
+
8
+ const API_URL_V2 = 'https://api.dropboxapi.com/';
9
+ const CONTENT_URL_V2 = 'https://content.dropboxapi.com/2/';
10
+ const API_ID = 'cwn4z5jg8wy7b4u';
11
+
12
+ private $access_token;
13
+ private $option;
14
+
15
+ public function __construct($option){
16
+ $this -> option = $option;
17
+ $this -> access_token = $option['token'];
18
+ }
19
+
20
+ public function upload($target_path, $file_data, $mode = "add") {
21
+ $endpoint = self::CONTENT_URL_V2."files/upload";
22
+ $headers = array(
23
+ "Content-Type: application/octet-stream",
24
+ "Dropbox-API-Arg: {\"path\": \"$target_path\", \"mode\": \"$mode\"}"
25
+ );
26
+
27
+ if (file_exists($file_data))
28
+ $postdata = file_get_contents($file_data);
29
+ else
30
+ $postdata = $file_data;
31
+
32
+ $returnData = $this ->postRequest($endpoint, $headers, $postdata);
33
+ return $returnData;
34
+ }
35
+
36
+ public function upload_session_start() {
37
+ $endpoint = self::CONTENT_URL_V2."files/upload_session/start";
38
+ $headers = array(
39
+ "Content-Type: application/octet-stream",
40
+ "Dropbox-API-Arg: {\"close\": false}"
41
+ );
42
+ $returnData = $this ->postRequest($endpoint, $headers,null);
43
+ return $returnData;
44
+ }
45
+
46
+ public function upload_session_append_v2($session_id, $offset, $postdata) {
47
+ $endpoint = self::CONTENT_URL_V2."files/upload_session/append_v2";
48
+ $headers = array(
49
+ "Content-Type: application/octet-stream",
50
+ "Dropbox-API-Arg: {\"cursor\": {\"session_id\": \"$session_id\",\"offset\": $offset},\"close\": false}"
51
+ );
52
+
53
+ $returnData = $this ->postRequest($endpoint, $headers, $postdata);
54
+ return $returnData;
55
+ }
56
+
57
+ public function upload_session_finish($session_id, $filesize, $path, $mode = 'add') {
58
+ $endpoint = self::CONTENT_URL_V2."files/upload_session/finish";
59
+ $entry = array(
60
+ 'cursor' => array(
61
+ 'session_id' => $session_id,
62
+ 'offset' => $filesize,
63
+ ),
64
+ 'commit' => array(
65
+ 'path' => $path,
66
+ 'mode' => $mode,
67
+
68
+ ),
69
+ );
70
+ $headers = array(
71
+ "Content-Type: application/octet-stream",
72
+ "Dropbox-API-Arg: " . json_encode($entry),
73
+ );
74
+
75
+ $returnData = $this ->postRequest($endpoint, $headers,null);
76
+ return $returnData;
77
+ }
78
+
79
+ public function download($path,$header = array()) {
80
+ $endpoint = "https://content.dropboxapi.com/2/files/download";
81
+ $headers = array(
82
+ "Content-Type: text/plain; charset=utf-8",
83
+ "Dropbox-API-Arg: {\"path\": \"$path\"}"
84
+ );
85
+ $headers = array_merge ($headers,$header);
86
+ $data = $this ->postRequest($endpoint, $headers,null,false);
87
+ return $data;
88
+ }
89
+
90
+ public function delete($path) {
91
+ $endpoint = self::API_URL_V2."2/files/delete";
92
+ $headers = array(
93
+ "Content-Type: application/json"
94
+ );
95
+ $postdata = json_encode(array( "path" => $path ));
96
+ $returnData = $this -> postRequest($endpoint, $headers, $postdata);
97
+ return $returnData;
98
+ }
99
+
100
+ public function revoke() {
101
+ $endpoint = self::API_URL_V2."2/auth/token/revoke";
102
+ $headers = array();
103
+ $this -> postRequest($endpoint, $headers);
104
+ }
105
+
106
+ public function getUsage(){
107
+ $endpoint = self::API_URL_V2."2/users/get_space_usage";
108
+ $headers = array(
109
+ "Content-Type: application/json"
110
+ );
111
+ $postdata = "null";
112
+ $returnData = $this -> postRequest($endpoint, $headers,$postdata);
113
+ return $returnData;
114
+ }
115
+
116
+ public static function getUrl($url,$state = ''){
117
+ $params = array(
118
+ 'client_id' => self::API_ID,
119
+ 'response_type' => 'code',
120
+ 'redirect_uri' => $url,
121
+ 'state' => $state,
122
+ );
123
+ $url = 'https://www.dropbox.com/oauth2/authorize?';
124
+ $url .= http_build_query($params,'','&');
125
+ return $url;
126
+ }
127
+
128
+ public function postRequest($endpoint, $headers, $data = null,$returnjson = true) {
129
+ $ch = curl_init($endpoint);
130
+ array_push($headers, "Authorization: Bearer " . $this -> access_token);
131
+
132
+ curl_setopt($ch, CURLOPT_POST, TRUE);
133
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
134
+ curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
135
+ curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
136
+
137
+ //todo delete this code
138
+ // curl_setopt($ch,CURLOPT_PROXY, '127.0.0.1:1080');
139
+ $r = curl_exec($ch);
140
+ $chinfo = curl_getinfo($ch);
141
+ $error = curl_error($ch);
142
+ curl_close($ch);
143
+
144
+ if($r === false){
145
+ $r['error_summary'] = $error;
146
+ }else{
147
+ if($chinfo['http_code'] === 401){
148
+ $r = array();
149
+ $r['error_summary'] = 'Invalid or expired token. Please remove '.$this -> option['name'].' from the storage list and re-authenticate it.';
150
+ }elseif($chinfo['http_code'] !== 200 && $chinfo['http_code'] !== 206){
151
+ $r = json_decode($r,true);
152
+ }
153
+ }
154
+ if($returnjson && !is_array($r))
155
+ $r = json_decode($r,true);
156
+
157
+ return $r;
158
+ }
159
+ public function setAccessToken($access_token){
160
+ $this -> access_token = $access_token;
161
+ }
162
+ }
includes/customclass/class-wpvivid-dropbox.php ADDED
@@ -0,0 +1,526 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if (!defined('WPVIVID_PLUGIN_DIR')){
4
+ die;
5
+ }
6
+ if(!defined('WPVIVID_REMOTE_DROPBOX')){
7
+ define('WPVIVID_REMOTE_DROPBOX','dropbox');
8
+ }
9
+ define('WPVIVID_DROPBOX_DEFAULT_FOLDER','wpvivid_backup');
10
+ require_once WPVIVID_PLUGIN_DIR . '/includes/customclass/class-wpvivid-base-dropbox.php';
11
+ require_once WPVIVID_PLUGIN_DIR . '/includes/customclass/class-wpvivid-remote.php';
12
+ class WPvivid_Dropbox extends WPvivid_Remote {
13
+
14
+ private $options;
15
+ private $upload_chunk_size = 2097152;
16
+ private $download_chunk_size = 2097152;
17
+ private $redirect_url = 'https://auth.wpvivid.com/dropbox';
18
+
19
+ public function __construct($options = array())
20
+ {
21
+ if(empty($options)){
22
+ if(!defined('WPVIVID_INIT_STORAGE_TAB_DROPBOX')){
23
+ add_action('init', array($this, 'handle_auth_actions'));
24
+ add_action('wpvivid_delete_remote_token',array($this,'revoke'));
25
+
26
+ add_filter('wpvivid_remote_register', array($this, 'init_remotes'),10);
27
+ add_action('wpvivid_add_storage_tab',array($this,'wpvivid_add_storage_tab_dropbox'), 10);
28
+ add_action('wpvivid_add_storage_page',array($this,'wpvivid_add_storage_page_dropbox'), 10);
29
+ add_action('wpvivid_edit_remote_page',array($this,'wpvivid_edit_storage_page_dropbox'), 10);
30
+ add_filter('wpvivid_remote_pic',array($this,'wpvivid_remote_pic_dropbox'),10);
31
+ add_filter('wpvivid_get_out_of_date_remote',array($this,'wpvivid_get_out_of_date_dropbox'),10,2);
32
+ add_filter('wpvivid_storage_provider_tran',array($this,'wpvivid_storage_provider_dropbox'),10);
33
+
34
+ define('WPVIVID_INIT_STORAGE_TAB_DROPBOX',1);
35
+ }
36
+ }else{
37
+ $this -> options = $options;
38
+ }
39
+ }
40
+
41
+ public function test_connect()
42
+ {
43
+ return array('result' => WPVIVID_SUCCESS);
44
+ }
45
+
46
+ public function sanitize_options($skip_name='')
47
+ {
48
+ $ret['result']=WPVIVID_SUCCESS;
49
+
50
+ if(!isset($this->options['name']))
51
+ {
52
+ $ret['error']="Warning: An alias for remote storage is required.";
53
+ return $ret;
54
+ }
55
+
56
+ $this->options['name']=sanitize_text_field($this->options['name']);
57
+
58
+ if(empty($this->options['name']))
59
+ {
60
+ $ret['error']="Warning: An alias for remote storage is required.";
61
+ return $ret;
62
+ }
63
+
64
+ $remoteslist=WPvivid_Setting::get_all_remote_options();
65
+ foreach ($remoteslist as $key=>$value)
66
+ {
67
+ if(isset($value['name'])&&$value['name'] == $this->options['name']&&$skip_name!=$value['name'])
68
+ {
69
+ $ret['error']="Warning: The alias already exists in storage list.";
70
+ return $ret;
71
+ }
72
+ }
73
+
74
+ $ret['options']=$this->options;
75
+ return $ret;
76
+ }
77
+
78
+ public function upload($task_id, $files, $callback = '')
79
+ {
80
+ global $wpvivid_pulgin;
81
+
82
+ $options = $this -> options;
83
+ $dropbox = new Dropbox_Base($options);
84
+ $upload_job=WPvivid_taskmanager::get_backup_sub_task_progress($task_id,'upload',WPVIVID_REMOTE_DROPBOX);
85
+ if(empty($upload_job))
86
+ {
87
+ $job_data=array();
88
+ foreach ($files as $file)
89
+ {
90
+ $file_data['size']=filesize($file);
91
+ $file_data['uploaded']=0;
92
+ $job_data[basename($file)]=$file_data;
93
+ }
94
+ WPvivid_taskmanager::update_backup_sub_task_progress($task_id,'upload',WPVIVID_REMOTE_DROPBOX,'0','Start uploading',$job_data);
95
+ }
96
+
97
+ foreach ($files as $file){
98
+ if(array_key_exists(basename($file),$upload_job['job_data']))
99
+ {
100
+ if($upload_job['job_data'][basename($file)]['uploaded']==1)
101
+ continue;
102
+ }
103
+
104
+ $this -> last_time = time();
105
+ $this -> last_size = 0;
106
+ $wpvivid_pulgin->wpvivid_log->WriteLog('Start uploading '.basename($file),'notice');
107
+ if(!file_exists($file))
108
+ return array('result' =>WPVIVID_FAILED,'error' =>$file.' not found. The file might has been moved, renamed or deleted. Please reload the list and verify the file exists.');
109
+ $result = $this -> _put($task_id,$dropbox,$file,$callback);
110
+ if($result['result'] !==WPVIVID_SUCCESS){
111
+ $wpvivid_pulgin->wpvivid_log->WriteLog('Uploading '.basename($file).' failed.','notice');
112
+ return $result;
113
+ }
114
+ $wpvivid_pulgin->wpvivid_log->WriteLog('Finished uploading '.basename($file),'notice');
115
+ }
116
+ return array('result' =>WPVIVID_SUCCESS);
117
+ }
118
+ private function _put($task_id,$dropbox,$file,$callback){
119
+ global $wpvivid_pulgin;
120
+ $options = $this -> options;
121
+ $path = trailingslashit($options['path']).basename($file);
122
+ $upload_job=WPvivid_taskmanager::get_backup_sub_task_progress($task_id,'upload',WPVIVID_REMOTE_DROPBOX);
123
+ $this -> current_file_size = filesize($file);
124
+ $this -> current_file_name = basename($file);
125
+
126
+ if($this -> current_file_size > $this -> upload_chunk_size){
127
+ WPvivid_taskmanager::update_backup_sub_task_progress($task_id,'upload',WPVIVID_REMOTE_DROPBOX,'0','Start uploading '.basename($file).'.',$upload_job['job_data']);
128
+ $result = $dropbox -> upload_session_start();
129
+ if(isset($result['error_summary'])){
130
+ return array('result'=>WPVIVID_FAILED,'error'=>$result['error_summary']);
131
+ }
132
+ $build_id = $result['session_id'];
133
+ $result = $this -> large_file_upload($build_id,$file,$dropbox,$callback);
134
+ }else{
135
+ $result = $dropbox -> upload($path,$file);
136
+ if(isset($result['error_summary'])){
137
+ WPvivid_taskmanager::update_backup_sub_task_progress($task_id,'upload',WPVIVID_REMOTE_DROPBOX,'0','Uploading '.basename($file).' failed.',$upload_job['job_data']);
138
+ $result = array('result' => WPVIVID_FAILED,'error' => $result['error_summary']);
139
+ }else{
140
+ WPvivid_taskmanager::update_backup_sub_task_progress($task_id,'upload',WPVIVID_REMOTE_DROPBOX,'0','Uploading '.basename($file).' completed.',$upload_job['job_data']);
141
+ $result = array('result'=> WPVIVID_SUCCESS);
142
+ }
143
+ }
144
+ return $result;
145
+ }
146
+
147
+ public function large_file_upload($session_id,$file,$dropbox,$callback){
148
+ $fh = fopen($file,'rb');
149
+ $offset = 0;
150
+ while(!feof($fh)){
151
+ $data = fread($fh,$this -> upload_chunk_size);
152
+ $ret = $this -> _upload_loop($session_id,$offset,$data,$dropbox);
153
+ if($ret['result'] !== WPVIVID_SUCCESS)
154
+ break;
155
+
156
+ if((time() - $this -> last_time) >3)
157
+ {
158
+ if(is_callable($callback))
159
+ {
160
+ call_user_func_array($callback,array(min($offset + $this -> upload_chunk_size,$this -> current_file_size),$this -> current_file_name,
161
+ $this->current_file_size,$this -> last_time,$this -> last_size));
162
+ }
163
+ $this -> last_size = $offset;
164
+ $this -> last_time = time();
165
+ }
166
+ $offset += $this -> upload_chunk_size;
167
+ }
168
+ if($ret['result'] === WPVIVID_SUCCESS){
169
+ $options = $this -> options;
170
+ $path = trailingslashit($options['path']).basename($file);
171
+ $result = $dropbox -> upload_session_finish($session_id,$this -> current_file_size,$path);
172
+ if(isset($result['error_summary'])){
173
+ $ret = array('result' => WPVIVID_FAILED,'error' => $result['error_summary']);
174
+ }else{
175
+ $ret = array('result'=> WPVIVID_SUCCESS);
176
+ }
177
+ }
178
+ fclose($fh);
179
+ return $ret;
180
+ }
181
+ public function _upload_loop($session_id,$offset,$data,$dropbox){
182
+ for($i =0;$i <WPVIVID_REMOTE_CONNECT_RETRY_TIMES; $i ++){
183
+ $result = $dropbox -> upload_session_append_v2($session_id,$offset,$data);
184
+ if(isset($result['error_summary'])){
185
+ $result = array('result' => WPVIVID_FAILED,'error' => 'Uploading '.$this -> current_file_name.' to Dropbox server failed. '.$result['error_summary']);
186
+ }else{
187
+ return array('result' => WPVIVID_SUCCESS);
188
+ }
189
+ }
190
+ return $result;
191
+ }
192
+
193
+ public function download($file, $local_path, $callback = '')
194
+ {
195
+ $this -> current_file_name = $file['file_name'];
196
+ $this -> current_file_size = $file['size'];
197
+ $file_md5 = $file['md5'];
198
+ $options = $this -> options;
199
+ $dropbox = new Dropbox_Base($options);
200
+
201
+ $file_path = trailingslashit($local_path).$this -> current_file_name;
202
+ $start_offset = file_exists($file_path)?filesize($file_path):0;
203
+ $fh = fopen($file_path, 'a');
204
+
205
+ while($start_offset < $this -> current_file_size)
206
+ {
207
+ $last_byte = min($start_offset + $this -> download_chunk_size - 1,$this -> current_file_size-1);
208
+ $headers = array("Range: bytes=$start_offset-$last_byte");
209
+ $response = $dropbox -> download(trailingslashit($options['path']).$this -> current_file_name,$headers);
210
+ if(isset($response['error_summary']))
211
+ return array('result' => WPVIVID_FAILED,'error'=> 'Downloading '.trailingslashit($options['path']).$this -> current_file_name.' failed.'.$response['error_summary']);
212
+ if(!fwrite($fh,$response)){
213
+ return array('result' => WPVIVID_FAILED,'error'=> 'Downloading '.trailingslashit($options['path']).$this -> current_file_name.' failed.');
214
+ }
215
+ clearstatcache();
216
+ $state = stat($file_path);
217
+ $start_offset = $state['size'];
218
+
219
+ if((time() - $this -> last_time) >3)
220
+ {
221
+ if(is_callable($callback))
222
+ {
223
+ call_user_func_array($callback,array($start_offset,$this -> current_file_name,
224
+ $this->current_file_size,$this -> last_time,$this -> last_size));
225
+ }
226
+ $this -> last_size = $start_offset;
227
+ $this -> last_time = time();
228
+ }
229
+ }
230
+ @fclose($fh);
231
+ if(md5_file($file_path) != $file_md5)
232
+ {
233
+ @unlink($file_path);
234
+ return array('result' => WPVIVID_FAILED, 'error' =>'file md5 is not matched.');
235
+ }
236
+ return array('result' => WPVIVID_SUCCESS);
237
+ }
238
+
239
+ public function cleanup($files)
240
+ {
241
+ $options = $this -> options;
242
+ $dropbox = new Dropbox_Base($options);
243
+ foreach ($files as $file){
244
+ $dropbox -> delete(trailingslashit($options['path']).$file);
245
+ }
246
+ return array('result'=>WPVIVID_SUCCESS);
247
+ }
248
+
249
+ public function init_remotes($remote_collection){
250
+ $remote_collection[WPVIVID_REMOTE_DROPBOX] = 'WPvivid_Dropbox';
251
+ return $remote_collection;
252
+ }
253
+ public function handle_auth_actions(){
254
+ if(isset($_GET['action']))
255
+ {
256
+ if($_GET['action'] === 'wpvivid_dropbox_auth')
257
+ {
258
+ if(!isset($_GET['name'])||empty($_GET['name']))
259
+ {
260
+ _e('<div class="notice notice-warning is-dismissible"><p>Warning: An alias for remote storage is required.</p></div>');
261
+ return;
262
+ }
263
+
264
+ $_GET['name']=sanitize_text_field($_GET['name']);
265
+
266
+ $remoteslist=WPvivid_Setting::get_all_remote_options();
267
+ foreach ($remoteslist as $key=>$value)
268
+ {
269
+ if(isset($value['name'])&&$value['name'] == $_GET['name'])
270
+ {
271
+ _e('<div class="notice notice-warning is-dismissible"><p>Warning: The alias already exists in storage list.</p></div>');
272
+ return;
273
+ }
274
+ }
275
+ $state = admin_url().'admin.php?page=WPvivid'.'&action=wpvivid_dropbox_finish_auth&name='.$_GET['name'].'&bdefault='.$_GET['bdefault'];
276
+ $url = Dropbox_Base::getUrl($this -> redirect_url,$state);
277
+ header('Location: ' . filter_var($url, FILTER_SANITIZE_URL));
278
+ }
279
+ else if($_GET['action'] === 'wpvivid_dropbox_finish_auth')
280
+ {
281
+ if(!isset($_GET['code'])){
282
+ header('Location: '.admin_url().'admin.php?page='.WPVIVID_PLUGIN_SLUG.'&action=wpvivid_dropbox_drive&result=error&error='.'Get Dropbox token failed.');
283
+ }else{
284
+ global $wpvivid_pulgin;
285
+ $remote_options['type']=WPVIVID_REMOTE_DROPBOX;
286
+ $remote_options['token']= $_GET['code'];
287
+ $remote_options['name']=$_GET['name'];
288
+ $remote_options['path'] ='/'.WPVIVID_DROPBOX_DEFAULT_FOLDER;
289
+ $remote_options['default']=$_GET['bdefault'];
290
+ $ret=$wpvivid_pulgin->remote_collection->add_remote($remote_options);
291
+ if($ret['result']=='success')
292
+ {
293
+ header('Location: '.admin_url().'admin.php?page='.WPVIVID_PLUGIN_SLUG.'&action=wpvivid_dropbox_drive&result=success');
294
+ return;
295
+ }
296
+ else
297
+ {
298
+ header('Location: '.admin_url().'admin.php?page='.WPVIVID_PLUGIN_SLUG.'&action=wpvivid_dropbox_drive&result=error&error='.$ret['error']);
299
+ return;
300
+ }
301
+ }
302
+ }
303
+ else if($_GET['action']=='wpvivid_dropbox_drive')
304
+ {
305
+ if(isset($_GET['result']))
306
+ {
307
+ if($_GET['result']=='success')
308
+ {
309
+ _e('<div class="notice notice-success is-dismissible"><p>You have authenticated the Dropbox account as your remote storage.</p></div>');
310
+ }
311
+ else if($_GET['result']=='error')
312
+ {
313
+ _e('<div class="notice notice-error is-dismissible"><p>'.$_GET['error'].'</p></div>');
314
+ }
315
+ }
316
+ }
317
+ else if($_GET['action'] === 'wpvivid_dropbox_update_auth')
318
+ {
319
+ if(!isset($_GET['name'])||empty($_GET['name']))
320
+ {
321
+ _e('<div class="notice notice-warning is-dismissible"><p>Warning: An alias for remote storage is required.</p></div>');
322
+ return;
323
+ }
324
+
325
+ $_GET['name']=sanitize_text_field($_GET['name']);
326
+
327
+ $remoteslist=WPvivid_Setting::get_all_remote_options();
328
+ foreach ($remoteslist as $key=>$value)
329
+ {
330
+ if(isset($value['name'])&&$value['name'] == $_GET['name']&&$key!=$_GET['id'])
331
+ {
332
+ _e('<div class="notice notice-warning is-dismissible"><p>Warning: The alias already exists in storage list.</p></div>');
333
+ return;
334
+ }
335
+ }
336
+ $state = admin_url().'admin.php?page=WPvivid'.'&action=wpvivid_dropbox_finish_update_auth&name='.$_GET['name'].'&id='.$_GET['id'];
337
+ $url = Dropbox_Base::getUrl($this -> redirect_url,$state);
338
+ header('Location: ' . filter_var($url, FILTER_SANITIZE_URL));
339
+ }
340
+ else if($_GET['action'] === 'wpvivid_dropbox_finish_update_auth')
341
+ {
342
+ if(!isset($_GET['code'])){
343
+ header('Location: '.admin_url().'admin.php?page='.WPVIVID_PLUGIN_SLUG.'&action=wpvivid_dropbox_drive_update&result=error&error='.'Get Dropbox token failed.');
344
+ }else{
345
+ global $wpvivid_pulgin;
346
+ $remote_options['type']=WPVIVID_REMOTE_DROPBOX;
347
+ $remote_options['token']= $_GET['code'];
348
+ $remote_options['name']=$_GET['name'];
349
+ $remote_options['path'] ='/'.WPVIVID_DROPBOX_DEFAULT_FOLDER;
350
+ $ret=$wpvivid_pulgin->remote_collection->update_remote($_GET['id'],$remote_options);
351
+ if($ret['result']=='success')
352
+ {
353
+ header('Location: '.admin_url().'admin.php?page='.WPVIVID_PLUGIN_SLUG.'&action=wpvivid_dropbox_drive_update&result=success');
354
+ return;
355
+ }
356
+ else
357
+ {
358
+ header('Location: '.admin_url().'admin.php?page='.WPVIVID_PLUGIN_SLUG.'&action=wpvivid_dropbox_drive_update&result=error&error='.$ret['error']);
359
+ return;
360
+ }
361
+ }
362
+ }
363
+ else if($_GET['action']=='wpvivid_dropbox_drive_update')
364
+ {
365
+ if(isset($_GET['result']))
366
+ {
367
+ if($_GET['result']=='success')
368
+ {
369
+ _e('<div class="notice notice-success is-dismissible"><p>You have successfully updated the storage alias.</p></div>');
370
+ }
371
+ else if($_GET['result']=='error')
372
+ {
373
+ _e('<div class="notice notice-error is-dismissible"><p>'.$_GET['error'].'</p></div>');
374
+ }
375
+ }
376
+ }
377
+ }
378
+ }
379
+ public function wpvivid_add_storage_tab_dropbox(){
380
+ ?>
381
+ <div class="storage-providers" remote_type="dropbox" onclick="select_remote_storage(event, 'storage_account_dropbox');">
382
+ <img src="<?php echo esc_url(WPVIVID_PLUGIN_URL.'/admin/partials/images/storage-dropbox.png'); ?>" style="vertical-align:middle;"/><?php _e('Dropbox', 'wpvivid'); ?>
383
+ </div>
384
+ <?php
385
+ }
386
+ public function wpvivid_add_storage_page_dropbox(){
387
+ ?>
388
+ <div id="storage_account_dropbox" class="storage-account-page" style="display:none;">
389
+ <p style="padding-left: 10px;">Please read <a target="_blank" href="https://wpvivid.com/privacy-policy">this privacy policy</a> for use of our Dropbox authorization app (none of your backup data is sent to us).</p>
390
+ <h2><span><?php _e( 'Enter Your Dropbox Information','wpvivid'); ?></span></h2>
391
+ <div class="storage-account-form">
392
+ <input type="text" autocomplete="off" option="dropbox" name="name" placeholder="Custom an unique name: Example: Dropbox-001" class="regular-text" onkeyup="value=value.replace(/[^a-zA-Z0-9\-_]/g,'')" />
393
+ </div>
394
+ <div style="padding-left: 10px; margin-bottom: -16px;">
395
+ <p><span><?php _e( 'Dropbox Folder:','wpvivid'); ?></span><span option="dropbox" name="path"><?php _e(WPVIVID_DROPBOX_DEFAULT_FOLDER); ?></span></p>
396
+ </div>
397
+ <div class="remote-storage-set-default-block">
398
+ <label>
399
+ <input type="checkbox" option="dropbox" name="default" checked><?php _e('Set as the default remote storage.', 'wpvivid'); ?>
400
+ </label>
401
+ </div>
402
+ <div id="wpvivid_storage_account_notice"></div>
403
+ <div class=""><input onclick="wpvivid_dropbox_auth()" class="button-primary storage-account-button" type="submit" value="<?php _e( 'Authenticate with Dropbox', 'wpvivid' ); ?>" /></div>
404
+ <div style="clear:both;"></div>
405
+ <div style="padding-left: 10px;">Tips: Click the button above to get Dropbox authentication and add it to the storage list below.</div>
406
+ </div>
407
+ <script>
408
+ function wpvivid_check_dropbox_storage_alias(storage_alias){
409
+ var find = 1;
410
+ jQuery('#wpvivid_remote_storage_list tr').each(function (i) {
411
+ jQuery(this).children('td').each(function (j) {
412
+ if (j == 3) {
413
+ if (jQuery(this).text() == storage_alias) {
414
+ find = -1;
415
+ return false;
416
+ }
417
+ }
418
+ });
419
+ });
420
+ return find;
421
+ }
422
+ function wpvivid_dropbox_auth()
423
+ {
424
+ wpvivid_settings_changed = false;
425
+ var name='';
426
+ var path = '';
427
+ var bdefault = '0';
428
+ jQuery("input:checkbox[option=dropbox]").each(function(){
429
+ var key = jQuery(this).prop('name');
430
+ if(jQuery(this).prop('checked')) {
431
+ bdefault = '1';
432
+ }
433
+ else {
434
+ bdefault = '0';
435
+ }
436
+ });
437
+ jQuery('input:text[option=dropbox]').each(function()
438
+ {
439
+ var type = jQuery(this).prop('name');
440
+ if(type == 'name'){
441
+ name = jQuery(this).val();
442
+ }
443
+ });
444
+ if(name == ''){
445
+ alert('Warning: An alias for remote storage is required.');
446
+ }
447
+ else if(wpvivid_check_dropbox_storage_alias(name) === -1){
448
+ alert("Warning: The alias already exists in storage list.");
449
+ }
450
+ else{
451
+ location.href ='<?php echo admin_url().'admin.php?page=WPvivid'.'&action=wpvivid_dropbox_auth&name='?>'+name+'<?php echo '&bdefault='?>'+bdefault;
452
+ }
453
+ }
454
+ </script>
455
+ <?php
456
+ }
457
+ public function wpvivid_edit_storage_page_dropbox()
458
+ {
459
+ do_action('wpvivid_remote_storage_js');
460
+ ?>
461
+ <div id="remote_storage_edit_dropbox" class="postbox storage-account-block remote-storage-edit" style="display:none;">
462
+ <h2><span><?php _e( 'Enter an alias for Dropbox','wpvivid'); ?></span></h2>
463
+ <div class="storage-account-form">
464
+ <input type="text" option="edit-dropbox" name="name" placeholder="Custom an unique name: Example: Dropbox-001" class="regular-text" onkeyup="value=value.replace(/[^a-zA-Z0-9\-_]/g,'')" />
465
+ </div>
466
+ <div class=""><input onclick="wpvivid_dropbox_update_auth()" class="button-primary storage-account-button" type="button" value="<?php _e( 'Save Changes', 'wpvivid' ); ?>" /></div>
467
+ <div style="clear:both;"></div>
468
+ <div style="padding-left: 10px;">Tips: Get Dropbox authentication to change the alias.</div>
469
+ </div>
470
+ <script>
471
+ function wpvivid_dropbox_update_auth()
472
+ {
473
+ var name='';
474
+ jQuery('input:text[option=edit-dropbox]').each(function()
475
+ {
476
+ var key = jQuery(this).prop('name');
477
+ if(key==='name')
478
+ {
479
+ name = jQuery(this).val();
480
+ }
481
+ });
482
+ if(name == ''){
483
+ alert('Warning: An alias for remote storage is required.');
484
+ }
485
+ else if(wpvivid_check_onedrive_storage_alias(name) === -1){
486
+ alert("Warning: The alias already exists in storage list.");
487
+ }
488
+ else {
489
+ location.href = '<?php echo admin_url() . 'admin.php?page=WPvivid' . '&action=wpvivid_dropbox_update_auth&name='?>' + name + '&id=' + wpvivid_editing_storage_id;
490
+ }
491
+ }
492
+ </script>
493
+ <?php
494
+ }
495
+ public function wpvivid_remote_pic_dropbox($remote)
496
+ {
497
+ $remote['dropbox']['default_pic'] = '/admin/partials/images/storage-dropbox(gray).png';
498
+ $remote['dropbox']['selected_pic'] = '/admin/partials/images/storage-dropbox.png';
499
+ $remote['dropbox']['title'] = 'Dropbox';
500
+ return $remote;
501
+ }
502
+
503
+ public function revoke($id){
504
+ $upload_options = WPvivid_Setting::get_option('wpvivid_upload_setting');
505
+ if(array_key_exists($id,$upload_options) && $upload_options[$id] == WPVIVID_REMOTE_DROPBOX){
506
+ $dropbox = new Dropbox_Base($upload_options);
507
+ $dropbox -> revoke();
508
+ }
509
+ }
510
+
511
+ public function wpvivid_get_out_of_date_dropbox($out_of_date_remote, $remote)
512
+ {
513
+ if($remote['type'] == WPVIVID_REMOTE_DROPBOX){
514
+ $out_of_date_remote = $remote['path'];
515
+ }
516
+ return $out_of_date_remote;
517
+ }
518
+
519
+ public function wpvivid_storage_provider_dropbox($storage_type)
520
+ {
521
+ if($storage_type == WPVIVID_REMOTE_DROPBOX){
522
+ $storage_type = 'Dropbox';
523
+ }
524
+ return $storage_type;
525
+ }
526
+ }
includes/customclass/class-wpvivid-google-drive.php ADDED
@@ -0,0 +1,777 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if (!defined('WPVIVID_PLUGIN_DIR')){
4
+ die;
5
+ }
6
+
7
+ require_once WPVIVID_PLUGIN_DIR . '/includes/customclass/class-wpvivid-remote.php';
8
+
9
+ define('WPVIVID_REMOTE_GOOGLEDRIVE','googledrive');
10
+ define('WPVIVID_GOOGLEDRIVE_DEFAULT_FOLDER','wpvivid_backup');
11
+ define('WPVIVID_GOOGLEDRIVE_SECRETS',WPVIVID_PLUGIN_DIR.'/includes/customclass/client_secrets.json');
12
+ define('WPVIVID_GOOGLEDRIVE_UPLOAD_SIZE',1024*1024*2);
13
+
14
+ class Wpvivid_Google_drive extends WPvivid_Remote
15
+ {
16
+ public $options;
17
+
18
+ public function __construct($options=array())
19
+ {
20
+ if(empty($options))
21
+ {
22
+ if(!defined('WPVIVID_INIT_STORAGE_TAB_GOOGLE_DRIVE'))
23
+ {
24
+ add_action('init', array($this, 'handle_auth_actions'));
25
+
26
+ add_action('wpvivid_add_storage_tab',array($this,'wpvivid_add_storage_tab_google_drive'), 10);
27
+ add_action('wpvivid_add_storage_page',array($this,'wpvivid_add_storage_page_google_drive'), 10);
28
+ add_filter('wpvivid_pre_add_remote',array($this, 'pre_add_remote'),10,2);
29
+ add_action('wpvivid_edit_remote_page',array($this,'wpvivid_edit_storage_page_google_drive'), 10);
30
+ add_filter('wpvivid_remote_pic',array($this,'wpvivid_remote_pic_google_drive'),10);
31
+ add_filter('wpvivid_get_out_of_date_remote',array($this,'wpvivid_get_out_of_date_google_drive'),10,2);
32
+ add_filter('wpvivid_storage_provider_tran',array($this,'wpvivid_storage_provider_google_drive'),10);
33
+ define('WPVIVID_INIT_STORAGE_TAB_GOOGLE_DRIVE',1);
34
+ }
35
+ }
36
+ else
37
+ {
38
+ $this->options=$options;
39
+ }
40
+ }
41
+
42
+ public function pre_add_remote($remote,$id)
43
+ {
44
+ if($remote['type']==WPVIVID_REMOTE_GOOGLEDRIVE)
45
+ {
46
+ $remote['id']=$id;
47
+ }
48
+
49
+ return $remote;
50
+ }
51
+
52
+ public function handle_auth_actions()
53
+ {
54
+ if (isset($_GET['action']))
55
+ {
56
+ if($_GET['action']=='wpvivid_google_drive_auth')
57
+ {
58
+ if(!isset($_GET['name'])||empty($_GET['name']))
59
+ {
60
+ _e('<div class="notice notice-warning is-dismissible"><p>Warning: An alias for remote storage is required.</p></div>');
61
+ return;
62
+ }
63
+
64
+ $_GET['name']=sanitize_text_field($_GET['name']);
65
+
66
+ $remoteslist=WPvivid_Setting::get_all_remote_options();
67
+ foreach ($remoteslist as $key=>$value)
68
+ {
69
+ if(isset($value['name'])&&$value['name'] == $_GET['name'])
70
+ {
71
+ _e('<div class="notice notice-warning is-dismissible"><p>Warning: The alias already exists in storage list.</p></div>');
72
+ return;
73
+ }
74
+ }
75
+
76
+ include_once WPVIVID_PLUGIN_DIR.'/vendor/autoload.php';
77
+ $client = new Google_Client();
78
+ $client->setAuthConfig(WPVIVID_GOOGLEDRIVE_SECRETS);
79
+ $client->setApprovalPrompt('force');
80
+ $client->addScope(Google_Service_Drive::DRIVE_FILE);
81
+ $client->setAccessType('offline');
82
+ $client->setState(admin_url().'admin.php?page=WPvivid'.'&action=wpvivid_google_drive_finish_auth&name='.$_GET['name'].'&default='.$_GET['default']);
83
+ $auth_url = $client->createAuthUrl();
84
+ header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));
85
+ }
86
+ else if($_GET['action']=='wpvivid_google_drive_finish_auth')
87
+ {
88
+ if(isset($_GET['error']))
89
+ {
90
+ header('Location: '.admin_url().'admin.php?page='.WPVIVID_PLUGIN_SLUG.'&action=wpvivid_google_drive&result=error&error='.$_GET['error']);
91
+
92
+ return;
93
+ }
94
+
95
+ global $wpvivid_pulgin;
96
+
97
+ $remote_options['type']=WPVIVID_REMOTE_GOOGLEDRIVE;
98
+ $token=$_GET['token'];
99
+ $token = stripslashes($token);
100
+ $remote_options['token']=json_decode($token,1);
101
+ $remote_options['name']=$_GET['name'];
102
+ $remote_options['default']=$_GET['default'];
103
+ $remote_options['path']=WPVIVID_GOOGLEDRIVE_DEFAULT_FOLDER;
104
+ $ret=$wpvivid_pulgin->remote_collection->add_remote($remote_options);
105
+
106
+ if($ret['result']=='success')
107
+ {
108
+ header('Location: '.admin_url().'admin.php?page='.WPVIVID_PLUGIN_SLUG.'&action=wpvivid_google_drive&result=success');
109
+ return;
110
+ }
111
+ else
112
+ {
113
+ header('Location: '.admin_url().'admin.php?page='.WPVIVID_PLUGIN_SLUG.'&action=wpvivid_google_drive&result=error&error='.$ret['error']);
114
+ return;
115
+ }
116
+ }
117
+ else if($_GET['action']=='wpvivid_google_drive')
118
+ {
119
+ if(isset($_GET['result']))
120
+ {
121
+ if($_GET['result']=='success')
122
+ {
123
+ _e('<div class="notice notice-success is-dismissible"><p>You have authenticated the Google Drive account as your remote storage.</p></div>');
124
+ }
125
+ else if($_GET['result']=='error')
126
+ {
127
+ _e('<div class="notice notice-error is-dismissible"><p>'.$_GET['error'].'</p></div>');
128
+ }
129
+ }
130
+ }
131
+ else if($_GET['action']=='wpvivid_google_drive_update_auth')
132
+ {
133
+ if(!isset($_GET['name'])||empty($_GET['name']))
134
+ {
135
+ _e('<div class="notice notice-warning is-dismissible"><p>Warning: An alias for remote storage is required.</p></div>');
136
+ return;
137
+ }
138
+
139
+ $_GET['name']=sanitize_text_field($_GET['name']);
140
+
141
+ $remoteslist=WPvivid_Setting::get_all_remote_options();
142
+ foreach ($remoteslist as $key=>$value)
143
+ {
144
+ if(isset($value['name'])&&$value['name'] == $_GET['name']&&$key!=$_GET['id'])
145
+ {
146
+ _e('<div class="notice notice-warning is-dismissible"><p>Warning: The alias already exists in storage list.</p></div>');
147
+ return;
148
+ }
149
+ }
150
+
151
+ include_once WPVIVID_PLUGIN_DIR.'/vendor/autoload.php';
152
+ $client = new Google_Client();
153
+ $client->setAuthConfig(WPVIVID_GOOGLEDRIVE_SECRETS);
154
+ $client->setApprovalPrompt('force');
155
+ $client->addScope(Google_Service_Drive::DRIVE_FILE);
156
+ $client->setAccessType('offline');
157
+ $client->setState(admin_url().'admin.php?page=WPvivid'.'&action=wpvivid_google_drive_finish_update_auth&name='.$_GET['name'].'&id='.$_GET['id']);
158
+ $auth_url = $client->createAuthUrl();
159
+ header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));
160
+ }
161
+ else if($_GET['action']=='wpvivid_google_drive_finish_update_auth')
162
+ {
163
+ if(isset($_GET['error']))
164
+ {
165
+ header('Location: '.admin_url().'admin.php?page='.WPVIVID_PLUGIN_SLUG.'&action=wpvivid_google_drive_update&result=error&error='.$_GET['error']);
166
+
167
+ return;
168
+ }
169
+
170
+ global $wpvivid_pulgin;
171
+
172
+ $remote_options['type']=WPVIVID_REMOTE_GOOGLEDRIVE;
173
+ $token=$_GET['token'];
174
+ $token = stripslashes($token);
175
+ $remote_options['token']=json_decode($token,1);
176
+ $remote_options['name']=$_GET['name'];
177
+ $remote_options['path']=WPVIVID_GOOGLEDRIVE_DEFAULT_FOLDER;
178
+ $ret=$wpvivid_pulgin->remote_collection->update_remote($_GET['id'],$remote_options);
179
+
180
+ if($ret['result']=='success')
181
+ {
182
+ header('Location: '.admin_url().'admin.php?page='.WPVIVID_PLUGIN_SLUG.'&action=wpvivid_google_drive_update&result=success');
183
+ return;
184
+ }
185
+ else
186
+ {
187
+ header('Location: '.admin_url().'admin.php?page='.WPVIVID_PLUGIN_SLUG.'&action=wpvivid_google_drive_update&result=error&error='.$ret['error']);
188
+ return;
189
+ }
190
+ }
191
+ else if($_GET['action']=='wpvivid_google_drive_update')
192
+ {
193
+ if(isset($_GET['result']))
194
+ {
195
+ if($_GET['result']=='success')
196
+ {
197
+ _e('<div class="notice notice-success is-dismissible"><p>You have successfully updated the storage alias.</p></div>');
198
+ }
199
+ else if($_GET['result']=='error')
200
+ {
201
+ _e('<div class="notice notice-error is-dismissible"><p>'.$_GET['error'].'</p></div>');
202
+ }
203
+ }
204
+ }
205
+ }
206
+ }
207
+
208
+ public function wpvivid_add_storage_tab_google_drive()
209
+ {
210
+ ?>
211
+ <div class="storage-providers" remote_type="googledrive" onclick="select_remote_storage(event, 'storage_account_google_drive');">
212
+ <img src="<?php echo esc_url(WPVIVID_PLUGIN_URL.'/admin/partials/images/stroage-google-drive.png'); ?>" style="vertical-align:middle;"/><?php _e('Google Drive', 'wpvivid'); ?>
213
+ </div>
214
+ <?php
215
+ }
216
+
217
+ public function wpvivid_add_storage_page_google_drive()
218
+ {
219
+ ?>
220
+ <div id="storage_account_google_drive" class="storage-account-page" style="display:none;">
221
+ <p style="padding-left: 10px;">Please read <a target="_blank" href="https://wpvivid.com/privacy-policy">this privacy policy</a> for use of our Google Drive authorization app (none of your backup data is sent to us).</p>
222
+ <h2><span><?php _e( 'Enter Your Google Drive Information','wpvivid'); ?></span></h2>
223
+ <div class="storage-account-form">
224
+ <input type="text" autocomplete="off" option="googledrive" name="name" placeholder="Custom an unique name: Example: Google Drive-001" class="regular-text" onkeyup="value=value.replace(/[^a-zA-Z0-9\-_]/g,'')" />
225
+ </div>
226
+ <div style="padding-left: 10px; margin-bottom: -16px;">
227
+ <p><span><?php _e( 'Google Drive Folder:','wpvivid'); ?></span><span option="googledrive" name="path"><?php _e(WPVIVID_GOOGLEDRIVE_DEFAULT_FOLDER); ?></span></p>
228
+ </div>
229
+ <div class="remote-storage-set-default-block">
230
+ <label>
231
+ <input type="checkbox" option="googledrive" name="default" checked /><?php _e('Set as the default remote storage.', 'wpvivid'); ?>
232
+ </label>
233
+ </div>
234
+ <div id="wpvivid_storage_account_notice"></div>
235
+ <div class=""><input onclick="wpvivid_google_drive_auth()" class="button-primary storage-account-button" type="submit" value="<?php _e( 'Authenticate with Google Drive', 'wpvivid' ); ?>" /></div>
236
+ <div style="clear:both;"></div>
237
+ <div style="padding-left: 10px;">Tips: Click the button above to get Google authentication and add it to the storage list below.</div>
238
+ </div>
239
+ <script>
240
+ function wpvivid_check_google_drive_storage_alias(storage_alias){
241
+ var find = 1;
242
+ jQuery('#wpvivid_remote_storage_list tr').each(function (i) {
243
+ jQuery(this).children('td').each(function (j) {
244
+ if (j == 3) {
245
+ if (jQuery(this).text() == storage_alias) {
246
+ find = -1;
247
+ return false;
248
+ }
249
+ }
250
+ });
251
+ });
252
+ return find;
253
+ }
254
+ function wpvivid_google_drive_auth()
255
+ {
256
+ wpvivid_settings_changed = false;
257
+ var name='';
258
+ var path='';
259
+ jQuery('input:text[option=googledrive]').each(function()
260
+ {
261
+ var key = jQuery(this).prop('name');
262
+ if(key==='name')
263
+ {
264
+ name = jQuery(this).val();
265
+ }
266
+ });
267
+
268
+ var remote_default='0';
269
+
270
+ jQuery('input:checkbox[option=googledrive]').each(function()
271
+ {
272
+ if(jQuery(this).prop('checked')) {
273
+ remote_default='1';
274
+ }
275
+ else {
276
+ remote_default='0';
277
+ }
278
+ });
279
+ if(name == ''){
280
+ alert('Warning: An alias for remote storage is required.');
281
+ }
282
+ else if(wpvivid_check_google_drive_storage_alias(name) === -1){
283
+ alert("Warning: The alias already exists in storage list.");
284
+ }
285
+ else {
286
+ location.href = '<?php echo admin_url() . 'admin.php?page=WPvivid' . '&action=wpvivid_google_drive_auth&name='?>' + name + '&default=' + remote_default;
287
+ }
288
+ }
289
+ </script>
290
+ <?php
291
+ }
292
+
293
+ public function wpvivid_edit_storage_page_google_drive()
294
+ {
295
+ ?>
296
+ <div id="remote_storage_edit_googledrive" class="postbox storage-account-block remote-storage-edit" style="display:none;">
297
+ <h2><span><?php _e( 'Enter an alias for Google Drive','wpvivid'); ?></span></h2>
298
+ <div class="storage-account-form">
299
+ <input type="text" option="edit-googledrive" name="name" placeholder="Custom an unique name: Example: Google Drive-001" class="regular-text" onkeyup="value=value.replace(/[^a-zA-Z0-9\-_]/g,'')" />
300
+ </div>
301
+ <div class=""><input onclick="wpvivid_google_drive_update_auth()" class="button-primary storage-account-button" type="button" value="<?php _e( 'Save Changes', 'wpvivid' ); ?>" /></div>
302
+ <div style="clear:both;"></div>
303
+ <div style="padding-left: 10px;">Tips: Get Google authentication to change the alias.</div>
304
+ </div>
305
+ <script>
306
+ function wpvivid_google_drive_update_auth()
307
+ {
308
+ var name='';
309
+ jQuery('input:text[option=edit-googledrive]').each(function()
310
+ {
311
+ var key = jQuery(this).prop('name');
312
+ if(key==='name')
313
+ {
314
+ name = jQuery(this).val();
315
+ }
316
+ });
317
+
318
+ if(name == ''){
319
+ alert('Warning: An alias for remote storage is required.');
320
+ }
321
+ else if(wpvivid_check_onedrive_storage_alias(name) === -1){
322
+ alert("Warning: The alias already exists in storage list.");
323
+ }
324
+ else {
325
+ location.href = '<?php echo admin_url() . 'admin.php?page=WPvivid' . '&action=wpvivid_google_drive_update_auth&name='?>' + name + '&id=' + wpvivid_editing_storage_id;
326
+ }
327
+ }
328
+ </script>
329
+ <?php
330
+ }
331
+
332
+ public function wpvivid_remote_pic_google_drive($remote)
333
+ {
334
+ $remote['googledrive']['default_pic'] = '/admin/partials/images/stroage-google-drive(gray).png';
335
+ $remote['googledrive']['selected_pic'] = '/admin/partials/images/stroage-google-drive.png';
336
+ $remote['googledrive']['title'] = 'Google Drive';
337
+ return $remote;
338
+ }
339
+
340
+ public function sanitize_options($skip_name='')
341
+ {
342
+ $ret['result']=WPVIVID_SUCCESS;
343
+
344
+ if(!isset($this->options['name']))
345
+ {
346
+ $ret['error']="Warning: An alias for remote storage is required.";
347
+ return $ret;
348
+ }
349
+
350
+ $this->options['name']=sanitize_text_field($this->options['name']);
351
+
352
+ if(empty($this->options['name']))
353
+ {
354
+ $ret['error']="Warning: An alias for remote storage is required.";
355
+ return $ret;
356
+ }
357
+
358
+ $remoteslist=WPvivid_Setting::get_all_remote_options();
359
+ foreach ($remoteslist as $key=>$value)
360
+ {
361
+ if(isset($value['name'])&&$value['name'] == $this->options['name']&&$skip_name!=$value['name'])
362
+ {
363
+ $ret['error']="Warning: The alias already exists in storage list.";
364
+ return $ret;
365
+ }
366
+ }
367
+
368
+ $ret['options']=$this->options;
369
+ return $ret;
370
+ }
371
+
372
+ public function test_connect()
373
+ {
374
+ return array('result' => WPVIVID_SUCCESS);
375
+ }
376
+
377
+ public function upload($task_id, $files, $callback = '')
378
+ {
379
+ global $wpvivid_pulgin;
380
+
381
+ $client=$this->get_client();
382
+ if($client===false)
383
+ {
384
+ return array('result' => WPVIVID_FAILED,'error'=> 'Token refresh failed.');
385
+ }
386
+
387
+ $service = new Google_Service_Drive($client);
388
+ $path=$this->options['path'];
389
+ $folder_id=$this->get_folder($service,$path);
390
+
391
+ if($folder_id==false)
392
+ {
393
+ return array('result' => WPVIVID_FAILED,'error'=> 'Unable to create the local file. Please make sure the folder is writable and try again.');
394
+ }
395
+
396
+ $upload_job=WPvivid_taskmanager::get_backup_sub_task_progress($task_id,'upload',WPVIVID_REMOTE_GOOGLEDRIVE);
397
+ if(empty($upload_job))
398
+ {
399
+ $job_data=array();
400
+ foreach ($files as $file)
401
+ {
402
+ $file_data['size']=filesize($file);
403
+ $file_data['uploaded']=0;
404
+ $job_data[basename($file)]=$file_data;
405
+ }
406
+ WPvivid_taskmanager::update_backup_sub_task_progress($task_id,'upload',WPVIVID_REMOTE_GOOGLEDRIVE,'0','Start uploading',$job_data);
407
+ }
408
+
409
+ foreach ($files as $file)
410
+ {
411
+ if(array_key_exists(basename($file),$upload_job['job_data']))
412
+ {
413
+ if($upload_job['job_data'][basename($file)]['uploaded']==1)
414
+ continue;
415
+ }
416
+
417
+ $this -> last_time = time();
418
+ $this -> last_size = 0;
419
+
420
+ if(!file_exists($file))
421
+ return array('result' =>WPVIVID_FAILED,'error' =>$file.' not found. The file might has been moved, renamed or deleted. Please reload the list and verify the file exists.');
422
+ $wpvivid_pulgin->wpvivid_log->WriteLog('Start uploading '.basename($file),'notice');
423
+ $result=$this->_upload($task_id, $file,$client,$service,$folder_id, $callback);
424
+ if($result['result'] !==WPVIVID_SUCCESS){
425
+ return $result;
426
+ }
427
+ }
428
+ return array('result' =>WPVIVID_SUCCESS);
429
+ }
430
+
431
+ public function _upload($task_id, $file,$client,$service,$folder_id, $callback = '')
432
+ {
433
+ global $wpvivid_pulgin;
434
+ if(!$this->delete_exist_file($folder_id,$file,$service))
435
+ {
436
+ return array('result' =>WPVIVID_FAILED,'error'=>'Uploading '.$file.' to Google Drive server failed. '.$file.' might be deleted or network doesn\'t work properly . Please verify the file and confirm the network connection and try again later.');
437
+ }
438
+
439
+ $upload_job=WPvivid_taskmanager::get_backup_sub_task_progress($task_id,'upload',WPVIVID_REMOTE_GOOGLEDRIVE);
440
+ $this -> current_file_size = filesize($file);
441
+ $this -> current_file_name = basename($file);
442
+
443
+ $fileMetadata = new Google_Service_Drive_DriveFile(array(
444
+ 'name' => basename($file),
445
+ 'parents' => array($folder_id)));
446
+ $chunk_size = 1 * 1024 * 1024;
447
+ $client->setDefer(true);
448
+ $request = $service->files->create($fileMetadata);
449
+ $media = new Google_Http_MediaFileUpload(
450
+ $client,
451
+ $request,
452
+ 'text/plain',
453
+ null,
454
+ true,
455
+ $chunk_size
456
+ );
457
+ $media->setFileSize(filesize($file));
458
+ $status = false;
459
+ $handle = fopen($file, "rb");
460
+
461
+ WPvivid_taskmanager::update_backup_sub_task_progress($task_id,'upload',WPVIVID_REMOTE_GOOGLEDRIVE,'0','Start uploading '.basename($file).'.',$upload_job['job_data']);
462
+
463
+ $offset=0;
464
+
465
+ while (!$status && !feof($handle))
466
+ {
467
+ $chunk = fread($handle, $chunk_size);
468
+
469
+ $status = $media->nextChunk($chunk);
470
+
471
+ $offset+=strlen($chunk);
472
+
473
+ if((time() - $this -> last_time) >3)
474
+ {
475
+ if(is_callable($callback))
476
+ {
477
+ call_user_func_array($callback,array($offset,$this -> current_file_name,
478
+ $this->current_file_size,$this -> last_time,$this -> last_size));
479
+ }
480
+ $this -> last_size = $offset;
481
+ $this -> last_time = time();
482
+ }
483
+ }
484
+
485
+ fclose($handle);
486
+
487
+ if ($status != false)
488
+ {
489
+ $wpvivid_pulgin->wpvivid_log->WriteLog('Finished uploading '.basename($file),'notice');
490
+ $upload_job['job_data'][basename($file)]['uploaded']=1;
491
+ WPvivid_taskmanager::update_backup_sub_task_progress($task_id,'upload',WPVIVID_REMOTE_GOOGLEDRIVE,'0','Uploading '.basename($file).' completed.',$upload_job['job_data']);
492
+ return array('result' =>WPVIVID_SUCCESS);
493
+ }
494
+ else
495
+ {
496
+ return array('result' =>WPVIVID_FAILED,'error'=>'Uploading '.$file.' to Google Drive server failed. '.$file.' might be deleted or network doesn\'t work properly. Please verify the file and confirm the network connection and try again later.');
497
+ }
498
+ }
499
+
500
+ private function get_client()
501
+ {
502
+ include_once WPVIVID_PLUGIN_DIR.'/vendor/autoload.php';
503
+ $client = new Google_Client();
504
+ $client->setConfig('access_type','offline');
505
+ $client->setAuthConfig(WPVIVID_GOOGLEDRIVE_SECRETS);
506
+ $client->addScope(Google_Service_Drive::DRIVE_FILE);//
507
+ $client->setAccessToken($this->options['token']);
508
+
509
+ if ($client->isAccessTokenExpired())
510
+ {
511
+ // Refresh the token if possible, else fetch a new one.
512
+ if ($client->getRefreshToken())
513
+ {
514
+ $client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
515
+ $token=$client->getAccessToken();
516
+ $this->options['token']=json_decode(json_encode($token),1);
517
+ WPvivid_Setting::update_remote_option($this->options['id'],$this->options);
518
+ return $client;
519
+ }
520
+ else
521
+ {
522
+ return false;
523
+ }
524
+ }
525
+ else
526
+ {
527
+ return $client;
528
+ }
529
+ }
530
+
531
+ private function get_folder($service,$path)
532
+ {
533
+ $response = $service->files->listFiles(array(
534
+ 'q' => "name ='".$path."' and 'root' in parents and mimeType = 'application/vnd.google-apps.folder'",
535
+ 'fields' => 'nextPageToken, files(id, name,mimeType)',
536
+ ));
537
+ if(sizeof($response->getFiles())==0)
538
+ {
539
+ $fileMetadata = new Google_Service_Drive_DriveFile(array(
540
+ 'name' => $path,
541
+ 'mimeType' => 'application/vnd.google-apps.folder'));
542
+ $file = $service->files->create($fileMetadata, array(
543
+ 'fields' => 'id'));
544
+
545
+ return $file->id;
546
+ }
547
+ else
548
+ {
549
+ foreach ($response->getFiles() as $file)
550
+ {
551
+ return $file->getId();
552
+ }
553
+ }
554
+
555
+ return false;
556
+ }
557
+
558
+ public function download( $file, $local_path, $callback = '')
559
+ {
560
+ $this -> current_file_name = $file['file_name'];
561
+ $this -> current_file_size = $file['size'];
562
+
563
+ try
564
+ {
565
+ $client=$this->get_client();
566
+
567
+ if($client===false)
568
+ {
569
+ return array('result' => WPVIVID_FAILED,'error'=> 'Token refresh failed.');
570
+ }
571
+
572
+ $service = new Google_Service_Drive($client);
573
+
574
+ $path=$this->options['path'];
575
+ $folder_id=$this->get_folder($service,$path);
576
+
577
+ if($folder_id==false)
578
+ {
579
+ return array('result' => WPVIVID_FAILED,'error'=> 'Unable to create the local file. Please make sure the folder is writable and try again.');
580
+ }
581
+
582
+ $response = $service->files->listFiles([
583
+ 'q' => "name='".$file['file_name']."' and '".$folder_id."' in parents",
584
+ 'fields' => 'files(id,size,webContentLink)'
585
+ ]);
586
+
587
+ if(sizeof($response->getFiles())==0)
588
+ {
589
+ return array('result' => WPVIVID_FAILED,'error'=> 'Downloading file failed. The file might be deleted or network doesn\'t work properly. Please verify the file and confirm the network connection and try again later.');
590
+ }
591
+ else
592
+ {
593
+ $fileSize=$file['size'];
594
+ $file_id='';
595
+ foreach ($response->getFiles() as $file)
596
+ {
597
+ $file_id=$file->getId();
598
+ break;
599
+ }
600
+ $download_url=$this->get_download_url($client,$file_id);
601
+
602
+ if(!empty($file_id)||!empty($download_url))
603
+ {
604
+ $file_path = trailingslashit($local_path).$this -> current_file_name;
605
+
606
+ if(file_exists($file_path))
607
+ {
608
+ $offset = filesize($file_path);
609
+ }
610
+ else
611
+ {
612
+ $offset=0;
613
+ }
614
+
615
+ $fh = fopen($file_path, 'a');
616
+ $upload_size = WPVIVID_GOOGLEDRIVE_UPLOAD_SIZE;
617
+ $http = $client->authorize();
618
+
619
+ while ($offset < $fileSize)
620
+ {
621
+ $upload_end=min($offset+$upload_size-1,$fileSize-1);
622
+
623
+ if ($offset > 0)
624
+ {
625
+ $options['headers']['Range']='bytes='.$offset.'-'.$upload_end;
626
+ } else {
627
+ $options['headers']['Range']='bytes=0-'.$upload_end;
628
+ }
629
+ $request = new GuzzleHttp\Psr7\Request('GET', $download_url,$options['headers']);
630
+ $http_request = $http->send($request);
631
+ $http_response=$http_request->getStatusCode();
632
+ if (200 == $http_response || 206 == $http_response)
633
+ {
634
+ fwrite($fh, $http_request->getBody()->getContents(),$upload_size);
635
+ $offset=$upload_end + 1;
636
+ }
637
+ else
638
+ {
639
+ throw new Exception('Failed to obtain any new data at size: '.$offset);
640
+ }
641
+
642
+ if((time() - $this -> last_time) >3)
643
+ {
644
+ if(is_callable($callback))
645
+ {
646
+ call_user_func_array($callback,array($offset,$this -> current_file_name,
647
+ $this->current_file_size,$this -> last_time,$this -> last_size));
648
+ }
649
+ $this -> last_size = $offset;
650
+ $this -> last_time = time();
651
+ }
652
+ }
653
+ fclose($fh);
654
+ }
655
+ else
656
+ {
657
+ return array('result' => WPVIVID_FAILED,'error'=> 'Downloading file failed. The file might be deleted or network doesn\'t work properly. Please verify the file and confirm the network connection and try again later.');
658
+ }
659
+ }
660
+ }catch(Exception $e)
661
+ {
662
+ return array('result' => WPVIVID_FAILED,'error' => $e -> getMessage());
663
+ }
664
+
665
+ return array('result' => WPVIVID_SUCCESS);
666
+ }
667
+
668
+ public function get_download_url($client,$file_id)
669
+ {
670
+ $http = $client->authorize();
671
+ $url='https://www.googleapis.com/drive/v2/files/'.$file_id;
672
+ $request = new GuzzleHttp\Psr7\Request('GET', $url);
673
+ $http_request = $http->send($request);
674
+
675
+ $http_response=$http_request->getStatusCode();
676
+ if (200 == $http_response)
677
+ {
678
+ $json=$http_request->getBody()->getContents();
679
+ $json=json_decode($json,1);
680
+ $download_url=$json['downloadUrl'];
681
+ return $download_url;
682
+ }
683
+ else
684
+ {
685
+ throw new Exception('Failed to use v2 api');
686
+ }
687
+ }
688
+
689
+ public function delete_exist_file($folder_id,$file,$service)
690
+ {
691
+ $client=$this->get_client();
692
+
693
+ if($client===false)
694
+ {
695
+ return false;
696
+ }
697
+
698
+ $delete_files = $service->files->listFiles(array(
699
+ 'q' => "name='".$file."' and '".$folder_id."' in parents",
700
+ 'fields' => 'nextPageToken, files(id, name,mimeType)',
701
+ ));
702
+
703
+ if(sizeof($delete_files->getFiles())==0)
704
+ {
705
+ return true;
706
+ }
707
+ else
708
+ {
709
+ foreach ($delete_files->getFiles() as $file_google_drive)
710
+ {
711
+ $file_id=$file_google_drive->getId();
712
+ $service->files->delete($file_id);
713
+ return true;
714
+ }
715
+ }
716
+
717
+ return false;
718
+ }
719
+
720
+ public function cleanup($files)
721
+ {
722
+ $client=$this->get_client();
723
+
724
+ if($client===false)
725
+ {
726
+ return array('result' => WPVIVID_FAILED,'error'=> 'Token refresh failed.');
727
+ }
728
+
729
+ $service = new Google_Service_Drive($client);
730
+
731
+ $path=$this->options['path'];
732
+ $folder_id=$this->get_folder($service,$path);
733
+
734
+ if($folder_id==false)
735
+ {
736
+ return array('result' => WPVIVID_FAILED,'error'=> 'Unable to create the local file. Please make sure the folder is writable and try again.');
737
+ }
738
+
739
+ foreach ($files as $file)
740
+ {
741
+ $delete_files = $service->files->listFiles(array(
742
+ 'q' => "name='".$file."' and '".$folder_id."' in parents",
743
+ 'fields' => 'nextPageToken, files(id, name,mimeType)',
744
+ ));
745
+
746
+ if(sizeof($delete_files->getFiles())==0)
747
+ {
748
+ continue;
749
+ }
750
+ else
751
+ {
752
+ foreach ($delete_files->getFiles() as $file_google_drive)
753
+ {
754
+ $file_id=$file_google_drive->getId();
755
+ $service->files->delete($file_id);
756
+ }
757
+ }
758
+ }
759
+ return array('result' =>WPVIVID_SUCCESS);
760
+ }
761
+
762
+ public function wpvivid_get_out_of_date_google_drive($out_of_date_remote, $remote)
763
+ {
764
+ if($remote['type'] == WPVIVID_REMOTE_GOOGLEDRIVE){
765
+ $out_of_date_remote = $remote['path'];
766
+ }
767
+ return $out_of_date_remote;
768
+ }
769
+
770
+ public function wpvivid_storage_provider_google_drive($storage_type)
771
+ {
772
+ if($storage_type == WPVIVID_REMOTE_GOOGLEDRIVE){
773
+ $storage_type = 'Google Drive';
774
+ }
775
+ return $storage_type;
776
+ }
777
+ }
includes/customclass/class-wpvivid-one-drive.php ADDED
@@ -0,0 +1,1077 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Created by PhpStorm.
4
+ * User: alienware`x
5
+ * Date: 2019/2/14
6
+ * Time: 16:06
7
+ */
8
+
9
+ if (!defined('WPVIVID_PLUGIN_DIR')){
10
+ die;
11
+ }
12
+
13
+ require_once WPVIVID_PLUGIN_DIR . '/includes/customclass/class-wpvivid-remote.php';
14
+
15
+ define('WPVIVID_REMOTE_ONEDRIVE','onedrive');
16
+ define('WPVIVID_ONEDRIVE_DEFAULT_FOLDER','wpvivid_backup');
17
+ define('WPVIVID_ONEDRIVE_UPLOAD_SIZE',1024*1024*2);
18
+ define('WPVIVID_ONEDRIVE_DOWNLOAD_SIZE',1024*1024*2);
19
+ define('WPVIVID_ONEDRIVE_RETRY_TIMES','3');
20
+
21
+ class WPvivid_one_drive extends WPvivid_Remote
22
+ {
23
+ public $options;
24
+
25
+ public function __construct($options=array())
26
+ {
27
+ if(empty($options))
28
+ {
29
+ if(!defined('WPVIVID_INIT_STORAGE_TAB_ONE_DRIVE'))
30
+ {
31
+ add_action('init', array($this, 'handle_auth_actions'));
32
+ add_action('wpvivid_add_storage_tab',array($this,'wpvivid_add_storage_tab_one_drive'), 10);
33
+ add_action('wpvivid_add_storage_page',array($this,'wpvivid_add_storage_page_one_drive'), 10);
34
+ add_action('wpvivid_edit_remote_page',array($this,'wpvivid_edit_storage_page_one_drive'), 10);
35
+ add_filter('wpvivid_remote_pic',array($this,'wpvivid_remote_pic_one_drive'),10);
36
+ add_filter('wpvivid_get_out_of_date_remote',array($this,'wpvivid_get_out_of_date_one_drive'),10,2);
37
+ add_filter('wpvivid_storage_provider_tran',array($this,'wpvivid_storage_provider_one_drive'),10);
38
+
39
+ add_filter('wpvivid_pre_add_remote',array($this, 'pre_add_remote'),10,2);
40
+ define('WPVIVID_INIT_STORAGE_TAB_ONE_DRIVE',1);
41
+ }
42
+ }
43
+ else
44
+ {
45
+ $this->options=$options;
46
+ }
47
+ }
48
+
49
+ public function pre_add_remote($remote,$id)
50
+ {
51
+ if($remote['type']==WPVIVID_REMOTE_ONEDRIVE)
52
+ {
53
+ $remote['id']=$id;
54
+ }
55
+
56
+ return $remote;
57
+ }
58
+
59
+ public function handle_auth_actions()
60
+ {
61
+ if (isset($_GET['action']))
62
+ {
63
+ if($_GET['action']=='wpvivid_one_drive_auth')
64
+ {
65
+ if(!isset($_GET['name'])||empty($_GET['name']))
66
+ {
67
+ _e('<div class="notice notice-warning is-dismissible"><p>Warning: An alias for remote storage is required.</p></div>');
68
+ return;
69
+ }
70
+
71
+ $_GET['name']=sanitize_text_field($_GET['name']);
72
+
73
+ $remoteslist=WPvivid_Setting::get_all_remote_options();
74
+ foreach ($remoteslist as $key=>$value)
75
+ {
76
+ if(isset($value['name'])&&$value['name'] == $_GET['name'])
77
+ {
78
+ _e('<div class="notice notice-warning is-dismissible"><p>Warning: The alias already exists in storage list.</p></div>');
79
+ return;
80
+ }
81
+ }
82
+
83
+ $url = 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize'
84
+ . '?client_id=' . urlencode('37668be9-b55f-458f-b6a3-97e6f8aa10c9')
85
+ . '&scope=' . urlencode('offline_access files.readwrite')
86
+ . '&response_type=code'
87
+ . '&redirect_uri=' . urlencode('https://auth.wpvivid.com/onedrive')
88
+ . '&state=' . urlencode(admin_url().'admin.php?page=WPvivid'.'&action=wpvivid_one_drive_finish_auth&name='.$_GET['name'].'&default='.$_GET['default'])
89
+ . '&display=popup'
90
+ . '&locale=en';
91
+ header('Location: '.esc_url_raw($url));
92
+ }
93
+ else if($_GET['action']=='wpvivid_one_drive_finish_auth')
94
+ {
95
+ if(isset($_GET['auth_error']))
96
+ {
97
+ $error=urldecode($_GET['auth_error']);
98
+ header('Location: '.admin_url().'admin.php?page='.WPVIVID_PLUGIN_SLUG.'&action=wpvivid_one_drive&result=error&error='.$error);
99
+
100
+ return;
101
+ }
102
+
103
+ global $wpvivid_pulgin;
104
+
105
+ $remote_options['type']=WPVIVID_REMOTE_ONEDRIVE;
106
+ $token=$_GET['token'];
107
+ $token = stripslashes($token);
108
+ $remote_options['token']=json_decode($token,1);
109
+ $remote_options['token']['expires']=time()+ $remote_options['token']['expires_in'];
110
+ //
111
+ $remote_options['name']=$_GET['name'];
112
+ $remote_options['default']=$_GET['default'];
113
+ $remote_options['path']=WPVIVID_ONEDRIVE_DEFAULT_FOLDER;
114
+ $ret=$wpvivid_pulgin->remote_collection->add_remote($remote_options);
115
+
116
+ if($ret['result']=='success')
117
+ {
118
+ header('Location: '.admin_url().'admin.php?page='.WPVIVID_PLUGIN_SLUG.'&action=wpvivid_one_drive&result=success');
119
+ return;
120
+ }
121
+ else
122
+ {
123
+ header('Location: '.admin_url().'admin.php?page='.WPVIVID_PLUGIN_SLUG.'&action=wpvivid_one_drive&result=error&error='.$ret['error']);
124
+ return;
125
+ }
126
+ }
127
+ else if($_GET['action']=='wpvivid_one_drive')
128
+ {
129
+ if(isset($_GET['result']))
130
+ {
131
+ if($_GET['result']=='success')
132
+ {
133
+ _e('<div class="notice notice-success is-dismissible"><p>You have authenticated the Microsoft OneDrive account as your remote storage.</p></div>');
134
+ }
135
+ else if($_GET['result']=='error')
136
+ {
137
+ _e('<div class="notice notice-error is-dismissible"><p>'.$_GET['error'].'</p></div>');
138
+ }
139
+ }
140
+ }
141
+ else if($_GET['action']=='wpvivid_one_drive_update_auth')
142
+ {
143
+ if(!isset($_GET['name'])||empty($_GET['name']))
144
+ {
145
+ _e('<div class="notice notice-warning is-dismissible"><p>Warning: An alias for remote storage is required.</p></div>');
146
+ return;
147
+ }
148
+
149
+ $_GET['name']=sanitize_text_field($_GET['name']);
150
+
151
+ $remoteslist=WPvivid_Setting::get_all_remote_options();
152
+ foreach ($remoteslist as $key=>$value)
153
+ {
154
+ if(isset($value['name'])&&$value['name'] == $_GET['name']&&$key!=$_GET['id'])
155
+ {
156
+ _e('<div class="notice notice-warning is-dismissible"><p>Warning: The alias already exists in storage list.</p></div>');
157
+ return;
158
+ }
159
+ }
160
+
161
+ $url = 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize'
162
+ . '?client_id=' . urlencode('37668be9-b55f-458f-b6a3-97e6f8aa10c9')
163
+ . '&scope=' . urlencode('offline_access files.readwrite')
164
+ . '&response_type=code'
165
+ . '&redirect_uri=' . urlencode('https://auth.wpvivid.com/onedrive')
166
+ . '&state=' . urlencode(admin_url().'admin.php?page=WPvivid'.'&action=wpvivid_one_drive_update_finish_auth&name='.$_GET['name'].'&id='.$_GET['id'])
167
+ . '&display=popup'
168
+ . '&locale=en';
169
+ header('Location: '.esc_url_raw($url));
170
+ }
171
+ else if($_GET['action']=='wpvivid_one_drive_update_finish_auth')
172
+ {
173
+ if(isset($_GET['auth_error']))
174
+ {
175
+ $error=urldecode($_GET['auth_error']);
176
+ header('Location: '.admin_url().'admin.php?page='.WPVIVID_PLUGIN_SLUG.'&action=wpvivid_one_drive_update&result=error&error='.$error);
177
+
178
+ return;
179
+ }
180
+
181
+ global $wpvivid_pulgin;
182
+
183
+ $remote_options['type']=WPVIVID_REMOTE_ONEDRIVE;
184
+ $token=$_GET['token'];
185
+ $token = stripslashes($token);
186
+ $remote_options['token']=json_decode($token,1);
187
+ $remote_options['token']['expires']=time()+ $remote_options['token']['expires_in'];
188
+ //
189
+ $remote_options['name']=$_GET['name'];
190
+ $remote_options['path']=WPVIVID_ONEDRIVE_DEFAULT_FOLDER;
191
+ $ret=$wpvivid_pulgin->remote_collection->update_remote($_GET['id'],$remote_options);
192
+
193
+ if($ret['result']=='success')
194
+ {
195
+ header('Location: '.admin_url().'admin.php?page='.WPVIVID_PLUGIN_SLUG.'&action=wpvivid_one_drive_update&result=success');
196
+ return;
197
+ }
198
+ else
199
+ {
200
+ header('Location: '.admin_url().'admin.php?page='.WPVIVID_PLUGIN_SLUG.'&action=wpvivid_one_drive_update&result=error&error='.$ret['error']);
201
+ return;
202
+ }
203
+ }
204
+ else if($_GET['action']=='wpvivid_one_drive_update')
205
+ {
206
+ if(isset($_GET['result']))
207
+ {
208
+ if($_GET['result']=='success')
209
+ {
210
+ _e('<div class="notice notice-success is-dismissible"><p>You have successfully updated the storage alias.</p></div>');
211
+ }
212
+ else if($_GET['result']=='error')
213
+ {
214
+ _e('<div class="notice notice-error is-dismissible"><p>'.$_GET['error'].'</p></div>');
215
+ }
216
+ }
217
+ }
218
+ }
219
+ }
220
+
221
+ public function wpvivid_add_storage_tab_one_drive()
222
+ {
223
+ ?>
224
+ <div class="storage-providers" remote_type="one_drive" onclick="select_remote_storage(event, 'storage_account_one_drive');">
225
+ <img src="<?php echo esc_url(WPVIVID_PLUGIN_URL.'/admin/partials/images/storage-microsoft-onedrive.png'); ?>" style="vertical-align:middle;"/><?php _e('Microsoft OneDrive', 'wpvivid'); ?>
226
+ </div>
227
+ <?php
228
+ }
229
+
230
+ public function wpvivid_add_storage_page_one_drive()
231
+ {
232
+ ?>
233
+ <div id="storage_account_one_drive" class="storage-account-page" style="display:none;">
234
+ <p style="padding-left: 10px;">Please read <a target="_blank" href="https://wpvivid.com/privacy-policy">this privacy policy</a> for use of our Microsoft OneDrive authorization app (none of your backup data is sent to us).</p>
235
+ <h2><span><?php _e( 'Enter Your Microsoft OneDrive Information','wpvivid'); ?></span></h2>
236
+ <div class="storage-account-form">
237
+ <input type="text" autocomplete="off" option="one_drive" name="name" placeholder="Custom an unique name: Example: OneDrive-001" class="regular-text" onkeyup="value=value.replace(/[^a-zA-Z0-9\-_]/g,'')" />
238
+ </div>
239
+ <div style="padding-left: 10px; margin-bottom: -16px;">
240
+ <p><span><?php _e( 'Microsoft OneDrive Folder:','wpvivid'); ?></span><span option="one_drive" name="path"><?php _e(WPVIVID_ONEDRIVE_DEFAULT_FOLDER); ?></span></p>
241
+ </div>
242
+ <div class="remote-storage-set-default-block">
243
+ <label>
244
+ <input type="checkbox" option="one_drive" name="default" checked /><?php _e('Set as the default remote storage.', 'wpvivid'); ?>
245
+ </label>
246
+ </div>
247
+ <div id="wpvivid_storage_account_notice"></div>
248
+ <div class=""><input onclick="wpvivid_one_drive_auth()" class="button-primary storage-account-button" type="submit" value="<?php _e( 'Authenticate with Microsoft OneDrive', 'wpvivid' ); ?>" /></div>
249
+ <div style="clear:both;"></div>
250
+ <div style="padding-left: 10px;">Tips: Click the button above to get Microsoft authentication and add it to the storage list below.</div>
251
+ </div>
252
+ <script>
253
+ function wpvivid_check_onedrive_storage_alias(storage_alias){
254
+ var find = 1;
255
+ jQuery('#wpvivid_remote_storage_list tr').each(function (i) {
256
+ jQuery(this).children('td').each(function (j) {
257
+ if (j == 3) {
258
+ if (jQuery(this).text() == storage_alias) {
259
+ find = -1;
260
+ return false;
261
+ }
262
+ }
263
+ });
264
+ });
265
+ return find;
266
+ }
267
+ function wpvivid_one_drive_auth()
268
+ {
269
+ wpvivid_settings_changed = false;
270
+ var name='';
271
+ var path='';
272
+ jQuery('input:text[option=one_drive]').each(function()
273
+ {
274
+ var key = jQuery(this).prop('name');
275
+ if(key==='name')
276
+ {
277
+ name = jQuery(this).val();
278
+ }
279
+ });
280
+
281
+ var remote_default='0';
282
+
283
+ jQuery('input:checkbox[option=one_drive]').each(function()
284
+ {
285
+ if(jQuery(this).prop('checked')) {
286
+ remote_default='1';
287
+ }
288
+ else {
289
+ remote_default='0';
290
+ }
291
+ });
292
+ if(name == ''){
293
+ alert('Warning: An alias for remote storage is required.');
294
+ }
295
+ else if(wpvivid_check_onedrive_storage_alias(name) === -1){
296
+ alert("Warning: The alias already exists in storage list.");
297
+ }
298
+ else {
299
+ location.href = '<?php echo admin_url() . 'admin.php?page=WPvivid' . '&action=wpvivid_one_drive_auth&name='?>' + name + '&default=' + remote_default;
300
+ }
301
+ }
302
+ </script>
303
+ <?php
304
+ }
305
+
306
+ public function wpvivid_edit_storage_page_one_drive()
307
+ {
308
+ ?>
309
+ <div id="remote_storage_edit_onedrive" class="postbox storage-account-block remote-storage-edit" style="display:none;">
310
+ <h2><span><?php _e( 'Enter an alias for Microsoft OneDrive','wpvivid'); ?></span></h2>
311
+ <div class="storage-account-form">
312
+ <input type="text" option="edit-onedrive" name="name" placeholder="Custom an unique name: Example: OneDrive-001" class="regular-text" onkeyup="value=value.replace(/[^a-zA-Z0-9\-_]/g,'')" />
313
+ </div>
314
+ <div class=""><input onclick="wpvivid_one_drive_update_auth()" class="button-primary storage-account-button" type="button" value="<?php _e( 'Save Changes', 'wpvivid' ); ?>" /></div>
315
+ <div style="clear:both;"></div>
316
+ <div style="padding-left: 10px;">Tips: Get Microsoft authentication to change the alias.</div>
317
+ </div>
318
+ <script>
319
+ function wpvivid_one_drive_update_auth()
320
+ {
321
+ var name='';
322
+ jQuery('input:text[option=edit-onedrive]').each(function()
323
+ {
324
+ var key = jQuery(this).prop('name');
325
+ if(key==='name')
326
+ {
327
+ name = jQuery(this).val();
328
+ }
329
+ });
330
+ if(name == ''){
331
+ alert('Warning: An alias for remote storage is required.');
332
+ }
333
+ else if(wpvivid_check_onedrive_storage_alias(name) === -1){
334
+ alert("Warning: The alias already exists in storage list.");
335
+ }
336
+ else {
337
+ location.href = '<?php echo admin_url() . 'admin.php?page=WPvivid' . '&action=wpvivid_one_drive_update_auth&name='?>' + name + '&id=' + wpvivid_editing_storage_id;
338
+ }
339
+ }
340
+ </script>
341
+ <?php
342
+ }
343
+
344
+ public function sanitize_options($skip_name='')
345
+ {
346
+ $ret['result']=WPVIVID_SUCCESS;
347
+
348
+ if(!isset($this->options['name']))
349
+ {
350
+ $ret['error']="Warning: An alias for remote storage is required.";
351
+ return $ret;
352
+ }
353
+
354
+ $ret['options']=$this->options;
355
+ return $ret;
356
+ }
357
+
358
+ public function test_connect()
359
+ {
360
+ return array('result' => WPVIVID_SUCCESS);
361
+ }
362
+
363
+ public function upload($task_id, $files, $callback = '')
364
+ {
365
+ global $wpvivid_pulgin;
366
+
367
+ if($this->need_refresh())
368
+ {
369
+ $ret=$this->refresh_token();
370
+ if($ret['result']===WPVIVID_FAILED)
371
+ {
372
+ return $ret;
373
+ }
374
+ }
375
+
376
+ $path=$this->options['path'];
377
+
378
+ $ret=$this->check_folder($path);
379
+
380
+ if($ret['result']===WPVIVID_FAILED)
381
+ {
382
+ return $ret;
383
+ }
384
+
385
+ $upload_job=WPvivid_taskmanager::get_backup_sub_task_progress($task_id,'upload',WPVIVID_REMOTE_ONEDRIVE);
386
+ if(empty($upload_job))
387
+ {
388
+ $job_data=array();
389
+ foreach ($files as $file)
390
+ {
391
+ $file_data['size']=filesize($file);
392
+ $file_data['uploaded']=0;
393
+ $job_data[basename($file)]=$file_data;
394
+ }
395
+ WPvivid_taskmanager::update_backup_sub_task_progress($task_id,'upload',WPVIVID_REMOTE_ONEDRIVE,'0','Start uploading',$job_data);
396
+ }
397
+
398
+ foreach ($files as $file)
399
+ {
400
+ if(array_key_exists(basename($file),$upload_job['job_data']))
401
+ {
402
+ if($upload_job['job_data'][basename($file)]['uploaded']==1)
403
+ continue;
404
+ }
405
+
406
+ $this -> last_time = time();
407
+ $this -> last_size = 0;
408
+
409
+ if(!file_exists($file))
410
+ return array('result' =>WPVIVID_FAILED,'error' =>$file.' not found. The file might has been moved, renamed or deleted. Please reload the list and verify the file exists.');
411
+ $wpvivid_pulgin->wpvivid_log->WriteLog('Start uploading '.basename($file),'notice');
412
+ $result=$this->_upload($task_id, $file,$callback);
413
+ if($result['result'] !==WPVIVID_SUCCESS)
414
+ {
415
+ return $result;
416
+ }
417
+ }
418
+ return array('result' =>WPVIVID_SUCCESS);
419
+ }
420
+
421
+ public function cleanup($files)
422
+ {
423
+ set_time_limit(120);
424
+
425
+ $path=$this->options['path'];
426
+ if($this->need_refresh())
427
+ {
428
+ $ret=$this->refresh_token();
429
+ if($ret['result']===WPVIVID_FAILED)
430
+ {
431
+ return $ret;
432
+ }
433
+ }
434
+
435
+ $ret=$this->get_files_id($files,$path);
436
+ if($ret['result']==WPVIVID_SUCCESS)
437
+ {
438
+ $ids=$ret['ids'];
439
+ foreach ($ids as $id)
440
+ {
441
+ $this->delete_file($id);
442
+ }
443
+ }
444
+ else
445
+ {
446
+ return $ret;
447
+ }
448
+
449
+ return array('result' =>WPVIVID_SUCCESS);
450
+ }
451
+
452
+ public function download($file, $local_path, $callback = '')
453
+ {
454
+ $this -> current_file_name = $file['file_name'];
455
+ $this -> current_file_size = $file['size'];
456
+
457
+ global $wpvivid_pulgin;
458
+ $log_file_name=uniqid('test-');
459
+ $wpvivid_pulgin->wpvivid_log=new WPvivid_Log();
460
+ $wpvivid_pulgin->wpvivid_log->CreateLogFile($log_file_name,'no_folder','test');
461
+ if($this->need_refresh())
462
+ {
463
+ $ret=$this->refresh_token();
464
+ if($ret['result']===WPVIVID_FAILED)
465
+ {
466
+ return $ret;
467
+ }
468
+ }
469
+
470
+ $path=$this->options['path'];
471
+ $ret=$this->check_file($file['file_name'],$path);
472
+
473
+ if($ret['result']===WPVIVID_FAILED)
474
+ {
475
+ return $ret;
476
+ }
477
+
478
+ $file_path=$local_path.$file['file_name'];
479
+
480
+ $fh = fopen($file_path, 'a');
481
+
482
+ $downloaded_start=filesize($file_path);
483
+ $url='https://graph.microsoft.com/v1.0/me/drive/root:/'.$this->options['path'].'/'.$file['file_name'].':/content';
484
+ $download_size=WPVIVID_ONEDRIVE_DOWNLOAD_SIZE;
485
+ $size=$file['size'];
486
+ while($downloaded_start<$size)
487
+ {
488
+ $ret=$this->download_loop($url,$downloaded_start,$download_size,$size);
489
+ if($ret['result']!=WPVIVID_SUCCESS)
490
+ {
491
+ return $ret;
492
+ }
493
+
494
+ fwrite($fh,$ret['body']);
495
+
496
+ if((time() - $this -> last_time) >3)
497
+ {
498
+ if(is_callable($callback))
499
+ {
500
+ call_user_func_array($callback,array($downloaded_start,$this -> current_file_name,
501
+ $this->current_file_size,$this -> last_time,$this -> last_size));
502
+ }
503
+ $this -> last_size = $downloaded_start;
504
+ $this -> last_time = time();
505
+ }
506
+ }
507
+
508
+ fclose($fh);
509
+ return array('result' => WPVIVID_SUCCESS);
510
+ }
511
+
512
+ private function download_loop($url,&$downloaded_start,$download_size,$file_size,$retry_count=0)
513
+ {
514
+ global $wpvivid_pulgin;
515
+
516
+ $downloaded_end=min($downloaded_start+$download_size-1,$file_size-1);
517
+ $headers['Range']="bytes=$downloaded_start-$downloaded_end";
518
+ $response=$this->remote_get($url,$headers,false,15);
519
+
520
+ if($response['result']==WPVIVID_SUCCESS)
521
+ {
522
+ $downloaded_start=$downloaded_end+1;
523
+ $ret['result']=WPVIVID_SUCCESS;
524
+ $ret['body']=$response['body'];
525
+ return $ret;
526
+ }
527
+ else
528
+ {
529
+ if($retry_count<WPVIVID_ONEDRIVE_RETRY_TIMES)
530
+ {
531
+ $retry_count++;
532
+ return $this->download_loop($url,$downloaded_start,$download_size,$file_size,$retry_count);
533
+ }
534
+ else
535
+ {
536
+ return $response;
537
+ }
538
+ }
539
+ }
540
+
541
+ private function need_refresh()
542
+ {
543
+ if(time()-120> $this->options['token']['expires'])
544
+ {
545
+ return true;
546
+ }
547
+ else
548
+ {
549
+ return false;
550
+ }
551
+ }
552
+
553
+ private function refresh_token()
554
+ {
555
+ $args['method']='POST';
556
+ $args['wpvivid_refresh_token']=1;
557
+ $args['body']=array( 'wpvivid_refresh_token' => '1', 'refresh_token' => $this->options['token']['refresh_token']);
558
+ $response=wp_remote_post('https://auth.wpvivid.com/onedrive',$args);
559
+ if(!is_wp_error($response) && ($response['response']['code'] == 200))
560
+ {
561
+ $json =stripslashes($response['body']);
562
+ $json_ret =json_decode($json,true);
563
+ if($json_ret['result']=='success')
564
+ {
565
+ $this->options['token']=$json_ret['token'];
566
+ $this->options['token']['expires']=time()+ $json_ret['token']['expires_in'];
567
+ WPvivid_Setting::update_remote_option($this->options['id'],$this->options);
568
+ $ret['result']=WPVIVID_SUCCESS;
569
+ return $ret;
570
+ }
571
+ else{
572
+ $ret['result']=WPVIVID_FAILED;
573
+ $ret['error']=$json_ret['error'];
574
+ return $ret;
575
+ }
576
+ }
577
+ else
578
+ {
579
+ $ret['result']=WPVIVID_FAILED;
580
+ if ( is_wp_error( $response ) )
581
+ {
582
+ $ret['error']= $response->get_error_message();
583
+ }
584
+ else
585
+ {
586
+ $ret['error']=$response['response']['message'];
587
+ }
588
+ return $ret;
589
+ }
590
+ }
591
+
592
+ private function check_folder($folder)
593
+ {
594
+ $url='https://graph.microsoft.com/v1.0/me/drive/root:/'.$folder.'?$select=id,name,folder';
595
+ $response=$this->remote_get($url);
596
+ if($response['result']==WPVIVID_SUCCESS)
597
+ {
598
+ $ret['result']=WPVIVID_SUCCESS;
599
+ return $ret;
600
+ }
601
+ else
602
+ {
603
+ if(isset($response['code'])&&$response['code'] ==404)
604
+ {
605
+ $body=array( 'name' => $folder, 'folder' => ["childCount" => '0']);
606
+ $body=json_encode($body);
607
+ $url='https://graph.microsoft.com/v1.0/me/drive/root/children';
608
+
609
+ $response=$this->remote_post($url,array(),$body);
610
+ if($response['result']==WPVIVID_SUCCESS)
611
+ {
612
+ $ret['result']=WPVIVID_SUCCESS;
613
+ return $ret;
614
+ }
615
+ else
616
+ {
617
+ return $response;
618
+ }
619
+ }
620
+ else
621
+ {
622
+ return $response;
623
+ }
624
+ }
625
+ }
626
+
627
+ private function check_file($file,$folder)
628
+ {
629
+ $url='https://graph.microsoft.com/v1.0/me/drive/root:/'.$folder.'/'.$file.'?$select=id,name,size';
630
+
631
+ $response=$this->remote_get($url);
632
+ if($response['result']==WPVIVID_SUCCESS)
633
+ {
634
+ $ret['result']=WPVIVID_SUCCESS;
635
+ return $ret;
636
+ }
637
+ else
638
+ {
639
+ return $response;
640
+ }
641
+ }
642
+
643
+ private function _upload($task_id,$local_file,$callback)
644
+ {
645
+ $this -> current_file_size = filesize($local_file);
646
+ $this -> current_file_name = basename($local_file);
647
+
648
+ $ret=$this->delete_file_by_name($this->options['path'],basename($local_file));
649
+
650
+ if($ret['result']===WPVIVID_FAILED)
651
+ {
652
+ if($ret['error']!='file not found')
653
+ return $ret;
654
+ }
655
+
656
+ $file_size=filesize($local_file);
657
+
658
+ //small file
659
+ if($file_size<1024*1024*4)
660
+ {
661
+ $ret=$this->upload_small_file($local_file,$task_id);
662
+ return $ret;
663
+ }
664
+ else
665
+ {
666
+ //big file
667
+ $ret=$this->create_upload_session(basename($local_file));
668
+
669
+ if($ret['result']===WPVIVID_FAILED)
670
+ {
671
+ return $ret;
672
+ }
673
+
674
+ $ret=$this->upload_resume($ret['session_url'],$local_file,$task_id,$callback);
675
+
676
+ return $ret;
677
+ }
678
+ }
679
+
680
+ private function upload_small_file($file,$task_id)
681
+ {
682
+ $upload_job=WPvivid_taskmanager::get_backup_sub_task_progress($task_id,'upload',WPVIVID_REMOTE_ONEDRIVE);
683
+
684
+ $path=$this->options['path'].'/'.basename($file);
685
+ $args['method']='PUT';
686
+ $args['headers']=array( 'Authorization' => 'bearer '.$this->options['token']['access_token'],'content-type' => 'application/zip');
687
+ $args['timeout']=15;
688
+
689
+ $data=file_get_contents($file);
690
+ $args['body']=$data;
691
+
692
+ WPvivid_taskmanager::update_backup_sub_task_progress($task_id,'upload',WPVIVID_REMOTE_ONEDRIVE,'0','Start uploading '.basename($file).'.',$upload_job['job_data']);
693
+
694
+ $response=wp_remote_post('https://graph.microsoft.com/v1.0/me/drive/root:/'.$path.':/content',$args);
695
+
696
+ if(!is_wp_error($response) && ($response['response']['code'] == 200||$response['response']['code'] == 201))
697
+ {
698
+ $upload_job['job_data'][basename($file)]['uploaded']=1;
699
+ WPvivid_taskmanager::update_backup_sub_task_progress($task_id,'upload',WPVIVID_REMOTE_ONEDRIVE,'0','Uploading '.basename($file).' completed.',$upload_job['job_data']);
700
+ return array('result' =>WPVIVID_SUCCESS);
701
+ }
702
+ else
703
+ {
704
+ $ret['result']=WPVIVID_FAILED;
705
+ if ( is_wp_error( $response ) )
706
+ {
707
+ $ret['error']= $response->get_error_message();
708
+ }
709
+ else
710
+ {
711
+ $error=json_decode($response['body'],1);
712
+ $ret['error']=$error['error']['message'];
713
+ }
714
+ return $ret;
715
+ }
716
+ }
717
+
718
+ private function upload_resume($session_url,$file,$task_id,$callback)
719
+ {
720
+ global $wpvivid_pulgin;
721
+ $upload_job=WPvivid_taskmanager::get_backup_sub_task_progress($task_id,'upload',WPVIVID_REMOTE_ONEDRIVE);
722
+
723
+ $offset=0;
724
+
725
+ WPvivid_taskmanager::update_backup_sub_task_progress($task_id,'upload',WPVIVID_REMOTE_ONEDRIVE,'0','Start uploading '.basename($file).'.',$upload_job['job_data']);
726
+
727
+ $file_size=filesize($file);
728
+ $handle=fopen($file,'rb');
729
+ $upload_size=WPVIVID_ONEDRIVE_UPLOAD_SIZE;
730
+ $upload_end=min($offset+$upload_size-1,$file_size-1);
731
+ while(true)
732
+ {
733
+ $ret=$this->upload_loop($session_url,$handle,$offset,$upload_end,$upload_size,$file_size);
734
+
735
+ if($ret['result']==WPVIVID_SUCCESS)
736
+ {
737
+ if((time() - $this -> last_time) >3)
738
+ {
739
+ if(is_callable($callback))
740
+ {
741
+ call_user_func_array($callback,array($offset,$this -> current_file_name,
742
+ $this->current_file_size,$this -> last_time,$this -> last_size));
743
+ }
744
+ $this -> last_size = $offset;
745
+ $this -> last_time = time();
746
+ }
747
+
748
+ if($ret['op']=='continue')
749
+ {
750
+ continue;
751
+ }
752
+ else
753
+ {
754
+ break;
755
+ }
756
+ }
757
+ else
758
+ {
759
+ return $ret;
760
+ }
761
+ }
762
+
763
+ fclose($handle);
764
+ $upload_job['job_data'][basename($file)]['uploaded']=1;
765
+ $wpvivid_pulgin->wpvivid_log->WriteLog('Finished uploading '.basename($file),'notice');
766
+ WPvivid_taskmanager::update_backup_sub_task_progress($task_id,'upload',WPVIVID_REMOTE_ONEDRIVE,'0','Uploading '.basename($file).' completed.',$upload_job['job_data']);
767
+ return array('result' =>WPVIVID_SUCCESS);
768
+ }
769
+
770
+ private function create_upload_session($file)
771
+ {
772
+ $path=$this->options['path'].'/'.basename($file);
773
+ $url='https://graph.microsoft.com/v1.0/me/drive/root:/'.$path.':/createUploadSession';
774
+ $response=$this->remote_post($url);
775
+
776
+ if($response['result']==WPVIVID_SUCCESS)
777
+ {
778
+ $upload_session=$response['body']['uploadUrl'];
779
+
780
+ $ret['result']=WPVIVID_SUCCESS;
781
+ $ret['session_url']=$upload_session;
782
+ return $ret;
783
+ }
784
+ else
785
+ {
786
+ return $response;
787
+ }
788
+ }
789
+
790
+ private function upload_loop($url,$file_handle,&$uploaded,&$upload_end,$upload_size,$file_size,$retry_count=0)
791
+ {
792
+ $curl = curl_init();
793
+
794
+ curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
795
+
796
+ $upload_size=min($upload_size,$file_size-$uploaded);
797
+
798
+ if ($uploaded)
799
+ fseek($file_handle, $uploaded);
800
+
801
+ $headers = array(
802
+ "Content-Length: $upload_size",
803
+ "Content-Range: bytes $uploaded-$upload_end/".$file_size,
804
+ );
805
+ $headers[] = 'Authorization: Bearer ' . $this->options['token']['access_token'];
806
+
807
+ $options = array(
808
+ CURLOPT_URL => $url,
809
+ CURLOPT_HTTPHEADER => $headers,
810
+ CURLOPT_PUT => true,
811
+ CURLOPT_INFILE => $file_handle,
812
+ CURLOPT_INFILESIZE => $upload_size,
813
+ CURLOPT_RETURNTRANSFER=>true,
814
+ );
815
+
816
+ curl_setopt_array($curl, $options);
817
+
818
+ global $wpvivid_pulgin;
819
+
820
+ $response=curl_exec($curl);
821
+
822
+ $http_code = curl_getinfo($curl,CURLINFO_HTTP_CODE);
823
+
824
+ if($response!=false)
825
+ {
826
+ curl_close($curl);
827
+ if($http_code==202)
828
+ {
829
+ $json=json_decode($response,1);
830
+ $ranges=$json['nextExpectedRanges'];
831
+
832
+ if (is_array($ranges))
833
+ {
834
+ $range = $ranges[0];
835
+ } else {
836
+ $range=$ranges;
837
+ }
838
+
839
+ if (preg_match('/^(\d+)/', $range, $matches))
840
+ {
841
+ $uploaded = $matches[1];
842
+ $upload_end=min($uploaded+$upload_size-1,$file_size-1);
843
+ }
844
+
845
+ $ret['result']=WPVIVID_SUCCESS;
846
+ $ret['op']='continue';
847
+ return $ret;
848
+ }
849
+ else if($http_code==200||201)
850
+ {
851
+ $ret['result']=WPVIVID_SUCCESS;
852
+ $ret['op']='finished';
853
+ return $ret;
854
+ }
855
+ else
856
+ {
857
+ if($retry_count<WPVIVID_ONEDRIVE_RETRY_TIMES)
858
+ {
859
+ $retry_count++;
860
+ return $this->upload_loop($url,$file_handle,$uploaded,$upload_end,$upload_size,$file_size,$retry_count);
861
+ }
862
+ else
863
+ {
864
+ $ret['result']=WPVIVID_FAILED;
865
+ $error=json_decode($response,1);
866
+ $ret['error']=$error['error']['message'];
867
+ return $ret;
868
+ }
869
+ }
870
+ }
871
+ else
872
+ {
873
+ if($retry_count<WPVIVID_ONEDRIVE_RETRY_TIMES)
874
+ {
875
+ $retry_count++;
876
+ return $this->upload_loop($url,$file_handle,$uploaded,$upload_end,$upload_size,$file_size,$retry_count);
877
+ }
878
+ else
879
+ {
880
+ $ret['result']=WPVIVID_FAILED;
881
+ $ret['error']=curl_error($curl);
882
+ curl_close($curl);
883
+ return $ret;
884
+ }
885
+ }
886
+ }
887
+
888
+ private function get_files_id($files,$path)
889
+ {
890
+ $ret['ids']=array();
891
+ foreach ($files as $file)
892
+ {
893
+ $url='https://graph.microsoft.com/v1.0/me/drive/root:/'.$path.'/'.$file.'?$select=id';
894
+ $response=$this->remote_get($url);
895
+ if($response['result']==WPVIVID_SUCCESS)
896
+ {
897
+ if($response['code']==200)
898
+ {
899
+ $ret['ids'][]=$response['body']['id'];
900
+ }
901
+ }
902
+ else
903
+ {
904
+ continue;
905
+ }
906
+ }
907
+
908
+ if(sizeof($ret['ids'])==0)
909
+ {
910
+ $ret['result']=WPVIVID_FAILED;
911
+ $ret['error']='file not found';
912
+ }
913
+ else
914
+ {
915
+ $ret['result']=WPVIVID_SUCCESS;
916
+ }
917
+
918
+ return $ret;
919
+ }
920
+
921
+ private function delete_file($id)
922
+ {
923
+ $args['method']='DELETE';
924
+ $args['headers']=array( 'Authorization' => 'bearer '.$this->options['token']['access_token']);
925
+ $args['timeout']=10;
926
+
927
+ $response = wp_remote_request( 'https://graph.microsoft.com/v1.0/me/drive/items/'.$id,$args);
928
+
929
+ if(!is_wp_error($response) && ($response['response']['code'] == 204))
930
+ {
931
+ $ret['result']=WPVIVID_SUCCESS;
932
+ return $ret;
933
+ }
934
+ else
935
+ {
936
+ $ret['result']=WPVIVID_FAILED;
937
+ if ( is_wp_error( $response ) )
938
+ {
939
+ $ret['error']= $response->get_error_message();
940
+ }
941
+ else
942
+ {
943
+ $ret['error']= $response['body'];
944
+ }
945
+ return $ret;
946
+ }
947
+ }
948
+
949
+ private function remote_get($url,$header=array(),$decode=true,$timeout=10,$except_code=array())
950
+ {
951
+ if(empty($except_code))
952
+ {
953
+ $except_code=array(200,201,202,204,206);
954
+ }
955
+ $args['timeout']=$timeout;
956
+ $args['headers']['Authorization']= 'bearer '.$this->options['token']['access_token'];
957
+ $args['headers']= $args['headers']+$header;
958
+ $response=wp_remote_get($url,$args);
959
+
960
+ if(!is_wp_error($response))
961
+ {
962
+ $ret['code']=$response['response']['code'];
963
+ if(in_array($response['response']['code'],$except_code))
964
+ {
965
+ $ret['result']=WPVIVID_SUCCESS;
966
+ if($decode)
967
+ $ret['body']=json_decode($response['body'],1);
968
+ else
969
+ $ret['body']=$response['body'];
970
+ }
971
+ else
972
+ {
973
+ $ret['result']=WPVIVID_FAILED;
974
+ $error=json_decode($response['body'],1);
975
+ $ret['error']=$error['error']['message'].' http code:'.$response['response']['code'];
976
+ }
977
+ return $ret;
978
+ }
979
+ else
980
+ {
981
+ $ret['result']=WPVIVID_FAILED;
982
+ $ret['error']=$response->get_error_message();
983
+ return $ret;
984
+ }
985
+ }
986
+
987
+ private function remote_post($url,$header=array(),$body=null,$except_code=array())
988
+ {
989
+ if(empty($except_code))
990
+ {
991
+ $except_code=array(200,201,202,204,206);
992
+ }
993
+
994
+ $args['method']='POST';
995
+ $args['headers']=array( 'Authorization' => 'bearer '.$this->options['token']['access_token'],'content-type' => 'application/json');
996
+ $args['headers']=$args['headers']+$header;
997
+ if(!is_null($body))
998
+ {
999
+ $args['body']=$body;
1000
+ }
1001
+ $args['timeout']=10;
1002
+
1003
+ $response=wp_remote_post($url,$args);
1004
+
1005
+ if(!is_wp_error($response))
1006
+ {
1007
+ $ret['code']=$response['response']['code'];
1008
+ if(in_array($response['response']['code'],$except_code))
1009
+ {
1010
+ $ret['result']=WPVIVID_SUCCESS;
1011
+ $ret['body']=json_decode($response['body'],1);
1012
+ }
1013
+ else
1014
+ {
1015
+ $ret['result']=WPVIVID_FAILED;
1016
+ $error=json_decode($response['body'],1);
1017
+ $ret['error']=$error['error']['message'];
1018
+ }
1019
+ return $ret;
1020
+ }
1021
+ else
1022
+ {
1023
+ $ret['result']=WPVIVID_FAILED;
1024
+ $ret['error']=$response->get_error_message();
1025
+ return $ret;
1026
+ }
1027
+ }
1028
+
1029
+ private function delete_file_by_name($folder,$file_name)
1030
+ {
1031
+ $files[]=$file_name;
1032
+ $ret=$this->get_files_id($files,$folder);
1033
+
1034
+ if($ret['result']==WPVIVID_SUCCESS)
1035
+ {
1036
+ $ids=$ret['ids'];
1037
+ foreach ($ids as $id)
1038
+ {
1039
+ $ret=$this->delete_file($id);
1040
+ if($ret['result']==WPVIVID_FAILED)
1041
+ {
1042
+ return $ret;
1043
+ }
1044
+ }
1045
+ }
1046
+ else
1047
+ {
1048
+ return $ret;
1049
+ }
1050
+
1051
+ return array('result' =>WPVIVID_SUCCESS);
1052
+ }
1053
+
1054
+ public function wpvivid_remote_pic_one_drive($remote)
1055
+ {
1056
+ $remote['onedrive']['default_pic'] = '/admin/partials/images/storage-microsoft-onedrive(gray).png';
1057
+ $remote['onedrive']['selected_pic'] = '/admin/partials/images/storage-microsoft-onedrive.png';
1058
+ $remote['onedrive']['title'] = 'Microsoft OneDrive';
1059
+ return $remote;
1060
+ }
1061
+
1062
+ public function wpvivid_get_out_of_date_one_drive($out_of_date_remote, $remote)
1063
+ {
1064
+ if($remote['type'] == WPVIVID_REMOTE_ONEDRIVE){
1065
+ $out_of_date_remote = $remote['path'];
1066
+ }
1067
+ return $out_of_date_remote;
1068
+ }
1069
+
1070
+ public function wpvivid_storage_provider_one_drive($storage_type)
1071
+ {
1072
+ if($storage_type == WPVIVID_REMOTE_ONEDRIVE){
1073
+ $storage_type = 'Microsoft OneDrive';
1074
+ }
1075
+ return $storage_type;
1076
+ }
1077
+ }
includes/customclass/client_secrets.json ADDED
@@ -0,0 +1 @@
 
1
+ {"web":{"client_id":"134809148507-32crusepgace4h6g47ota99jjrvf4j1u.apps.googleusercontent.com","project_id":"wpvivid-auth","auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://oauth2.googleapis.com/token","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs","client_secret":"GmD5Kmg_1fTcf0ciNEomposy","redirect_uris":["https://auth.wpvivid.com/google_drive"]}}
includes/lib/google-api-php-client/src/Google/AccessToken/Revoke.php ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * Copyright 2008 Google Inc.
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */
18
+
19
+ use Google\Auth\HttpHandler\HttpHandlerFactory;
20
+ use GuzzleHttp\ClientInterface;
21
+ use GuzzleHttp\Psr7;
22
+ use GuzzleHttp\Psr7\Request;
23
+
24
+ /**
25
+ * Wrapper around Google Access Tokens which provides convenience functions
26
+ *
27
+ */
28
+ class Google_AccessToken_Revoke
29
+ {
30
+ /**
31
+ * @var GuzzleHttp\ClientInterface The http client
32
+ */
33
+ private $http;
34
+
35
+ /**
36
+ * Instantiates the class, but does not initiate the login flow, leaving it
37
+ * to the discretion of the caller.
38
+ */
39
+ public function __construct(ClientInterface $http = null)
40
+ {
41
+ $this->http = $http;
42
+ }
43
+
44
+ /**
45
+ * Revoke an OAuth2 access token or refresh token. This method will revoke the current access
46
+ * token, if a token isn't provided.
47
+ *
48
+ * @param string|array $token The token (access token or a refresh token) that should be revoked.
49
+ * @return boolean Returns True if the revocation was successful, otherwise False.
50
+ */
51
+ public function revokeToken($token)
52
+ {
53
+ if (is_array($token)) {
54
+ if (isset($token['refresh_token'])) {
55
+ $token = $token['refresh_token'];
56
+ } else {
57
+ $token = $token['access_token'];
58
+ }
59
+ }
60
+
61
+ $body = Psr7\stream_for(http_build_query(array('token' => $token)));
62
+ $request = new Request(
63
+ 'POST',
64
+ Google_Client::OAUTH2_REVOKE_URI,
65
+ [
66
+ 'Cache-Control' => 'no-store',
67
+ 'Content-Type' => 'application/x-www-form-urlencoded',
68
+ ],
69
+ $body
70
+ );
71
+
72
+ $httpHandler = HttpHandlerFactory::build($this->http);
73
+
74
+ $response = $httpHandler($request);
75
+
76
+ return $response->getStatusCode() == 200;
77
+ }
78
+ }
includes/lib/google-api-php-client/src/Google/AccessToken/Verify.php ADDED
@@ -0,0 +1,273 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * Copyright 2008 Google Inc.
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */
18
+
19
+ use Firebase\JWT\ExpiredException as ExpiredExceptionV3;
20
+ use Firebase\JWT\SignatureInvalidException;
21
+ use GuzzleHttp\Client;
22
+ use GuzzleHttp\ClientInterface;
23
+ use Psr\Cache\CacheItemPoolInterface;
24
+ use Google\Auth\Cache\MemoryCacheItemPool;
25
+ use Stash\Driver\FileSystem;
26
+ use Stash\Pool;
27
+
28
+ /**
29
+ * Wrapper around Google Access Tokens which provides convenience functions
30
+ *
31
+ */
32
+ class Google_AccessToken_Verify
33
+ {
34
+ const FEDERATED_SIGNON_CERT_URL = 'https://www.googleapis.com/oauth2/v3/certs';
35
+ const OAUTH2_ISSUER = 'accounts.google.com';
36
+ const OAUTH2_ISSUER_HTTPS = 'https://accounts.google.com';
37
+
38
+ /**
39
+ * @var GuzzleHttp\ClientInterface The http client
40
+ */
41
+ private $http;
42
+
43
+ /**
44
+ * @var Psr\Cache\CacheItemPoolInterface cache class
45
+ */
46
+ private $cache;
47
+
48
+ /**
49
+ * Instantiates the class, but does not initiate the login flow, leaving it
50
+ * to the discretion of the caller.
51
+ */
52
+ public function __construct(
53
+ ClientInterface $http = null,
54
+ CacheItemPoolInterface $cache = null,
55
+ $jwt = null
56
+ ) {
57
+ if (null === $http) {
58
+ $http = new Client();
59
+ }
60
+
61
+ if (null === $cache) {
62
+ $cache = new MemoryCacheItemPool;
63
+ }
64
+
65
+ $this->http = $http;
66
+ $this->cache = $cache;
67
+ $this->jwt = $jwt ?: $this->getJwtService();
68
+ }
69
+
70
+ /**
71
+ * Verifies an id token and returns the authenticated apiLoginTicket.
72
+ * Throws an exception if the id token is not valid.
73
+ * The audience parameter can be used to control which id tokens are
74
+ * accepted. By default, the id token must have been issued to this OAuth2 client.
75
+ *
76
+ * @param $audience
77
+ * @return array the token payload, if successful
78
+ */
79
+ public function verifyIdToken($idToken, $audience = null)
80
+ {
81
+ if (empty($idToken)) {
82
+ throw new LogicException('id_token cannot be null');
83
+ }
84
+
85
+ // set phpseclib constants if applicable
86
+ $this->setPhpsecConstants();
87
+
88
+ // Check signature
89
+ $certs = $this->getFederatedSignOnCerts();
90
+ foreach ($certs as $cert) {
91
+ $bigIntClass = $this->getBigIntClass();
92
+ $rsaClass = $this->getRsaClass();
93
+ $modulus = new $bigIntClass($this->jwt->urlsafeB64Decode($cert['n']), 256);
94
+ $exponent = new $bigIntClass($this->jwt->urlsafeB64Decode($cert['e']), 256);
95
+
96
+ $rsa = new $rsaClass();
97
+ $rsa->loadKey(array('n' => $modulus, 'e' => $exponent));
98
+
99
+ try {
100
+ $payload = $this->jwt->decode(
101
+ $idToken,
102
+ $rsa->getPublicKey(),
103
+ array('RS256')
104
+ );
105
+
106
+ if (property_exists($payload, 'aud')) {
107
+ if ($audience && $payload->aud != $audience) {
108
+ return false;
109
+ }
110
+ }
111
+
112
+ // support HTTP and HTTPS issuers
113
+ // @see https://developers.google.com/identity/sign-in/web/backend-auth
114
+ $issuers = array(self::OAUTH2_ISSUER, self::OAUTH2_ISSUER_HTTPS);
115
+ if (!isset($payload->iss) || !in_array($payload->iss, $issuers)) {
116
+ return false;
117
+ }
118
+
119
+ return (array) $payload;
120
+ } catch (ExpiredException $e) {
121
+ return false;
122
+ } catch (ExpiredExceptionV3 $e) {
123
+ return false;
124
+ } catch (SignatureInvalidException $e) {
125
+ // continue
126
+ } catch (DomainException $e) {
127
+ // continue
128
+ }
129
+ }
130
+
131
+ return false;
132
+ }
133
+
134
+ private function getCache()
135
+ {
136
+ return $this->cache;
137
+ }
138
+
139
+ /**
140
+ * Retrieve and cache a certificates file.
141
+ *
142
+ * @param $url string location
143
+ * @throws Google_Exception
144
+ * @return array certificates
145
+ */
146
+ private function retrieveCertsFromLocation($url)
147
+ {
148
+ // If we're retrieving a local file, just grab it.
149
+ if (0 !== strpos($url, 'http')) {
150
+ if (!$file = file_get_contents($url)) {
151
+ throw new Google_Exception(
152
+ "Failed to retrieve verification certificates: '" .
153
+ $url . "'."
154
+ );
155
+ }
156
+
157
+ return json_decode($file, true);
158
+ }
159
+
160
+ $response = $this->http->get($url);
161
+
162
+ if ($response->getStatusCode() == 200) {
163
+ return json_decode((string) $response->getBody(), true);
164
+ }
165
+ throw new Google_Exception(
166
+ sprintf(
167
+ 'Failed to retrieve verification certificates: "%s".',
168
+ $response->getBody()->getContents()
169
+ ),
170
+ $response->getStatusCode()
171
+ );
172
+ }
173
+
174
+ // Gets federated sign-on certificates to use for verifying identity tokens.
175
+ // Returns certs as array structure, where keys are key ids, and values
176
+ // are PEM encoded certificates.
177
+ private function getFederatedSignOnCerts()
178
+ {
179
+ $certs = null;
180
+ if ($cache = $this->getCache()) {
181
+ $cacheItem = $cache->getItem('federated_signon_certs_v3');
182
+ $certs = $cacheItem->get();
183
+ }
184
+
185
+
186
+ if (!$certs) {
187
+ $certs = $this->retrieveCertsFromLocation(
188
+ self::FEDERATED_SIGNON_CERT_URL
189
+ );
190
+
191
+ if ($cache) {
192
+ $cacheItem->expiresAt(new DateTime('+1 hour'));
193
+ $cacheItem->set($certs);
194
+ $cache->save($cacheItem);
195
+ }
196
+ }
197
+
198
+ if (!isset($certs['keys'])) {
199
+ throw new InvalidArgumentException(
200
+ 'federated sign-on certs expects "keys" to be set'
201
+ );
202
+ }
203
+
204
+ return $certs['keys'];
205
+ }
206
+
207
+ private function getJwtService()
208
+ {
209
+ $jwtClass = 'JWT';
210
+ if (class_exists('\Firebase\JWT\JWT')) {
211
+ $jwtClass = 'Firebase\JWT\JWT';
212
+ }
213
+
214
+ if (property_exists($jwtClass, 'leeway') && $jwtClass::$leeway < 1) {
215
+ // Ensures JWT leeway is at least 1
216
+ // @see https://github.com/google/google-api-php-client/issues/827
217
+ $jwtClass::$leeway = 1;
218
+ }
219
+
220
+ return new $jwtClass;
221
+ }
222
+
223
+ private function getRsaClass()
224
+ {
225
+ if (class_exists('phpseclib\Crypt\RSA')) {
226
+ return 'phpseclib\Crypt\RSA';
227
+ }
228
+
229
+ return 'Crypt_RSA';
230
+ }
231
+
232
+ private function getBigIntClass()
233
+ {
234
+ if (class_exists('phpseclib\Math\BigInteger')) {
235
+ return 'phpseclib\Math\BigInteger';
236
+ }
237
+
238
+ return 'Math_BigInteger';
239
+ }
240
+
241
+ private function getOpenSslConstant()
242
+ {
243
+ if (class_exists('phpseclib\Crypt\RSA')) {
244
+ return 'phpseclib\Crypt\RSA::MODE_OPENSSL';
245
+ }
246
+
247
+ if (class_exists('Crypt_RSA')) {
248
+ return 'CRYPT_RSA_MODE_OPENSSL';
249
+ }
250
+
251
+ throw new \Exception('Cannot find RSA class');
252
+ }
253
+
254
+ /**
255
+ * phpseclib calls "phpinfo" by default, which requires special
256
+ * whitelisting in the AppEngine VM environment. This function
257
+ * sets constants to bypass the need for phpseclib to check phpinfo
258
+ *
259
+ * @see phpseclib/Math/BigInteger
260
+ * @see https://github.com/GoogleCloudPlatform/getting-started-php/issues/85
261
+ */
262
+ private function setPhpsecConstants()
263
+ {
264
+ if (filter_var(getenv('GAE_VM'), FILTER_VALIDATE_BOOLEAN)) {
265
+ if (!defined('MATH_BIGINTEGER_OPENSSL_ENABLED')) {
266
+ define('MATH_BIGINTEGER_OPENSSL_ENABLED', true);
267
+ }
268
+ if (!defined('CRYPT_RSA_MODE')) {
269
+ define('CRYPT_RSA_MODE', constant($this->getOpenSslConstant()));
270
+ }
271
+ }
272
+ }
273
+ }
includes/lib/google-api-php-client/src/Google/AuthHandler/AuthHandlerFactory.php ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright 2015 Google Inc. All Rights Reserved.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ use GuzzleHttp\Client;
19
+ use GuzzleHttp\ClientInterface;
20
+
21
+ class Google_AuthHandler_AuthHandlerFactory
22
+ {
23
+ /**
24
+ * Builds out a default http handler for the installed version of guzzle.
25
+ *
26
+ * @return Google_AuthHandler_Guzzle5AuthHandler|Google_AuthHandler_Guzzle6AuthHandler
27
+ * @throws Exception
28
+ */
29
+ public static function build($cache = null, array $cacheConfig = [])
30
+ {
31
+ $version = ClientInterface::VERSION;
32
+
33
+ switch ($version[0]) {
34
+ case '5':
35
+ return new Google_AuthHandler_Guzzle5AuthHandler($cache, $cacheConfig);
36
+ case '6':
37
+ return new Google_AuthHandler_Guzzle6AuthHandler($cache, $cacheConfig);
38
+ default:
39
+ throw new Exception('Version not supported');
40
+ }
41
+ }
42
+ }
includes/lib/google-api-php-client/src/Google/AuthHandler/Guzzle5AuthHandler.php ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ use Google\Auth\CredentialsLoader;
4
+ use Google\Auth\HttpHandler\HttpHandlerFactory;
5
+ use Google\Auth\FetchAuthTokenCache;
6
+ use Google\Auth\Subscriber\AuthTokenSubscriber;
7
+ use Google\Auth\Subscriber\ScopedAccessTokenSubscriber;
8
+ use Google\Auth\Subscriber\SimpleSubscriber;
9
+ use GuzzleHttp\Client;
10
+ use GuzzleHttp\ClientInterface;
11
+ use Psr\Cache\CacheItemPoolInterface;
12
+
13
+ /**
14
+ *
15
+ */
16
+ class Google_AuthHandler_Guzzle5AuthHandler
17
+ {
18
+ protected $cache;
19
+ protected $cacheConfig;
20
+
21
+ public function __construct(CacheItemPoolInterface $cache = null, array $cacheConfig = [])
22
+ {
23
+ $this->cache = $cache;
24
+ $this->cacheConfig = $cacheConfig;
25
+ }
26
+
27
+ public function attachCredentials(
28
+ ClientInterface $http,
29
+ CredentialsLoader $credentials,
30
+ callable $tokenCallback = null
31
+ ) {
32
+ // use the provided cache
33
+ if ($this->cache) {
34
+ $credentials = new FetchAuthTokenCache(
35
+ $credentials,
36
+ $this->cacheConfig,
37
+ $this->cache
38
+ );
39
+ }
40
+ // if we end up needing to make an HTTP request to retrieve credentials, we
41
+ // can use our existing one, but we need to throw exceptions so the error
42
+ // bubbles up.
43
+ $authHttp = $this->createAuthHttp($http);
44
+ $authHttpHandler = HttpHandlerFactory::build($authHttp);
45
+ $subscriber = new AuthTokenSubscriber(
46
+ $credentials,
47
+ $authHttpHandler,
48
+ $tokenCallback
49
+ );
50
+
51
+ $http->setDefaultOption('auth', 'google_auth');
52
+ $http->getEmitter()->attach($subscriber);
53
+
54
+ return $http;
55
+ }
56
+
57
+ public function attachToken(ClientInterface $http, array $token, array $scopes)
58
+ {
59
+ $tokenFunc = function ($scopes) use ($token) {
60
+ return $token['access_token'];
61
+ };
62
+
63
+ $subscriber = new ScopedAccessTokenSubscriber(
64
+ $tokenFunc,
65
+ $scopes,
66
+ $this->cacheConfig,
67
+ $this->cache
68
+ );
69
+
70
+ $http->setDefaultOption('auth', 'scoped');
71
+ $http->getEmitter()->attach($subscriber);
72
+
73
+ return $http;
74
+ }
75
+
76
+ public function attachKey(ClientInterface $http, $key)
77
+ {
78
+ $subscriber = new SimpleSubscriber(['key' => $key]);
79
+
80
+ $http->setDefaultOption('auth', 'simple');
81
+ $http->getEmitter()->attach($subscriber);
82
+
83
+ return $http;
84
+ }
85
+
86
+ private function createAuthHttp(ClientInterface $http)
87
+ {
88
+ return new Client(
89
+ [
90
+ 'base_url' => $http->getBaseUrl(),
91
+ 'defaults' => [
92
+ 'exceptions' => true,
93
+ 'verify' => $http->getDefaultOption('verify'),
94
+ 'proxy' => $http->getDefaultOption('proxy'),
95
+ ]
96
+ ]
97
+ );
98
+ }
99
+ }
includes/lib/google-api-php-client/src/Google/AuthHandler/Guzzle6AuthHandler.php ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ use Google\Auth\CredentialsLoader;
4
+ use Google\Auth\HttpHandler\HttpHandlerFactory;
5
+ use Google\Auth\FetchAuthTokenCache;
6
+ use Google\Auth\Middleware\AuthTokenMiddleware;
7
+ use Google\Auth\Middleware\ScopedAccessTokenMiddleware;
8
+ use Google\Auth\Middleware\SimpleMiddleware;
9
+ use GuzzleHttp\Client;
10
+ use GuzzleHttp\ClientInterface;
11
+ use Psr\Cache\CacheItemPoolInterface;
12
+
13
+ /**
14
+ *
15
+ */
16
+ class Google_AuthHandler_Guzzle6AuthHandler
17
+ {
18
+ protected $cache;
19
+ protected $cacheConfig;
20
+
21
+ public function __construct(CacheItemPoolInterface $cache = null, array $cacheConfig = [])
22
+ {
23
+ $this->cache = $cache;
24
+ $this->cacheConfig = $cacheConfig;
25
+ }
26
+
27
+ public function attachCredentials(
28
+ ClientInterface $http,
29
+ CredentialsLoader $credentials,
30
+ callable $tokenCallback = null
31
+ ) {
32
+ // use the provided cache
33
+ if ($this->cache) {
34
+ $credentials = new FetchAuthTokenCache(
35
+ $credentials,
36
+ $this->cacheConfig,
37
+ $this->cache
38
+ );
39
+ }
40
+ // if we end up needing to make an HTTP request to retrieve credentials, we
41
+ // can use our existing one, but we need to throw exceptions so the error
42
+ // bubbles up.
43
+ $authHttp = $this->createAuthHttp($http);
44
+ $authHttpHandler = HttpHandlerFactory::build($authHttp);
45
+ $middleware = new AuthTokenMiddleware(
46
+ $credentials,
47
+ $authHttpHandler,
48
+ $tokenCallback
49
+ );
50
+
51
+ $config = $http->getConfig();
52
+ $config['handler']->remove('google_auth');
53
+ $config['handler']->push($middleware, 'google_auth');
54
+ $config['auth'] = 'google_auth';
55
+ $http = new Client($config);
56
+
57
+ return $http;
58
+ }
59
+
60
+ public function attachToken(ClientInterface $http, array $token, array $scopes)
61
+ {
62
+ $tokenFunc = function ($scopes) use ($token) {
63
+ return $token['access_token'];
64
+ };
65
+
66
+ $middleware = new ScopedAccessTokenMiddleware(
67
+ $tokenFunc,
68
+ $scopes,
69
+ $this->cacheConfig,
70
+ $this->cache
71
+ );
72
+
73
+ $config = $http->getConfig();
74
+ $config['handler']->remove('google_auth');
75
+ $config['handler']->push($middleware, 'google_auth');
76
+ $config['auth'] = 'scoped';
77
+ $http = new Client($config);
78
+
79
+ return $http;
80
+ }
81
+
82
+ public function attachKey(ClientInterface $http, $key)
83
+ {
84
+ $middleware = new SimpleMiddleware(['key' => $key]);
85
+
86
+ $config = $http->getConfig();
87
+ $config['handler']->remove('google_auth');
88
+ $config['handler']->push($middleware, 'google_auth');
89
+ $config['auth'] = 'simple';
90
+ $http = new Client($config);
91
+
92
+ return $http;
93
+ }
94
+
95
+ private function createAuthHttp(ClientInterface $http)
96
+ {
97
+ return new Client(
98
+ [
99
+ 'base_uri' => $http->getConfig('base_uri'),
100
+ 'exceptions' => true,
101
+ 'verify' => $http->getConfig('verify'),
102
+ 'proxy' => $http->getConfig('proxy'),
103
+ ]
104
+ );
105
+ }
106
+ }
includes/lib/google-api-php-client/src/Google/Client.php ADDED
@@ -0,0 +1,1128 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * Copyright 2010 Google Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ use Google\Auth\ApplicationDefaultCredentials;
19
+ use Google\Auth\Cache\MemoryCacheItemPool;
20
+ use Google\Auth\CredentialsLoader;
21
+ use Google\Auth\HttpHandler\HttpHandlerFactory;
22
+ use Google\Auth\OAuth2;
23
+ use Google\Auth\Credentials\ServiceAccountCredentials;
24
+ use Google\Auth\Credentials\UserRefreshCredentials;
25
+ use GuzzleHttp\Client;
26
+ use GuzzleHttp\ClientInterface;
27
+ use GuzzleHttp\Ring\Client\StreamHandler;
28
+ use Psr\Cache\CacheItemPoolInterface;
29
+ use Psr\Http\Message\RequestInterface;
30
+ use Psr\Log\LoggerInterface;
31
+ use Monolog\Logger;
32
+ use Monolog\Handler\StreamHandler as MonologStreamHandler;
33
+ use Monolog\Handler\SyslogHandler as MonologSyslogHandler;
34
+
35
+ /**
36
+ * The Google API Client
37
+ * https://github.com/google/google-api-php-client
38
+ */
39
+ class Google_Client
40
+ {
41
+ const LIBVER = "2.2.2";
42
+ const USER_AGENT_SUFFIX = "google-api-php-client/";
43
+ const OAUTH2_REVOKE_URI = 'https://accounts.google.com/o/oauth2/revoke';
44
+ const OAUTH2_TOKEN_URI = 'https://www.googleapis.com/oauth2/v4/token';
45
+ const OAUTH2_AUTH_URL = 'https://accounts.google.com/o/oauth2/auth';
46
+ const API_BASE_PATH = 'https://www.googleapis.com';
47
+
48
+ /**
49
+ * @var Google\Auth\OAuth2 $auth
50
+ */
51
+ private $auth;
52
+
53
+ /**
54
+ * @var GuzzleHttp\ClientInterface $http
55
+ */
56
+ private $http;
57
+
58
+ /**
59
+ * @var Psr\Cache\CacheItemPoolInterface $cache
60
+ */
61
+ private $cache;
62
+
63
+ /**
64
+ * @var array access token
65
+ */
66
+ private $token;
67
+
68
+ /**
69
+ * @var array $config
70
+ */
71
+ private $config;
72
+
73
+ /**
74
+ * @var Psr\Log\LoggerInterface $logger
75
+ */
76
+ private $logger;
77
+
78
+ /**
79
+ * @var boolean $deferExecution
80
+ */
81
+ private $deferExecution = false;
82
+
83
+ /** @var array $scopes */
84
+ // Scopes requested by the client
85
+ protected $requestedScopes = [];
86
+
87
+ /**
88
+ * Construct the Google Client.
89
+ *
90
+ * @param array $config
91
+ */
92
+ public function __construct(array $config = array())
93
+ {
94
+ $this->config = array_merge(
95
+ [
96
+ 'application_name' => '',
97
+
98
+ // Don't change these unless you're working against a special development
99
+ // or testing environment.
100
+ 'base_path' => self::API_BASE_PATH,
101
+
102
+ // https://developers.google.com/console
103
+ 'client_id' => '',
104
+ 'client_secret' => '',
105
+ 'redirect_uri' => null,
106
+ 'state' => null,
107
+
108
+ // Simple API access key, also from the API console. Ensure you get
109
+ // a Server key, and not a Browser key.
110
+ 'developer_key' => '',
111
+
112
+ // For use with Google Cloud Platform
113
+ // fetch the ApplicationDefaultCredentials, if applicable
114
+ // @see https://developers.google.com/identity/protocols/application-default-credentials
115
+ 'use_application_default_credentials' => false,
116
+ 'signing_key' => null,
117
+ 'signing_algorithm' => null,
118
+ 'subject' => null,
119
+
120
+ // Other OAuth2 parameters.
121
+ 'hd' => '',
122
+ 'prompt' => '',
123
+ 'openid.realm' => '',
124
+ 'include_granted_scopes' => null,
125
+ 'login_hint' => '',
126
+ 'request_visible_actions' => '',
127
+ 'access_type' => 'online',
128
+ 'approval_prompt' => 'auto',
129
+
130
+ // Task Runner retry configuration
131
+ // @see Google_Task_Runner
132
+ 'retry' => array(),
133
+
134
+ // cache config for downstream auth caching
135
+ 'cache_config' => [],
136
+
137
+ // function to be called when an access token is fetched
138
+ // follows the signature function ($cacheKey, $accessToken)
139
+ 'token_callback' => null,
140
+
141
+ // Service class used in Google_Client::verifyIdToken.
142
+ // Explicitly pass this in to avoid setting JWT::$leeway
143
+ 'jwt' => null,
144
+ ],
145
+ $config
146
+ );
147
+ }
148
+
149
+ /**
150
+ * Get a string containing the version of the library.
151
+ *
152
+ * @return string
153
+ */
154
+ public function getLibraryVersion()
155
+ {
156
+ return self::LIBVER;
157
+ }
158
+
159
+ /**
160
+ * For backwards compatibility
161
+ * alias for fetchAccessTokenWithAuthCode
162
+ *
163
+ * @param $code string code from accounts.google.com
164
+ * @return array access token
165
+ * @deprecated
166
+ */
167
+ public function authenticate($code)
168
+ {
169
+ return $this->fetchAccessTokenWithAuthCode($code);
170
+ }
171
+
172
+ /**
173
+ * Attempt to exchange a code for an valid authentication token.
174
+ * Helper wrapped around the OAuth 2.0 implementation.
175
+ *
176
+ * @param $code string code from accounts.google.com
177
+ * @return array access token
178
+ */
179
+ public function fetchAccessTokenWithAuthCode($code)
180
+ {
181
+ if (strlen($code) == 0) {
182
+ throw new InvalidArgumentException("Invalid code");
183
+ }
184
+
185
+ $auth = $this->getOAuth2Service();
186
+ $auth->setCode($code);
187
+ $auth->setRedirectUri($this->getRedirectUri());
188
+
189
+ $httpHandler = HttpHandlerFactory::build($this->getHttpClient());
190
+ $creds = $auth->fetchAuthToken($httpHandler);
191
+ if ($creds && isset($creds['access_token'])) {
192
+ $creds['created'] = time();
193
+ $this->setAccessToken($creds);
194
+ }
195
+
196
+ return $creds;
197
+ }
198
+
199
+ /**
200
+ * For backwards compatibility
201
+ * alias for fetchAccessTokenWithAssertion
202
+ *
203
+ * @return array access token
204
+ * @deprecated
205
+ */
206
+ public function refreshTokenWithAssertion()
207
+ {
208
+ return $this->fetchAccessTokenWithAssertion();
209
+ }
210
+
211
+ /**
212
+ * Fetches a fresh access token with a given assertion token.
213
+ * @param ClientInterface $authHttp optional.
214
+ * @return array access token
215
+ */
216
+ public function fetchAccessTokenWithAssertion(ClientInterface $authHttp = null)
217
+ {
218
+ if (!$this->isUsingApplicationDefaultCredentials()) {
219
+ throw new DomainException(
220
+ 'set the JSON service account credentials using'
221
+ . ' Google_Client::setAuthConfig or set the path to your JSON file'
222
+ . ' with the "GOOGLE_APPLICATION_CREDENTIALS" environment variable'
223
+ . ' and call Google_Client::useApplicationDefaultCredentials to'
224
+ . ' refresh a token with assertion.'
225
+ );
226
+ }
227
+
228
+ $this->getLogger()->log(
229
+ 'info',
230
+ 'OAuth2 access token refresh with Signed JWT assertion grants.'
231
+ );
232
+
233
+ $credentials = $this->createApplicationDefaultCredentials();
234
+
235
+ $httpHandler = HttpHandlerFactory::build($authHttp);
236
+ $creds = $credentials->fetchAuthToken($httpHandler);
237
+ if ($creds && isset($creds['access_token'])) {
238
+ $creds['created'] = time();
239
+ $this->setAccessToken($creds);
240
+ }
241
+
242
+ return $creds;
243
+ }
244
+
245
+ /**
246
+ * For backwards compatibility
247
+ * alias for fetchAccessTokenWithRefreshToken
248
+ *
249
+ * @param string $refreshToken
250
+ * @return array access token
251
+ */
252
+ public function refreshToken($refreshToken)
253
+ {
254
+ return $this->fetchAccessTokenWithRefreshToken($refreshToken);
255
+ }
256
+
257
+ /**
258
+ * Fetches a fresh OAuth 2.0 access token with the given refresh token.
259
+ * @param string $refreshToken
260
+ * @return array access token
261
+ */
262
+ public function fetchAccessTokenWithRefreshToken($refreshToken = null)
263
+ {
264
+ if (null === $refreshToken) {
265
+ if (!isset($this->token['refresh_token'])) {
266
+ throw new LogicException(
267
+ 'refresh token must be passed in or set as part of setAccessToken'
268
+ );
269
+ }
270
+ $refreshToken = $this->token['refresh_token'];
271
+ }
272
+ $this->getLogger()->info('OAuth2 access token refresh');
273
+ $auth = $this->getOAuth2Service();
274
+ $auth->setRefreshToken($refreshToken);
275
+
276
+ $httpHandler = HttpHandlerFactory::build($this->getHttpClient());
277
+ $creds = $auth->fetchAuthToken($httpHandler);
278
+ if ($creds && isset($creds['access_token'])) {
279
+ $creds['created'] = time();
280
+ if (!isset($creds['refresh_token'])) {
281
+ $creds['refresh_token'] = $refreshToken;
282
+ }
283
+ $this->setAccessToken($creds);
284
+ }
285
+
286
+ return $creds;
287
+ }
288
+
289
+ /**
290
+ * Create a URL to obtain user authorization.
291
+ * The authorization endpoint allows the user to first
292
+ * authenticate, and then grant/deny the access request.
293
+ * @param string|array $scope The scope is expressed as an array or list of space-delimited strings.
294
+ * @return string
295
+ */
296
+ public function createAuthUrl($scope = null)
297
+ {
298
+ if (empty($scope)) {
299
+ $scope = $this->prepareScopes();
300
+ }
301
+ if (is_array($scope)) {
302
+ $scope = implode(' ', $scope);
303
+ }
304
+
305
+ // only accept one of prompt or approval_prompt
306
+ $approvalPrompt = $this->config['prompt']
307
+ ? null
308
+ : $this->config['approval_prompt'];
309
+
310
+ // include_granted_scopes should be string "true", string "false", or null
311
+ $includeGrantedScopes = $this->config['include_granted_scopes'] === null
312
+ ? null
313
+ : var_export($this->config['include_granted_scopes'], true);
314
+
315
+ $params = array_filter(
316
+ [
317
+ 'access_type' => $this->config['access_type'],
318
+ 'approval_prompt' => $approvalPrompt,
319
+ 'hd' => $this->config['hd'],
320
+ 'include_granted_scopes' => $includeGrantedScopes,
321
+ 'login_hint' => $this->config['login_hint'],
322
+ 'openid.realm' => $this->config['openid.realm'],
323
+ 'prompt' => $this->config['prompt'],
324
+ 'response_type' => 'code',
325
+ 'scope' => $scope,
326
+ 'state' => $this->config['state'],
327
+ ]
328
+ );
329
+
330
+ // If the list of scopes contains plus.login, add request_visible_actions
331
+ // to auth URL.
332
+ $rva = $this->config['request_visible_actions'];
333
+ if (strlen($rva) > 0 && false !== strpos($scope, 'plus.login')) {
334
+ $params['request_visible_actions'] = $rva;
335
+ }
336
+
337
+ $auth = $this->getOAuth2Service();
338
+
339
+ return (string) $auth->buildFullAuthorizationUri($params);
340
+ }
341
+
342
+ /**
343
+ * Adds auth listeners to the HTTP client based on the credentials
344
+ * set in the Google API Client object
345
+ *
346
+ * @param GuzzleHttp\ClientInterface $http the http client object.
347
+ * @return GuzzleHttp\ClientInterface the http client object
348
+ */
349
+ public function authorize(ClientInterface $http = null)
350
+ {
351
+ $credentials = null;
352
+ $token = null;
353
+ $scopes = null;
354
+ if (null === $http) {
355
+ $http = $this->getHttpClient();
356
+ }
357
+
358
+ // These conditionals represent the decision tree for authentication
359
+ // 1. Check for Application Default Credentials
360
+ // 2. Check for API Key
361
+ // 3a. Check for an Access Token
362
+ // 3b. If access token exists but is expired, try to refresh it
363
+ if ($this->isUsingApplicationDefaultCredentials()) {
364
+ $credentials = $this->createApplicationDefaultCredentials();
365
+ } elseif ($token = $this->getAccessToken()) {
366
+ $scopes = $this->prepareScopes();
367
+ // add refresh subscriber to request a new token
368
+ if (isset($token['refresh_token']) && $this->isAccessTokenExpired()) {
369
+ $credentials = $this->createUserRefreshCredentials(
370
+ $scopes,
371
+ $token['refresh_token']
372
+ );
373
+ }
374
+ }
375
+
376
+ $authHandler = $this->getAuthHandler();
377
+
378
+ if ($credentials) {
379
+ $callback = $this->config['token_callback'];
380
+ $http = $authHandler->attachCredentials($http, $credentials, $callback);
381
+ } elseif ($token) {
382
+ $http = $authHandler->attachToken($http, $token, (array) $scopes);
383
+ } elseif ($key = $this->config['developer_key']) {
384
+ $http = $authHandler->attachKey($http, $key);
385
+ }
386
+
387
+ return $http;
388
+ }
389
+
390
+ /**
391
+ * Set the configuration to use application default credentials for
392
+ * authentication
393
+ *
394
+ * @see https://developers.google.com/identity/protocols/application-default-credentials
395
+ * @param boolean $useAppCreds
396
+ */
397
+ public function useApplicationDefaultCredentials($useAppCreds = true)
398
+ {
399
+ $this->config['use_application_default_credentials'] = $useAppCreds;
400
+ }
401
+
402
+ /**
403
+ * To prevent useApplicationDefaultCredentials from inappropriately being
404
+ * called in a conditional
405
+ *
406
+ * @see https://developers.google.com/identity/protocols/application-default-credentials
407
+ */
408
+ public function isUsingApplicationDefaultCredentials()
409
+ {
410
+ return $this->config['use_application_default_credentials'];
411
+ }
412
+
413
+ /**
414
+ * @param string|array $token
415
+ * @throws InvalidArgumentException
416
+ */
417
+ public function setAccessToken($token)
418
+ {
419
+ if (is_string($token)) {
420
+ if ($json = json_decode($token, true)) {
421
+ $token = $json;
422
+ } else {
423
+ // assume $token is just the token string
424
+ $token = array(
425
+ 'access_token' => $token,
426
+ );
427
+ }
428
+ }
429
+ if ($token == null) {
430
+ throw new InvalidArgumentException('invalid json token');
431
+ }
432
+ if (!isset($token['access_token'])) {
433
+ throw new InvalidArgumentException("Invalid token format");
434
+ }
435
+ $this->token = $token;
436
+ }
437
+
438
+ public function getAccessToken()
439
+ {
440
+ return $this->token;
441
+ }
442
+
443
+ /**
444
+ * @return string|null
445
+ */
446
+ public function getRefreshToken()
447
+ {
448
+ if (isset($this->token['refresh_token'])) {
449
+ return $this->token['refresh_token'];
450
+ }
451
+
452
+ return null;
453
+ }
454
+
455
+ /**
456
+ * Returns if the access_token is expired.
457
+ * @return bool Returns True if the access_token is expired.
458
+ */
459
+ public function isAccessTokenExpired()
460
+ {
461
+ if (!$this->token) {
462
+ return true;
463
+ }
464
+
465
+ $created = 0;
466
+ if (isset($this->token['created'])) {
467
+ $created = $this->token['created'];
468
+ } elseif (isset($this->token['id_token'])) {
469
+ // check the ID token for "iat"
470
+ // signature verification is not required here, as we are just
471
+ // using this for convenience to save a round trip request
472
+ // to the Google API server
473
+ $idToken = $this->token['id_token'];
474
+ if (substr_count($idToken, '.') == 2) {
475
+ $parts = explode('.', $idToken);
476
+ $payload = json_decode(base64_decode($parts[1]), true);
477
+ if ($payload && isset($payload['iat'])) {
478
+ $created = $payload['iat'];
479
+ }
480
+ }
481
+ }
482
+
483
+ // If the token is set to expire in the next 30 seconds.
484
+ return ($created + ($this->token['expires_in'] - 30)) < time();
485
+ }
486
+
487
+ /**
488
+ * @deprecated See UPGRADING.md for more information
489
+ */
490
+ public function getAuth()
491
+ {
492
+ throw new BadMethodCallException(
493
+ 'This function no longer exists. See UPGRADING.md for more information'
494
+ );
495
+ }
496
+
497
+ /**
498
+ * @deprecated See UPGRADING.md for more information
499
+ */
500
+ public function setAuth($auth)
501
+ {
502
+ throw new BadMethodCallException(
503
+ 'This function no longer exists. See UPGRADING.md for more information'
504
+ );
505
+ }
506
+
507
+ /**
508
+ * Set the OAuth 2.0 Client ID.
509
+ * @param string $clientId
510
+ */
511
+ public function setClientId($clientId)
512
+ {
513
+ $this->config['client_id'] = $clientId;
514
+ }
515
+
516
+ public function getClientId()
517
+ {
518
+ return $this->config['client_id'];
519
+ }
520
+
521
+ /**
522
+ * Set the OAuth 2.0 Client Secret.
523
+ * @param string $clientSecret
524
+ */
525
+ public function setClientSecret($clientSecret)
526
+ {
527
+ $this->config['client_secret'] = $clientSecret;
528
+ }
529
+
530
+ public function getClientSecret()
531
+ {
532
+ return $this->config['client_secret'];
533
+ }
534
+
535
+ /**
536
+ * Set the OAuth 2.0 Redirect URI.
537
+ * @param string $redirectUri
538
+ */
539
+ public function setRedirectUri($redirectUri)
540
+ {
541
+ $this->config['redirect_uri'] = $redirectUri;
542
+ }
543
+
544
+ public function getRedirectUri()
545
+ {
546
+ return $this->config['redirect_uri'];
547
+ }
548
+
549
+ /**
550
+ * Set OAuth 2.0 "state" parameter to achieve per-request customization.
551
+ * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-22#section-3.1.2.2
552
+ * @param string $state
553
+ */
554
+ public function setState($state)
555
+ {
556
+ $this->config['state'] = $state;
557
+ }
558
+
559
+ /**
560
+ * @param string $accessType Possible values for access_type include:
561
+ * {@code "offline"} to request offline access from the user.
562
+ * {@code "online"} to request online access from the user.
563
+ */
564
+ public function setAccessType($accessType)
565
+ {
566
+ $this->config['access_type'] = $accessType;
567
+ }
568
+
569
+ /**
570
+ * @param string $approvalPrompt Possible values for approval_prompt include:
571
+ * {@code "force"} to force the approval UI to appear.
572
+ * {@code "auto"} to request auto-approval when possible. (This is the default value)
573
+ */
574
+ public function setApprovalPrompt($approvalPrompt)
575
+ {
576
+ $this->config['approval_prompt'] = $approvalPrompt;
577
+ }
578
+
579
+ /**
580
+ * Set the login hint, email address or sub id.
581
+ * @param string $loginHint
582
+ */
583
+ public function setLoginHint($loginHint)
584
+ {
585
+ $this->config['login_hint'] = $loginHint;
586
+ }
587
+
588
+ /**
589
+ * Set the application name, this is included in the User-Agent HTTP header.
590
+ * @param string $applicationName
591
+ */
592
+ public function setApplicationName($applicationName)
593
+ {
594
+ $this->config['application_name'] = $applicationName;
595
+ }
596
+
597
+ /**
598
+ * If 'plus.login' is included in the list of requested scopes, you can use
599
+ * this method to define types of app activities that your app will write.
600
+ * You can find a list of available types here:
601
+ * @link https://developers.google.com/+/api/moment-types
602
+ *
603
+ * @param array $requestVisibleActions Array of app activity types
604
+ */
605
+ public function setRequestVisibleActions($requestVisibleActions)
606
+ {
607
+ if (is_array($requestVisibleActions)) {
608
+ $requestVisibleActions = implode(" ", $requestVisibleActions);
609
+ }
610
+ $this->config['request_visible_actions'] = $requestVisibleActions;
611
+ }
612
+
613
+ /**
614
+ * Set the developer key to use, these are obtained through the API Console.
615
+ * @see http://code.google.com/apis/console-help/#generatingdevkeys
616
+ * @param string $developerKey
617
+ */
618
+ public function setDeveloperKey($developerKey)
619
+ {
620
+ $this->config['developer_key'] = $developerKey;
621
+ }
622
+
623
+ /**
624
+ * Set the hd (hosted domain) parameter streamlines the login process for
625
+ * Google Apps hosted accounts. By including the domain of the user, you
626
+ * restrict sign-in to accounts at that domain.
627
+ * @param $hd string - the domain to use.
628
+ */
629
+ public function setHostedDomain($hd)
630
+ {
631
+ $this->config['hd'] = $hd;
632
+ }
633
+
634
+ /**
635
+ * Set the prompt hint. Valid values are none, consent and select_account.
636
+ * If no value is specified and the user has not previously authorized
637
+ * access, then the user is shown a consent screen.
638
+ * @param $prompt string
639
+ */
640
+ public function setPrompt($prompt)
641
+ {
642
+ $this->config['prompt'] = $prompt;
643
+ }
644
+
645
+ /**
646
+ * openid.realm is a parameter from the OpenID 2.0 protocol, not from OAuth
647
+ * 2.0. It is used in OpenID 2.0 requests to signify the URL-space for which
648
+ * an authentication request is valid.
649
+ * @param $realm string - the URL-space to use.
650
+ */
651
+ public function setOpenidRealm($realm)
652
+ {
653
+ $this->config['openid.realm'] = $realm;
654
+ }
655
+
656
+ /**
657
+ * If this is provided with the value true, and the authorization request is
658
+ * granted, the authorization will include any previous authorizations
659
+ * granted to this user/application combination for other scopes.
660
+ * @param $include boolean - the URL-space to use.
661
+ */
662
+ public function setIncludeGrantedScopes($include)
663
+ {
664
+ $this->config['include_granted_scopes'] = $include;
665
+ }
666
+
667
+ /**
668
+ * sets function to be called when an access token is fetched
669
+ * @param callable $tokenCallback - function ($cacheKey, $accessToken)
670
+ */
671
+ public function setTokenCallback(callable $tokenCallback)
672
+ {
673
+ $this->config['token_callback'] = $tokenCallback;
674
+ }
675
+
676
+ /**
677
+ * Revoke an OAuth2 access token or refresh token. This method will revoke the current access
678
+ * token, if a token isn't provided.
679
+ *
680
+ * @param string|null $token The token (access token or a refresh token) that should be revoked.
681
+ * @return boolean Returns True if the revocation was successful, otherwise False.
682
+ */
683
+ public function revokeToken($token = null)
684
+ {
685
+ $tokenRevoker = new Google_AccessToken_Revoke(
686
+ $this->getHttpClient()
687
+ );
688
+
689
+ return $tokenRevoker->revokeToken($token ?: $this->getAccessToken());
690
+ }
691
+
692
+ /**
693
+ * Verify an id_token. This method will verify the current id_token, if one
694
+ * isn't provided.
695
+ *
696
+ * @throws LogicException
697
+ * @param string|null $idToken The token (id_token) that should be verified.
698
+ * @return array|false Returns the token payload as an array if the verification was
699
+ * successful, false otherwise.
700
+ */
701
+ public function verifyIdToken($idToken = null)
702
+ {
703
+ $tokenVerifier = new Google_AccessToken_Verify(
704
+ $this->getHttpClient(),
705
+ $this->getCache(),
706
+ $this->config['jwt']
707
+ );
708
+
709
+ if (null === $idToken) {
710
+ $token = $this->getAccessToken();
711
+ if (!isset($token['id_token'])) {
712
+ throw new LogicException(
713
+ 'id_token must be passed in or set as part of setAccessToken'
714
+ );
715
+ }
716
+ $idToken = $token['id_token'];
717
+ }
718
+
719
+ return $tokenVerifier->verifyIdToken(
720
+ $idToken,
721
+ $this->getClientId()
722
+ );
723
+ }
724
+
725
+ /**
726
+ * Set the scopes to be requested. Must be called before createAuthUrl().
727
+ * Will remove any previously configured scopes.
728
+ * @param array $scopes, ie: array('https://www.googleapis.com/auth/plus.login',
729
+ * 'https://www.googleapis.com/auth/moderator')
730
+ */
731
+ public function setScopes($scopes)
732
+ {
733
+ $this->requestedScopes = array();
734
+ $this->addScope($scopes);
735
+ }
736
+
737
+ /**
738
+ * This functions adds a scope to be requested as part of the OAuth2.0 flow.
739
+ * Will append any scopes not previously requested to the scope parameter.
740
+ * A single string will be treated as a scope to request. An array of strings
741
+ * will each be appended.
742
+ * @param $scope_or_scopes string|array e.g. "profile"
743
+ */
744
+ public function addScope($scope_or_scopes)
745
+ {
746
+ if (is_string($scope_or_scopes) && !in_array($scope_or_scopes, $this->requestedScopes)) {
747
+ $this->requestedScopes[] = $scope_or_scopes;
748
+ } else if (is_array($scope_or_scopes)) {
749
+ foreach ($scope_or_scopes as $scope) {
750
+ $this->addScope($scope);
751
+ }
752
+ }
753
+ }
754
+
755
+ /**
756
+ * Returns the list of scopes requested by the client
757
+ * @return array the list of scopes
758
+ *
759
+ */
760
+ public function getScopes()
761
+ {
762
+ return $this->requestedScopes;
763
+ }
764
+
765
+ /**
766
+ * @return string|null
767
+ * @visible For Testing
768
+ */
769
+ public function prepareScopes()
770
+ {
771
+ if (empty($this->requestedScopes)) {
772
+ return null;
773
+ }
774
+
775
+ return implode(' ', $this->requestedScopes);
776
+ }
777
+
778
+ /**
779
+ * Helper method to execute deferred HTTP requests.
780
+ *
781
+ * @param $request Psr\Http\Message\RequestInterface|Google_Http_Batch
782
+ * @throws Google_Exception
783
+ * @return object of the type of the expected class or Psr\Http\Message\ResponseInterface.
784
+ */
785
+ public function execute(RequestInterface $request, $expectedClass = null)
786
+ {
787
+ $request = $request->withHeader(
788
+ 'User-Agent',
789
+ $this->config['application_name']
790
+ . " " . self::USER_AGENT_SUFFIX
791
+ . $this->getLibraryVersion()
792
+ );
793
+
794
+ // call the authorize method
795
+ // this is where most of the grunt work is done
796
+ $http = $this->authorize();
797
+
798
+ return Google_Http_REST::execute($http, $request, $expectedClass, $this->config['retry']);
799
+ }
800
+
801
+ /**
802
+ * Declare whether batch calls should be used. This may increase throughput
803
+ * by making multiple requests in one connection.
804
+ *
805
+ * @param boolean $useBatch True if the batch support should
806
+ * be enabled. Defaults to False.
807
+ */
808
+ public function setUseBatch($useBatch)
809
+ {
810
+ // This is actually an alias for setDefer.
811
+ $this->setDefer($useBatch);
812
+ }
813
+
814
+ /**
815
+ * Are we running in Google AppEngine?
816
+ * return bool
817
+ */
818
+ public function isAppEngine()
819
+ {
820
+ return (isset($_SERVER['SERVER_SOFTWARE']) &&
821
+ strpos($_SERVER['SERVER_SOFTWARE'], 'Google App Engine') !== false);
822
+ }
823
+
824
+ public function setConfig($name, $value)
825
+ {
826
+ $this->config[$name] = $value;
827
+ }
828
+
829
+ public function getConfig($name, $default = null)
830
+ {
831
+ return isset($this->config[$name]) ? $this->config[$name] : $default;
832
+ }
833
+
834
+ /**
835
+ * For backwards compatibility
836
+ * alias for setAuthConfig
837
+ *
838
+ * @param string $file the configuration file
839
+ * @throws Google_Exception
840
+ * @deprecated
841
+ */
842
+ public function setAuthConfigFile($file)
843
+ {
844
+ $this->setAuthConfig($file);
845
+ }
846
+
847
+ /**
848
+ * Set the auth config from new or deprecated JSON config.
849
+ * This structure should match the file downloaded from
850
+ * the "Download JSON" button on in the Google Developer
851
+ * Console.
852
+ * @param string|array $config the configuration json
853
+ * @throws Google_Exception
854
+ */
855
+ public function setAuthConfig($config)
856
+ {
857
+ if (is_string($config)) {
858
+ if (!file_exists($config)) {
859
+ throw new InvalidArgumentException('file does not exist');
860
+ }
861
+
862
+ $json = file_get_contents($config);
863
+
864
+ if (!$config = json_decode($json, true)) {
865
+ throw new LogicException('invalid json for auth config');
866
+ }
867
+ }
868
+
869
+ $key = isset($config['installed']) ? 'installed' : 'web';
870
+ if (isset($config['type']) && $config['type'] == 'service_account') {
871
+ // application default credentials
872
+ $this->useApplicationDefaultCredentials();
873
+
874
+ // set the information from the config
875
+ $this->setClientId($config['client_id']);
876
+ $this->config['client_email'] = $config['client_email'];
877
+ $this->config['signing_key'] = $config['private_key'];
878
+ $this->config['signing_algorithm'] = 'HS256';
879
+ } elseif (isset($config[$key])) {
880
+ // old-style
881
+ $this->setClientId($config[$key]['client_id']);
882
+ $this->setClientSecret($config[$key]['client_secret']);
883
+ if (isset($config[$key]['redirect_uris'])) {
884
+ $this->setRedirectUri($config[$key]['redirect_uris'][0]);
885
+ }
886
+ } else {
887
+ // new-style
888
+ $this->setClientId($config['client_id']);
889
+ $this->setClientSecret($config['client_secret']);
890
+ if (isset($config['redirect_uris'])) {
891
+ $this->setRedirectUri($config['redirect_uris'][0]);
892
+ }
893
+ }
894
+ }
895
+
896
+ /**
897
+ * Use when the service account has been delegated domain wide access.
898
+ *
899
+ * @param string $subject an email address account to impersonate
900
+ */
901
+ public function setSubject($subject)
902
+ {
903
+ $this->config['subject'] = $subject;
904
+ }
905
+
906
+ /**
907
+ * Declare whether making API calls should make the call immediately, or
908
+ * return a request which can be called with ->execute();
909
+ *
910
+ * @param boolean $defer True if calls should not be executed right away.
911
+ */
912
+ public function setDefer($defer)
913
+ {
914
+ $this->deferExecution = $defer;
915
+ }
916
+
917
+ /**
918
+ * Whether or not to return raw requests
919
+ * @return boolean
920
+ */
921
+ public function shouldDefer()
922
+ {
923
+ return $this->deferExecution;
924
+ }
925
+
926
+ /**
927
+ * @return Google\Auth\OAuth2 implementation
928
+ */
929
+ public function getOAuth2Service()
930
+ {
931
+ if (!isset($this->auth)) {
932
+ $this->auth = $this->createOAuth2Service();
933
+ }
934
+
935
+ return $this->auth;
936
+ }
937
+
938
+ /**
939
+ * create a default google auth object
940
+ */
941
+ protected function createOAuth2Service()
942
+ {
943
+ $auth = new OAuth2(
944
+ [
945
+ 'clientId' => $this->getClientId(),
946
+ 'clientSecret' => $this->getClientSecret(),
947
+ 'authorizationUri' => self::OAUTH2_AUTH_URL,
948
+ 'tokenCredentialUri' => self::OAUTH2_TOKEN_URI,
949
+ 'redirectUri' => $this->getRedirectUri(),
950
+ 'issuer' => $this->config['client_id'],
951
+ 'signingKey' => $this->config['signing_key'],
952
+ 'signingAlgorithm' => $this->config['signing_algorithm'],
953
+ ]
954
+ );
955
+
956
+ return $auth;
957
+ }
958
+
959
+ /**
960
+ * Set the Cache object
961
+ * @param Psr\Cache\CacheItemPoolInterface $cache
962
+ */
963
+ public function setCache(CacheItemPoolInterface $cache)
964
+ {
965
+ $this->cache = $cache;
966
+ }
967
+
968
+ /**
969
+ * @return Psr\Cache\CacheItemPoolInterface Cache implementation
970
+ */
971
+ public function getCache()
972
+ {
973
+ if (!$this->cache) {
974
+ $this->cache = $this->createDefaultCache();
975
+ }
976
+
977
+ return $this->cache;
978
+ }
979
+
980
+ /**
981
+ * @param array $cacheConfig
982
+ */
983
+ public function setCacheConfig(array $cacheConfig)
984
+ {
985
+ $this->config['cache_config'] = $cacheConfig;
986
+ }
987
+
988
+ /**
989
+ * Set the Logger object
990
+ * @param Psr\Log\LoggerInterface $logger
991
+ */
992
+ public function setLogger(LoggerInterface $logger)
993
+ {
994
+ $this->logger = $logger;
995
+ }
996
+
997
+ /**
998
+ * @return Psr\Log\LoggerInterface implementation
999
+ */
1000
+ public function getLogger()
1001
+ {
1002
+ if (!isset($this->logger)) {
1003
+ $this->logger = $this->createDefaultLogger();
1004
+ }
1005
+
1006
+ return $this->logger;
1007
+ }
1008
+
1009
+ protected function createDefaultLogger()
1010
+ {
1011
+ $logger = new Logger('google-api-php-client');
1012
+ if ($this->isAppEngine()) {
1013
+ $handler = new MonologSyslogHandler('app', LOG_USER, Logger::NOTICE);
1014
+ } else {
1015
+ $handler = new MonologStreamHandler('php://stderr', Logger::NOTICE);
1016
+ }
1017
+ $logger->pushHandler($handler);
1018
+
1019
+ return $logger;
1020
+ }
1021
+
1022
+ protected function createDefaultCache()
1023
+ {
1024
+ return new MemoryCacheItemPool;
1025
+ }
1026
+
1027
+ /**
1028
+ * Set the Http Client object
1029
+ * @param GuzzleHttp\ClientInterface $http
1030
+ */
1031
+ public function setHttpClient(ClientInterface $http)
1032
+ {
1033
+ $this->http = $http;
1034
+ }
1035
+
1036
+ /**
1037
+ * @return GuzzleHttp\ClientInterface implementation
1038
+ */
1039
+ public function getHttpClient()
1040
+ {
1041
+ if (null === $this->http) {
1042
+ $this->http = $this->createDefaultHttpClient();
1043
+ }
1044
+
1045
+ return $this->http;
1046
+ }
1047
+
1048
+ protected function createDefaultHttpClient()
1049
+ {
1050
+ $options = ['exceptions' => false];
1051
+
1052
+ $version = ClientInterface::VERSION;
1053
+ if ('5' === $version[0]) {
1054
+ $options = [
1055
+ 'base_url' => $this->config['base_path'],
1056
+ 'defaults' => $options,
1057
+ ];
1058
+ if ($this->isAppEngine()) {
1059
+ // set StreamHandler on AppEngine by default
1060
+ $options['handler'] = new StreamHandler();
1061
+ $options['defaults']['verify'] = '/etc/ca-certificates.crt';
1062
+ }
1063
+ } else {
1064
+ // guzzle 6
1065
+ $options['base_uri'] = $this->config['base_path'];
1066
+ }
1067
+
1068
+ return new Client($options);
1069
+ }
1070
+
1071
+ private function createApplicationDefaultCredentials()
1072
+ {
1073
+ $scopes = $this->prepareScopes();
1074
+ $sub = $this->config['subject'];
1075
+ $signingKey = $this->config['signing_key'];
1076
+
1077
+ // create credentials using values supplied in setAuthConfig
1078
+ if ($signingKey) {
1079
+ $serviceAccountCredentials = array(
1080
+ 'client_id' => $this->config['client_id'],
1081
+ 'client_email' => $this->config['client_email'],
1082
+ 'private_key' => $signingKey,
1083
+ 'type' => 'service_account',
1084
+ );
1085
+ $credentials = CredentialsLoader::makeCredentials($scopes, $serviceAccountCredentials);
1086
+ } else {
1087
+ $credentials = ApplicationDefaultCredentials::getCredentials($scopes);
1088
+ }
1089
+
1090
+ // for service account domain-wide authority (impersonating a user)
1091
+ // @see https://developers.google.com/identity/protocols/OAuth2ServiceAccount
1092
+ if ($sub) {
1093
+ if (!$credentials instanceof ServiceAccountCredentials) {
1094
+ throw new DomainException('domain-wide authority requires service account credentials');
1095
+ }
1096
+
1097
+ $credentials->setSub($sub);
1098
+ }
1099
+
1100
+ return $credentials;
1101
+ }
1102
+
1103
+ protected function getAuthHandler()
1104
+ {
1105
+ // Be very careful using the cache, as the underlying auth library's cache
1106
+ // implementation is naive, and the cache keys do not account for user
1107
+ // sessions.
1108
+ //
1109
+ // @see https://github.com/google/google-api-php-client/issues/821
1110
+ return Google_AuthHandler_AuthHandlerFactory::build(
1111
+ $this->getCache(),
1112
+ $this->config['cache_config']
1113
+ );
1114
+ }
1115
+
1116
+ private function createUserRefreshCredentials($scope, $refreshToken)
1117
+ {
1118
+ $creds = array_filter(
1119
+ array(
1120
+ 'client_id' => $this->getClientId(),
1121
+ 'client_secret' => $this->getClientSecret(),
1122
+ 'refresh_token' => $refreshToken,
1123
+ )
1124
+ );
1125
+
1126
+ return new UserRefreshCredentials($scope, $creds);
1127
+ }
1128
+ }
includes/lib/google-api-php-client/src/Google/Collection.php ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if (!class_exists('Google_Client')) {
4
+ require_once __DIR__ . '/autoload.php';
5
+ }
6
+
7
+ /**
8
+ * Extension to the regular Google_Model that automatically
9
+ * exposes the items array for iteration, so you can just
10
+ * iterate over the object rather than a reference inside.
11
+ */
12
+ class Google_Collection extends Google_Model implements Iterator, Countable
13
+ {
14
+ protected $collection_key = 'items';
15
+
16
+ public function rewind()
17
+ {
18
+ if (isset($this->{$this->collection_key})
19
+ && is_array($this->{$this->collection_key})) {
20
+ reset($this->{$this->collection_key});
21
+ }
22
+ }
23
+
24
+ public function current()
25
+ {
26
+ $this->coerceType($this->key());
27
+ if (is_array($this->{$this->collection_key})) {
28
+ return current($this->{$this->collection_key});
29
+ }
30
+ }
31
+
32
+ public function key()
33
+ {
34
+ if (isset($this->{$this->collection_key})
35
+ && is_array($this->{$this->collection_key})) {
36
+ return key($this->{$this->collection_key});
37
+ }
38
+ }
39
+
40
+ public function next()
41
+ {
42
+ return next($this->{$this->collection_key});
43
+ }
44
+
45
+ public function valid()
46
+ {
47
+ $key = $this->key();
48
+ return $key !== null && $key !== false;
49
+ }
50
+
51
+ public function count()
52
+ {
53
+ if (!isset($this->{$this->collection_key})) {
54
+ return 0;
55
+ }
56
+ return count($this->{$this->collection_key});
57
+ }
58
+
59
+ public function offsetExists($offset)
60
+ {
61
+ if (!is_numeric($offset)) {
62
+ return parent::offsetExists($offset);
63
+ }
64
+ return isset($this->{$this->collection_key}[$offset]);
65
+ }
66
+
67
+ public function offsetGet($offset)
68
+ {
69
+ if (!is_numeric($offset)) {
70
+ return parent::offsetGet($offset);
71
+ }
72
+ $this->coerceType($offset);
73
+ return $this->{$this->collection_key}[$offset];
74
+ }
75
+
76
+ public function offsetSet($offset, $value)
77
+ {
78
+ if (!is_numeric($offset)) {
79
+ return parent::offsetSet($offset, $value);
80
+ }
81
+ $this->{$this->collection_key}[$offset] = $value;
82
+ }
83
+
84
+ public function offsetUnset($offset)
85
+ {
86
+ if (!is_numeric($offset)) {
87
+ return parent::offsetUnset($offset);
88
+ }
89
+ unset($this->{$this->collection_key}[$offset]);
90
+ }
91
+
92
+ private function coerceType($offset)
93
+ {
94
+ $keyType = $this->keyType($this->collection_key);
95
+ if ($keyType && !is_object($this->{$this->collection_key}[$offset])) {
96
+ $this->{$this->collection_key}[$offset] =
97
+ new $keyType($this->{$this->collection_key}[$offset]);
98
+ }
99
+ }
100
+ }
includes/lib/google-api-php-client/src/Google/Exception.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * Copyright 2013 Google Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ class Google_Exception extends Exception
19
+ {
20
+ }
includes/lib/google-api-php-client/src/Google/Http/Batch.php ADDED
@@ -0,0 +1,249 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * Copyright 2012 Google Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ use GuzzleHttp\Psr7;
19
+ use GuzzleHttp\Psr7\Request;
20
+ use GuzzleHttp\Psr7\Response;
21
+ use Psr\Http\Message\RequestInterface;
22
+ use Psr\Http\Message\ResponseInterface;
23
+
24
+ /**
25
+ * Class to handle batched requests to the Google API service.
26
+ */
27
+ class Google_Http_Batch
28
+ {
29
+ const BATCH_PATH = 'batch';
30
+
31
+ private static $CONNECTION_ESTABLISHED_HEADERS = array(
32
+ "HTTP/1.0 200 Connection established\r\n\r\n",
33
+ "HTTP/1.1 200 Connection established\r\n\r\n",
34
+ );
35
+
36
+ /** @var string Multipart Boundary. */
37
+ private $boundary;
38
+
39
+ /** @var array service requests to be executed. */
40
+ private $requests = array();
41
+
42
+ /** @var Google_Client */
43
+ private $client;
44
+
45
+ private $rootUrl;
46
+
47
+ private $batchPath;
48
+
49
+ public function __construct(
50
+ Google_Client $client,
51
+ $boundary = false,
52
+ $rootUrl = null,
53
+ $batchPath = null
54
+ ) {
55
+ $this->client = $client;
56
+ $this->boundary = $boundary ?: mt_rand();
57
+ $this->rootUrl = rtrim($rootUrl ?: $this->client->getConfig('base_path'), '/');
58
+ $this->batchPath = $batchPath ?: self::BATCH_PATH;
59
+ }
60
+
61
+ public function add(RequestInterface $request, $key = false)
62
+ {
63
+ if (false == $key) {
64
+ $key = mt_rand();
65
+ }
66
+
67
+ $this->requests[$key] = $request;
68
+ }
69
+
70
+ public function execute()
71
+ {
72
+ $body = '';
73
+ $classes = array();
74
+ $batchHttpTemplate = <<<EOF
75
+ --%s
76
+ Content-Type: application/http
77
+ Content-Transfer-Encoding: binary
78
+ MIME-Version: 1.0
79
+ Content-ID: %s
80
+
81
+ %s
82
+ %s%s
83
+
84
+
85
+ EOF;
86
+
87
+ /** @var Google_Http_Request $req */
88
+ foreach ($this->requests as $key => $request) {
89
+ $firstLine = sprintf(
90
+ '%s %s HTTP/%s',
91
+ $request->getMethod(),
92
+ $request->getRequestTarget(),
93
+ $request->getProtocolVersion()
94
+ );
95
+
96
+ $content = (string) $request->getBody();
97
+
98
+ $headers = '';
99
+ foreach ($request->getHeaders() as $name => $values) {
100
+ $headers .= sprintf("%s:%s\r\n", $name, implode(', ', $values));
101
+ }
102
+
103
+ $body .= sprintf(
104
+ $batchHttpTemplate,
105
+ $this->boundary,
106
+ $key,
107
+ $firstLine,
108
+ $headers,
109
+ $content ? "\n".$content : ''
110
+ );
111
+
112
+ $classes['response-' . $key] = $request->getHeaderLine('X-Php-Expected-Class');
113
+ }
114
+
115
+ $body .= "--{$this->boundary}--";
116
+ $body = trim($body);
117
+ $url = $this->rootUrl . '/' . $this->batchPath;
118
+ $headers = array(
119
+ 'Content-Type' => sprintf('multipart/mixed; boundary=%s', $this->boundary),
120
+ 'Content-Length' => strlen($body),
121
+ );
122
+
123
+ $request = new Request(
124
+ 'POST',
125
+ $url,
126
+ $headers,
127
+ $body
128
+ );
129
+
130
+ $response = $this->client->execute($request);
131
+
132
+ return $this->parseResponse($response, $classes);
133
+ }
134
+
135
+ public function parseResponse(ResponseInterface $response, $classes = array())
136
+ {
137
+ $contentType = $response->getHeaderLine('content-type');
138
+ $contentType = explode(';', $contentType);
139
+ $boundary = false;
140
+ foreach ($contentType as $part) {
141
+ $part = explode('=', $part, 2);
142
+ if (isset($part[0]) && 'boundary' == trim($part[0])) {
143
+ $boundary = $part[1];
144
+ }
145
+ }
146
+
147
+ $body = (string) $response->getBody();
148
+ if (!empty($body)) {
149
+ $body = str_replace("--$boundary--", "--$boundary", $body);
150
+ $parts = explode("--$boundary", $body);
151
+ $responses = array();
152
+ $requests = array_values($this->requests);
153
+
154
+ foreach ($parts as $i => $part) {
155
+ $part = trim($part);
156
+ if (!empty($part)) {
157
+ list($rawHeaders, $part) = explode("\r\n\r\n", $part, 2);
158
+ $headers = $this->parseRawHeaders($rawHeaders);
159
+
160
+ $status = substr($part, 0, strpos($part, "\n"));
161
+ $status = explode(" ", $status);
162
+ $status = $status[1];
163
+
164
+ list($partHeaders, $partBody) = $this->parseHttpResponse($part, false);
165
+ $response = new Response(
166
+ $status,
167
+ $partHeaders,
168
+ Psr7\stream_for($partBody)
169
+ );
170
+
171
+ // Need content id.
172
+ $key = $headers['content-id'];
173
+
174
+ try {
175
+ $response = Google_Http_REST::decodeHttpResponse($response, $requests[$i-1]);
176
+ } catch (Google_Service_Exception $e) {
177
+ // Store the exception as the response, so successful responses
178
+ // can be processed.
179
+ $response = $e;
180
+ }
181
+
182
+ $responses[$key] = $response;
183
+ }
184
+ }
185
+
186
+ return $responses;
187
+ }
188
+
189
+ return null;
190
+ }
191
+
192
+ private function parseRawHeaders($rawHeaders)
193
+ {
194
+ $headers = array();
195
+ $responseHeaderLines = explode("\r\n", $rawHeaders);
196
+ foreach ($responseHeaderLines as $headerLine) {
197
+ if ($headerLine && strpos($headerLine, ':') !== false) {
198
+ list($header, $value) = explode(': ', $headerLine, 2);
199
+ $header = strtolower($header);
200
+ if (isset($headers[$header])) {
201
+ $headers[$header] .= "\n" . $value;
202
+ } else {
203
+ $headers[$header] = $value;
204
+ }
205
+ }
206
+ }
207
+ return $headers;
208
+ }
209
+
210
+ /**
211
+ * Used by the IO lib and also the batch processing.
212
+ *
213
+ * @param $respData
214
+ * @param $headerSize
215
+ * @return array
216
+ */
217
+ private function parseHttpResponse($respData, $headerSize)
218
+ {
219
+ // check proxy header
220
+ foreach (self::$CONNECTION_ESTABLISHED_HEADERS as $established_header) {
221
+ if (stripos($respData, $established_header) !== false) {
222
+ // existed, remove it
223
+ $respData = str_ireplace($established_header, '', $respData);
224
+ // Subtract the proxy header size unless the cURL bug prior to 7.30.0
225
+ // is present which prevented the proxy header size from being taken into
226
+ // account.
227
+ // @TODO look into this
228
+ // if (!$this->needsQuirk()) {
229
+ // $headerSize -= strlen($established_header);
230
+ // }
231
+ break;
232
+ }
233
+ }
234
+
235
+ if ($headerSize) {
236
+ $responseBody = substr($respData, $headerSize);
237
+ $responseHeaders = substr($respData, 0, $headerSize);
238
+ } else {
239
+ $responseSegments = explode("\r\n\r\n", $respData, 2);
240
+ $responseHeaders = $responseSegments[0];
241
+ $responseBody = isset($responseSegments[1]) ? $responseSegments[1] :
242
+ null;
243
+ }
244
+
245
+ $responseHeaders = $this->parseRawHeaders($responseHeaders);
246
+
247
+ return array($responseHeaders, $responseBody);
248
+ }
249
+ }
includes/lib/google-api-php-client/src/Google/Http/MediaFileUpload.php ADDED
@@ -0,0 +1,351 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright 2012 Google Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ use GuzzleHttp\Psr7;
19
+ use GuzzleHttp\Psr7\Request;
20
+ use GuzzleHttp\Psr7\Uri;
21
+ use Psr\Http\Message\RequestInterface;
22
+
23
+ /**
24
+ * Manage large file uploads, which may be media but can be any type
25
+ * of sizable data.
26
+ */
27
+ class Google_Http_MediaFileUpload
28
+ {
29
+ const UPLOAD_MEDIA_TYPE = 'media';
30
+ const UPLOAD_MULTIPART_TYPE = 'multipart';
31
+ const UPLOAD_RESUMABLE_TYPE = 'resumable';
32
+
33
+ /** @var string $mimeType */
34
+ private $mimeType;
35
+
36
+ /** @var string $data */
37
+ private $data;
38
+
39
+ /** @var bool $resumable */
40
+ private $resumable;
41
+
42
+ /** @var int $chunkSize */
43
+ private $chunkSize;
44
+
45
+ /** @var int $size */
46
+ private $size;
47
+
48
+ /** @var string $resumeUri */
49
+ private $resumeUri;
50
+
51
+ /** @var int $progress */
52
+ private $progress;
53
+
54
+ /** @var Google_Client */
55
+ private $client;
56
+
57
+ /** @var Psr\Http\Message\RequestInterface */
58
+ private $request;
59
+
60
+ /** @var string */
61
+ private $boundary;
62
+
63
+ /**
64
+ * Result code from last HTTP call
65
+ * @var int
66
+ */
67
+ private $httpResultCode;
68
+
69
+ /**
70
+ * @param $mimeType string
71
+ * @param $data string The bytes you want to upload.
72
+ * @param $resumable bool
73
+ * @param bool $chunkSize File will be uploaded in chunks of this many bytes.
74
+ * only used if resumable=True
75
+ */
76
+ public function __construct(
77
+ Google_Client $client,
78
+ RequestInterface $request,
79
+ $mimeType,
80
+ $data,
81
+ $resumable = false,
82
+ $chunkSize = false
83
+ ) {
84
+ $this->client = $client;
85
+ $this->request = $request;
86
+ $this->mimeType = $mimeType;
87
+ $this->data = $data;
88
+ $this->resumable = $resumable;
89
+ $this->chunkSize = $chunkSize;
90
+ $this->progress = 0;
91
+
92
+ $this->process();
93
+ }
94
+
95
+ /**
96
+ * Set the size of the file that is being uploaded.
97
+ * @param $size - int file size in bytes
98
+ */
99
+ public function setFileSize($size)
100
+ {
101
+ $this->size = $size;
102
+ }
103
+
104
+ /**
105
+ * Return the progress on the upload
106
+ * @return int progress in bytes uploaded.
107
+ */
108
+ public function getProgress()
109
+ {
110
+ return $this->progress;
111
+ }
112
+
113
+ /**
114
+ * Send the next part of the file to upload.
115
+ * @param [$chunk] the next set of bytes to send. If false will used $data passed
116
+ * at construct time.
117
+ */
118
+ public function nextChunk($chunk = false)
119
+ {
120
+ $resumeUri = $this->getResumeUri();
121
+
122
+ if (false == $chunk) {
123
+ $chunk = substr($this->data, $this->progress, $this->chunkSize);
124
+ }
125
+
126
+ $lastBytePos = $this->progress + strlen($chunk) - 1;
127
+ $headers = array(
128
+ 'content-range' => "bytes $this->progress-$lastBytePos/$this->size",
129
+ 'content-length' => strlen($chunk),
130
+ 'expect' => '',
131
+ );
132
+
133
+ $request = new Request(
134
+ 'PUT',
135
+ $resumeUri,
136
+ $headers,
137
+ Psr7\stream_for($chunk)
138
+ );
139
+
140
+ return $this->makePutRequest($request);
141
+ }
142
+
143
+ /**
144
+ * Return the HTTP result code from the last call made.
145
+ * @return int code
146
+ */
147
+ public function getHttpResultCode()
148
+ {
149
+ return $this->httpResultCode;
150
+ }
151
+
152
+ /**
153
+ * Sends a PUT-Request to google drive and parses the response,
154
+ * setting the appropiate variables from the response()
155
+ *
156
+ * @param Google_Http_Request $httpRequest the Reuqest which will be send
157
+ *
158
+ * @return false|mixed false when the upload is unfinished or the decoded http response
159
+ *
160
+ */
161
+ private function makePutRequest(RequestInterface $request)
162
+ {
163
+ $response = $this->client->execute($request);
164
+ $this->httpResultCode = $response->getStatusCode();
165
+
166
+ if (308 == $this->httpResultCode) {
167
+ // Track the amount uploaded.
168
+ $range = $response->getHeaderLine('range');
169
+ if ($range) {
170
+ $range_array = explode('-', $range);
171
+ $this->progress = $range_array[1] + 1;
172
+ }
173
+
174
+ // Allow for changing upload URLs.
175
+ $location = $response->getHeaderLine('location');
176
+ if ($location) {
177
+ $this->resumeUri = $location;
178
+ }
179
+
180
+ // No problems, but upload not complete.
181
+ return false;
182
+ }
183
+
184
+ return Google_Http_REST::decodeHttpResponse($response, $this->request);
185
+ }
186
+
187
+ /**
188
+ * Resume a previously unfinished upload
189
+ * @param $resumeUri the resume-URI of the unfinished, resumable upload.
190
+ */
191
+ public function resume($resumeUri)
192
+ {
193
+ $this->resumeUri = $resumeUri;
194
+ $headers = array(
195
+ 'content-range' => "bytes */$this->size",
196
+ 'content-length' => 0,
197
+ );
198
+ $httpRequest = new Request(
199
+ 'PUT',
200
+ $this->resumeUri,
201
+ $headers
202
+ );
203
+
204
+ return $this->makePutRequest($httpRequest);
205
+ }
206
+
207
+ /**
208
+ * @return Psr\Http\Message\RequestInterface $request
209
+ * @visible for testing
210
+ */
211
+ private function process()
212
+ {
213
+ $this->transformToUploadUrl();
214
+ $request = $this->request;
215
+
216
+ $postBody = '';
217
+ $contentType = false;
218
+
219
+ $meta = (string) $request->getBody();
220
+ $meta = is_string($meta) ? json_decode($meta, true) : $meta;
221
+
222
+ $uploadType = $this->getUploadType($meta);
223
+ $request = $request->withUri(
224
+ Uri::withQueryValue($request->getUri(), 'uploadType', $uploadType)
225
+ );
226
+
227
+ $mimeType = $this->mimeType ?: $request->getHeaderLine('content-type');
228
+
229
+ if (self::UPLOAD_RESUMABLE_TYPE == $uploadType) {
230
+ $contentType = $mimeType;
231
+ $postBody = is_string($meta) ? $meta : json_encode($meta);
232
+ } else if (self::UPLOAD_MEDIA_TYPE == $uploadType) {
233
+ $contentType = $mimeType;
234
+ $postBody = $this->data;
235
+ } else if (self::UPLOAD_MULTIPART_TYPE == $uploadType) {
236
+ // This is a multipart/related upload.
237
+ $boundary = $this->boundary ?: mt_rand();
238
+ $boundary = str_replace('"', '', $boundary);
239
+ $contentType = 'multipart/related; boundary=' . $boundary;
240
+ $related = "--$boundary\r\n";
241
+ $related .= "Content-Type: application/json; charset=UTF-8\r\n";
242
+ $related .= "\r\n" . json_encode($meta) . "\r\n";
243
+ $related .= "--$boundary\r\n";
244
+ $related .= "Content-Type: $mimeType\r\n";
245
+ $related .= "Content-Transfer-Encoding: base64\r\n";
246
+ $related .= "\r\n" . base64_encode($this->data) . "\r\n";
247
+ $related .= "--$boundary--";
248
+ $postBody = $related;
249
+ }
250
+
251
+ $request = $request->withBody(Psr7\stream_for($postBody));
252
+
253
+ if (isset($contentType) && $contentType) {
254
+ $request = $request->withHeader('content-type', $contentType);
255
+ }
256
+
257
+ return $this->request = $request;
258
+ }
259
+
260
+ /**
261
+ * Valid upload types:
262
+ * - resumable (UPLOAD_RESUMABLE_TYPE)
263
+ * - media (UPLOAD_MEDIA_TYPE)
264
+ * - multipart (UPLOAD_MULTIPART_TYPE)
265
+ * @param $meta
266
+ * @return string
267
+ * @visible for testing
268
+ */
269
+ public function getUploadType($meta)
270
+ {
271
+ if ($this->resumable) {
272
+ return self::UPLOAD_RESUMABLE_TYPE;
273
+ }
274
+
275
+ if (false == $meta && $this->data) {
276
+ return self::UPLOAD_MEDIA_TYPE;
277
+ }
278
+
279
+ return self::UPLOAD_MULTIPART_TYPE;
280
+ }
281
+
282
+ public function getResumeUri()
283
+ {
284
+ if (null === $this->resumeUri) {
285
+ $this->resumeUri = $this->fetchResumeUri();
286
+ }
287
+
288
+ return $this->resumeUri;
289
+ }
290
+
291
+ private function fetchResumeUri()
292
+ {
293
+ $body = $this->request->getBody();
294
+ if ($body) {
295
+ $headers = array(
296
+ 'content-type' => 'application/json; charset=UTF-8',
297
+ 'content-length' => $body->getSize(),
298
+ 'x-upload-content-type' => $this->mimeType,
299
+ 'x-upload-content-length' => $this->size,
300
+ 'expect' => '',
301
+ );
302
+ foreach ($headers as $key => $value) {
303
+ $this->request = $this->request->withHeader($key, $value);
304
+ }
305
+ }
306
+
307
+ $response = $this->client->execute($this->request, false);
308
+ $location = $response->getHeaderLine('location');
309
+ $code = $response->getStatusCode();
310
+
311
+ if (200 == $code && true == $location) {
312
+ return $location;
313
+ }
314
+
315
+ $message = $code;
316
+ $body = json_decode((string) $this->request->getBody(), true);
317
+ if (isset($body['error']['errors'])) {
318
+ $message .= ': ';
319
+ foreach ($body['error']['errors'] as $error) {
320
+ $message .= "{$error[domain]}, {$error[message]};";
321
+ }
322
+ $message = rtrim($message, ';');
323
+ }
324
+
325
+ $error = "Failed to start the resumable upload (HTTP {$message})";
326
+ $this->client->getLogger()->error($error);
327
+
328
+ throw new Google_Exception($error);
329
+ }
330
+
331
+ private function transformToUploadUrl()
332
+ {
333
+ $parts = parse_url((string) $this->request->getUri());
334
+ if (!isset($parts['path'])) {
335
+ $parts['path'] = '';
336
+ }
337
+ $parts['path'] = '/upload' . $parts['path'];
338
+ $uri = Uri::fromParts($parts);
339
+ $this->request = $this->request->withUri($uri);
340
+ }
341
+
342
+ public function setChunkSize($chunkSize)
343
+ {
344
+ $this->chunkSize = $chunkSize;
345
+ }
346
+
347
+ public function getRequest()
348
+ {
349
+ return $this->request;
350
+ }
351
+ }
includes/lib/google-api-php-client/src/Google/Http/REST.php ADDED
@@ -0,0 +1,182 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * Copyright 2010 Google Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ use Google\Auth\HttpHandler\HttpHandlerFactory;
19
+ use GuzzleHttp\ClientInterface;
20
+ use GuzzleHttp\Exception\RequestException;
21
+ use GuzzleHttp\Psr7\Response;
22
+ use Psr\Http\Message\RequestInterface;
23
+ use Psr\Http\Message\ResponseInterface;
24
+
25
+ /**
26
+ * This class implements the RESTful transport of apiServiceRequest()'s
27
+ */
28
+ class Google_Http_REST
29
+ {
30
+ /**
31
+ * Executes a Psr\Http\Message\RequestInterface and (if applicable) automatically retries
32
+ * when errors occur.
33
+ *
34
+ * @param Google_Client $client
35
+ * @param Psr\Http\Message\RequestInterface $req
36
+ * @return array decoded result
37
+ * @throws Google_Service_Exception on server side error (ie: not authenticated,
38
+ * invalid or malformed post body, invalid url)
39
+ */
40
+ public static function execute(
41
+ ClientInterface $client,
42
+ RequestInterface $request,
43
+ $expectedClass = null,
44
+ $config = array(),
45
+ $retryMap = null
46
+ ) {
47
+ $runner = new Google_Task_Runner(
48
+ $config,
49
+ sprintf('%s %s', $request->getMethod(), (string) $request->getUri()),
50
+ array(get_class(), 'doExecute'),
51
+ array($client, $request, $expectedClass)
52
+ );
53
+
54
+ if (null !== $retryMap) {
55
+ $runner->setRetryMap($retryMap);
56
+ }
57
+
58
+ return $runner->run();
59
+ }
60
+
61
+ /**
62
+ * Executes a Psr\Http\Message\RequestInterface
63
+ *
64
+ * @param Google_Client $client
65
+ * @param Psr\Http\Message\RequestInterface $request
66
+ * @return array decoded result
67
+ * @throws Google_Service_Exception on server side error (ie: not authenticated,
68
+ * invalid or malformed post body, invalid url)
69
+ */
70
+ public static function doExecute(ClientInterface $client, RequestInterface $request, $expectedClass = null)
71
+ {
72
+ try {
73
+ $httpHandler = HttpHandlerFactory::build($client);
74
+ $response = $httpHandler($request);
75
+ } catch (RequestException $e) {
76
+ // if Guzzle throws an exception, catch it and handle the response
77
+ if (!$e->hasResponse()) {
78
+ throw $e;
79
+ }
80
+
81
+ $response = $e->getResponse();
82
+ // specific checking for Guzzle 5: convert to PSR7 response
83
+ if ($response instanceof \GuzzleHttp\Message\ResponseInterface) {
84
+ $response = new Response(
85
+ $response->getStatusCode(),
86
+ $response->getHeaders() ?: [],
87
+ $response->getBody(),
88
+ $response->getProtocolVersion(),
89
+ $response->getReasonPhrase()
90
+ );
91
+ }
92
+ }
93
+
94
+ return self::decodeHttpResponse($response, $request, $expectedClass);
95
+ }
96
+
97
+ /**
98
+ * Decode an HTTP Response.
99
+ * @static
100
+ * @throws Google_Service_Exception
101
+ * @param Psr\Http\Message\RequestInterface $response The http response to be decoded.
102
+ * @param Psr\Http\Message\ResponseInterface $response
103
+ * @return mixed|null
104
+ */
105
+ public static function decodeHttpResponse(
106
+ ResponseInterface $response,
107
+ RequestInterface $request = null,
108
+ $expectedClass = null
109
+ ) {
110
+ $code = $response->getStatusCode();
111
+
112
+ // retry strategy
113
+ if (intVal($code) >= 400) {
114
+ // if we errored out, it should be safe to grab the response body
115
+ $body = (string) $response->getBody();
116
+
117
+ // Check if we received errors, and add those to the Exception for convenience
118
+ throw new Google_Service_Exception($body, $code, null, self::getResponseErrors($body));
119
+ }
120
+
121
+ // Ensure we only pull the entire body into memory if the request is not
122
+ // of media type
123
+ $body = self::decodeBody($response, $request);
124
+
125
+ if ($expectedClass = self::determineExpectedClass($expectedClass, $request)) {
126
+ $json = json_decode($body, true);
127
+
128
+ return new $expectedClass($json);
129
+ }
130
+
131
+ return $response;
132
+ }
133
+
134
+ private static function decodeBody(ResponseInterface $response, RequestInterface $request = null)
135
+ {
136
+ if (self::isAltMedia($request)) {
137
+ // don't decode the body, it's probably a really long string
138
+ return '';
139
+ }
140
+
141
+ return (string) $response->getBody();
142
+ }
143
+
144
+ private static function determineExpectedClass($expectedClass, RequestInterface $request = null)
145
+ {
146
+ // "false" is used to explicitly prevent an expected class from being returned
147
+ if (false === $expectedClass) {
148
+ return null;
149
+ }
150
+
151
+ // if we don't have a request, we just use what's passed in
152
+ if (null === $request) {
153
+ return $expectedClass;
154
+ }
155
+
156
+ // return what we have in the request header if one was not supplied
157
+ return $expectedClass ?: $request->getHeaderLine('X-Php-Expected-Class');
158
+ }
159
+
160
+ private static function getResponseErrors($body)
161
+ {
162
+ $json = json_decode($body, true);
163
+
164
+ if (isset($json['error']['errors'])) {
165
+ return $json['error']['errors'];
166
+ }
167
+
168
+ return null;
169
+ }
170
+
171
+ private static function isAltMedia(RequestInterface $request = null)
172
+ {
173
+ if ($request && $qs = $request->getUri()->getQuery()) {
174
+ parse_str($qs, $query);
175
+ if (isset($query['alt']) && $query['alt'] == 'media') {
176
+ return true;
177
+ }
178
+ }
179
+
180
+ return false;
181
+ }
182
+ }
includes/lib/google-api-php-client/src/Google/Model.php ADDED
@@ -0,0 +1,317 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * Copyright 2011 Google Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ /**
19
+ * This class defines attributes, valid values, and usage which is generated
20
+ * from a given json schema.
21
+ * http://tools.ietf.org/html/draft-zyp-json-schema-03#section-5
22
+ *
23
+ */
24
+ class Google_Model implements ArrayAccess
25
+ {
26
+ /**
27
+ * If you need to specify a NULL JSON value, use Google_Model::NULL_VALUE
28
+ * instead - it will be replaced when converting to JSON with a real null.
29
+ */
30
+ const NULL_VALUE = "{}gapi-php-null";
31
+ protected $internal_gapi_mappings = array();
32
+ protected $modelData = array();
33
+ protected $processed = array();
34
+
35
+ /**
36
+ * Polymorphic - accepts a variable number of arguments dependent
37
+ * on the type of the model subclass.
38
+ */
39
+ final public function __construct()
40
+ {
41
+ if (func_num_args() == 1 && is_array(func_get_arg(0))) {
42
+ // Initialize the model with the array's contents.
43
+ $array = func_get_arg(0);
44
+ $this->mapTypes($array);
45
+ }
46
+ $this->gapiInit();
47
+ }
48
+
49
+ /**
50
+ * Getter that handles passthrough access to the data array, and lazy object creation.
51
+ * @param string $key Property name.
52
+ * @return mixed The value if any, or null.
53
+ */
54
+ public function __get($key)
55
+ {
56
+ $keyType = $this->keyType($key);
57
+ $keyDataType = $this->dataType($key);
58
+ if ($keyType && !isset($this->processed[$key])) {
59
+ if (isset($this->modelData[$key])) {
60
+ $val = $this->modelData[$key];
61
+ } elseif ($keyDataType == 'array' || $keyDataType == 'map') {
62
+ $val = array();
63
+ } else {
64
+ $val = null;
65
+ }
66
+
67
+ if ($this->isAssociativeArray($val)) {
68
+ if ($keyDataType && 'map' == $keyDataType) {
69
+ foreach ($val as $arrayKey => $arrayItem) {
70
+ $this->modelData[$key][$arrayKey] =
71
+ new $keyType($arrayItem);
72
+ }
73
+ } else {
74
+ $this->modelData[$key] = new $keyType($val);
75
+ }
76
+ } else if (is_array($val)) {
77
+ $arrayObject = array();
78
+ foreach ($val as $arrayIndex => $arrayItem) {
79
+ $arrayObject[$arrayIndex] = new $keyType($arrayItem);
80
+ }
81
+ $this->modelData[$key] = $arrayObject;
82
+ }
83
+ $this->processed[$key] = true;
84
+ }
85
+
86
+ return isset($this->modelData[$key]) ? $this->modelData[$key] : null;
87
+ }
88
+
89
+ /**
90
+ * Initialize this object's properties from an array.
91
+ *
92
+ * @param array $array Used to seed this object's properties.
93
+ * @return void
94
+ */
95
+ protected function mapTypes($array)
96
+ {
97
+ // Hard initialise simple types, lazy load more complex ones.
98
+ foreach ($array as $key => $val) {
99
+ if ($keyType = $this->keyType($key)) {
100
+ $dataType = $this->dataType($key);
101
+ if ($dataType == 'array' || $dataType == 'map') {
102
+ $this->$key = array();
103
+ foreach ($val as $itemKey => $itemVal) {
104
+ if ($itemVal instanceof $keyType) {
105
+ $this->{$key}[$itemKey] = $itemVal;
106
+ } else {
107
+ $this->{$key}[$itemKey] = new $keyType($itemVal);
108
+ }
109
+ }
110
+ } elseif ($val instanceof $keyType) {
111
+ $this->$key = $val;
112
+ } else {
113
+ $this->$key = new $keyType($val);
114
+ }
115
+ unset($array[$key]);
116
+ } elseif (property_exists($this, $key)) {
117
+ $this->$key = $val;
118
+ unset($array[$key]);
119
+ } elseif (property_exists($this, $camelKey = $this->camelCase($key))) {
120
+ // This checks if property exists as camelCase, leaving it in array as snake_case
121
+ // in case of backwards compatibility issues.
122
+ $this->$camelKey = $val;
123
+ }
124
+ }
125
+ $this->modelData = $array;
126
+ }
127
+
128
+ /**
129
+ * Blank initialiser to be used in subclasses to do post-construction initialisation - this
130
+ * avoids the need for subclasses to have to implement the variadics handling in their
131
+ * constructors.
132
+ */
133
+ protected function gapiInit()
134
+ {
135
+ return;
136
+ }
137
+
138
+ /**
139
+ * Create a simplified object suitable for straightforward
140
+ * conversion to JSON. This is relatively expensive
141
+ * due to the usage of reflection, but shouldn't be called
142
+ * a whole lot, and is the most straightforward way to filter.
143
+ */
144
+ public function toSimpleObject()
145
+ {
146
+ $object = new stdClass();
147
+
148
+ // Process all other data.
149
+ foreach ($this->modelData as $key => $val) {
150
+ $result = $this->getSimpleValue($val);
151
+ if ($result !== null) {
152
+ $object->$key = $this->nullPlaceholderCheck($result);
153
+ }
154
+ }
155
+
156
+ // Process all public properties.
157
+ $reflect = new ReflectionObject($this);
158
+ $props = $reflect->getProperties(ReflectionProperty::IS_PUBLIC);
159
+ foreach ($props as $member) {
160
+ $name = $member->getName();
161
+ $result = $this->getSimpleValue($this->$name);
162
+ if ($result !== null) {
163
+ $name = $this->getMappedName($name);
164
+ $object->$name = $this->nullPlaceholderCheck($result);
165
+ }
166
+ }
167
+
168
+ return $object;
169
+ }
170
+
171
+ /**
172
+ * Handle different types of values, primarily
173
+ * other objects and map and array data types.
174
+ */
175
+ private function getSimpleValue($value)
176
+ {
177
+ if ($value instanceof Google_Model) {
178
+ return $value->toSimpleObject();
179
+ } else if (is_array($value)) {
180
+ $return = array();
181
+ foreach ($value as $key => $a_value) {
182
+ $a_value = $this->getSimpleValue($a_value);
183
+ if ($a_value !== null) {
184
+ $key = $this->getMappedName($key);
185
+ $return[$key] = $this->nullPlaceholderCheck($a_value);
186
+ }
187
+ }
188
+ return $return;
189
+ }
190
+ return $value;
191
+ }
192
+
193
+ /**
194
+ * Check whether the value is the null placeholder and return true null.
195
+ */
196
+ private function nullPlaceholderCheck($value)
197
+ {
198
+ if ($value === self::NULL_VALUE) {
199
+ return null;
200
+ }
201
+ return $value;
202
+ }
203
+
204
+ /**
205
+ * If there is an internal name mapping, use that.
206
+ */
207
+ private function getMappedName($key)
208
+ {
209
+ if (isset($this->internal_gapi_mappings, $this->internal_gapi_mappings[$key])) {
210
+ $key = $this->internal_gapi_mappings[$key];
211
+ }
212
+ return $key;
213
+ }
214
+
215
+ /**
216
+ * Returns true only if the array is associative.
217
+ * @param array $array
218
+ * @return bool True if the array is associative.
219
+ */
220
+ protected function isAssociativeArray($array)
221
+ {
222
+ if (!is_array($array)) {
223
+ return false;
224
+ }
225
+ $keys = array_keys($array);
226
+ foreach ($keys as $key) {
227
+ if (is_string($key)) {
228
+ return true;
229
+ }
230
+ }
231
+ return false;
232
+ }
233
+
234
+ /**
235
+ * Verify if $obj is an array.
236
+ * @throws Google_Exception Thrown if $obj isn't an array.
237
+ * @param array $obj Items that should be validated.
238
+ * @param string $method Method expecting an array as an argument.
239
+ */
240
+ public function assertIsArray($obj, $method)
241
+ {
242
+ if ($obj && !is_array($obj)) {
243
+ throw new Google_Exception(
244
+ "Incorrect parameter type passed to $method(). Expected an array."
245
+ );
246
+ }
247
+ }
248
+
249
+ public function offsetExists($offset)
250
+ {
251
+ return isset($this->$offset) || isset($this->modelData[$offset]);
252
+ }
253
+
254
+ public function offsetGet($offset)
255
+ {
256
+ return isset($this->$offset) ?
257
+ $this->$offset :
258
+ $this->__get($offset);
259
+ }
260
+
261
+ public function offsetSet($offset, $value)
262
+ {
263
+ if (property_exists($this, $offset)) {
264
+ $this->$offset = $value;
265
+ } else {
266
+ $this->modelData[$offset] = $value;
267
+ $this->processed[$offset] = true;
268
+ }
269
+ }
270
+
271
+ public function offsetUnset($offset)
272
+ {
273
+ unset($this->modelData[$offset]);
274
+ }
275
+
276
+ protected function keyType($key)
277
+ {
278
+ $keyType = $key . "Type";
279
+
280
+ // ensure keyType is a valid class
281
+ if (property_exists($this, $keyType) && class_exists($this->$keyType)) {
282
+ return $this->$keyType;
283
+ }
284
+ }
285
+
286
+ protected function dataType($key)
287
+ {
288
+ $dataType = $key . "DataType";
289
+
290
+ if (property_exists($this, $dataType)) {
291
+ return $this->$dataType;
292
+ }
293
+ }
294
+
295
+ public function __isset($key)
296
+ {
297
+ return isset($this->modelData[$key]);
298
+ }
299
+
300
+ public function __unset($key)
301
+ {
302
+ unset($this->modelData[$key]);
303
+ }
304
+
305
+ /**
306
+ * Convert a string to camelCase
307
+ * @param string $value
308
+ * @return string
309
+ */
310
+ private function camelCase($value)
311
+ {
312
+ $value = ucwords(str_replace(array('-', '_'), ' ', $value));
313
+ $value = str_replace(' ', '', $value);
314
+ $value[0] = strtolower($value[0]);
315
+ return $value;
316
+ }
317
+ }
includes/lib/google-api-php-client/src/Google/Service.php ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * Copyright 2010 Google Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ class Google_Service
19
+ {
20
+ public $batchPath;
21
+ public $rootUrl;
22
+ public $version;
23
+ public $servicePath;
24
+ public $availableScopes;
25
+ public $resource;
26
+ private $client;
27
+
28
+ public function __construct(Google_Client $client)
29
+ {
30
+ $this->client = $client;
31
+ }
32
+
33
+ /**
34
+ * Return the associated Google_Client class.
35
+ * @return Google_Client
36
+ */
37
+ public function getClient()
38
+ {
39
+ return $this->client;
40
+ }
41
+
42
+ /**
43
+ * Create a new HTTP Batch handler for this service
44
+ *
45
+ * @return Google_Http_Batch
46
+ */
47
+ public function createBatch()
48
+ {
49
+ return new Google_Http_Batch(
50
+ $this->client,
51
+ false,
52
+ $this->rootUrl,
53
+ $this->batchPath
54
+ );
55
+ }
56
+ }
includes/lib/google-api-php-client/src/Google/Service/Exception.php ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * Copyright 2014 Google Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ class Google_Service_Exception extends Google_Exception
19
+ {
20
+ /**
21
+ * Optional list of errors returned in a JSON body of an HTTP error response.
22
+ */
23
+ protected $errors = array();
24
+
25
+ /**
26
+ * Override default constructor to add the ability to set $errors and a retry
27
+ * map.
28
+ *
29
+ * @param string $message
30
+ * @param int $code
31
+ * @param Exception|null $previous
32
+ * @param [{string, string}] errors List of errors returned in an HTTP
33
+ * response. Defaults to [].
34
+ * @param array|null $retryMap Map of errors with retry counts.
35
+ */
36
+ public function __construct(
37
+ $message,
38
+ $code = 0,
39
+ Exception $previous = null,
40
+ $errors = array()
41
+ ) {
42
+ if (version_compare(PHP_VERSION, '5.3.0') >= 0) {
43
+ parent::__construct($message, $code, $previous);
44
+ } else {
45
+ parent::__construct($message, $code);
46
+ }
47
+
48
+ $this->errors = $errors;
49
+ }
50
+
51
+ /**
52
+ * An example of the possible errors returned.
53
+ *
54
+ * {
55
+ * "domain": "global",
56
+ * "reason": "authError",
57
+ * "message": "Invalid Credentials",
58
+ * "locationType": "header",
59
+ * "location": "Authorization",
60
+ * }
61
+ *
62
+ * @return [{string, string}] List of errors return in an HTTP response or [].
63
+ */
64
+ public function getErrors()
65
+ {
66
+ return $this->errors;
67
+ }
68
+ }
includes/lib/google-api-php-client/src/Google/Service/README.md ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
1
+ # Google API Client Services
2
+
3
+ Google API Client Service classes have been moved to the
4
+ [google-api-php-client-services](https://github.com/google/google-api-php-client-services)
5
+ repository.
includes/lib/google-api-php-client/src/Google/Service/Resource.php ADDED
@@ -0,0 +1,302 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright 2010 Google Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ use GuzzleHttp\Psr7\Request;
19
+
20
+ /**
21
+ * Implements the actual methods/resources of the discovered Google API using magic function
22
+ * calling overloading (__call()), which on call will see if the method name (plus.activities.list)
23
+ * is available in this service, and if so construct an apiHttpRequest representing it.
24
+ *
25
+ */
26
+ class Google_Service_Resource
27
+ {
28
+ // Valid query parameters that work, but don't appear in discovery.
29
+ private $stackParameters = array(
30
+ 'alt' => array('type' => 'string', 'location' => 'query'),
31
+ 'fields' => array('type' => 'string', 'location' => 'query'),
32
+ 'trace' => array('type' => 'string', 'location' => 'query'),
33
+ 'userIp' => array('type' => 'string', 'location' => 'query'),
34
+ 'quotaUser' => array('type' => 'string', 'location' => 'query'),
35
+ 'data' => array('type' => 'string', 'location' => 'body'),
36
+ 'mimeType' => array('type' => 'string', 'location' => 'header'),
37
+ 'uploadType' => array('type' => 'string', 'location' => 'query'),
38
+ 'mediaUpload' => array('type' => 'complex', 'location' => 'query'),
39
+ 'prettyPrint' => array('type' => 'string', 'location' => 'query'),
40
+ );
41
+
42
+ /** @var string $rootUrl */
43
+ private $rootUrl;
44
+
45
+ /** @var Google_Client $client */
46
+ private $client;
47
+
48
+ /** @var string $serviceName */
49
+ private $serviceName;
50
+
51
+ /** @var string $servicePath */
52
+ private $servicePath;
53
+
54
+ /** @var string $resourceName */
55
+ private $resourceName;
56
+
57
+ /** @var array $methods */
58
+ private $methods;
59
+
60
+ public function __construct($service, $serviceName, $resourceName, $resource)
61
+ {
62
+ $this->rootUrl = $service->rootUrl;
63
+ $this->client = $service->getClient();
64
+ $this->servicePath = $service->servicePath;
65
+ $this->serviceName = $serviceName;
66
+ $this->resourceName = $resourceName;
67
+ $this->methods = is_array($resource) && isset($resource['methods']) ?
68
+ $resource['methods'] :
69
+ array($resourceName => $resource);
70
+ }
71
+
72
+ /**
73
+ * TODO: This function needs simplifying.
74
+ * @param $name
75
+ * @param $arguments
76
+ * @param $expectedClass - optional, the expected class name
77
+ * @return Google_Http_Request|expectedClass
78
+ * @throws Google_Exception
79
+ */
80
+ public function call($name, $arguments, $expectedClass = null)
81
+ {
82
+ if (! isset($this->methods[$name])) {
83
+ $this->client->getLogger()->error(
84
+ 'Service method unknown',
85
+ array(
86
+ 'service' => $this->serviceName,
87
+ 'resource' => $this->resourceName,
88
+ 'method' => $name
89
+ )
90
+ );
91
+
92
+ throw new Google_Exception(
93
+ "Unknown function: " .
94
+ "{$this->serviceName}->{$this->resourceName}->{$name}()"
95
+ );
96
+ }
97
+ $method = $this->methods[$name];
98
+ $parameters = $arguments[0];
99
+
100
+ // postBody is a special case since it's not defined in the discovery
101
+ // document as parameter, but we abuse the param entry for storing it.
102
+ $postBody = null;
103
+ if (isset($parameters['postBody'])) {
104
+ if ($parameters['postBody'] instanceof Google_Model) {
105
+ // In the cases the post body is an existing object, we want
106
+ // to use the smart method to create a simple object for
107
+ // for JSONification.
108
+ $parameters['postBody'] = $parameters['postBody']->toSimpleObject();
109
+ } else if (is_object($parameters['postBody'])) {
110
+ // If the post body is another kind of object, we will try and
111
+ // wrangle it into a sensible format.
112
+ $parameters['postBody'] =
113
+ $this->convertToArrayAndStripNulls($parameters['postBody']);
114
+ }
115
+ $postBody = (array) $parameters['postBody'];
116
+ unset($parameters['postBody']);
117
+ }
118
+
119
+ // TODO: optParams here probably should have been
120
+ // handled already - this may well be redundant code.
121
+ if (isset($parameters['optParams'])) {
122
+ $optParams = $parameters['optParams'];
123
+ unset($parameters['optParams']);
124
+ $parameters = array_merge($parameters, $optParams);
125
+ }
126
+
127
+ if (!isset($method['parameters'])) {
128
+ $method['parameters'] = array();
129
+ }
130
+
131
+ $method['parameters'] = array_merge(
132
+ $this->stackParameters,
133
+ $method['parameters']
134
+ );
135
+
136
+ foreach ($parameters as $key => $val) {
137
+ if ($key != 'postBody' && ! isset($method['parameters'][$key])) {
138
+ $this->client->getLogger()->error(
139
+ 'Service parameter unknown',
140
+ array(
141
+ 'service' => $this->serviceName,
142
+ 'resource' => $this->resourceName,
143
+ 'method' => $name,
144
+ 'parameter' => $key
145
+ )
146
+ );
147
+ throw new Google_Exception("($name) unknown parameter: '$key'");
148
+ }
149
+ }
150
+
151
+ foreach ($method['parameters'] as $paramName => $paramSpec) {
152
+ if (isset($paramSpec['required']) &&
153
+ $paramSpec['required'] &&
154
+ ! isset($parameters[$paramName])
155
+ ) {
156
+ $this->client->getLogger()->error(
157
+ 'Service parameter missing',
158
+ array(
159
+ 'service' => $this->serviceName,
160
+ 'resource' => $this->resourceName,
161
+ 'method' => $name,
162
+ 'parameter' => $paramName
163
+ )
164
+ );
165
+ throw new Google_Exception("($name) missing required param: '$paramName'");
166
+ }
167
+ if (isset($parameters[$paramName])) {
168
+ $value = $parameters[$paramName];
169
+ $parameters[$paramName] = $paramSpec;
170
+ $parameters[$paramName]['value'] = $value;
171
+ unset($parameters[$paramName]['required']);
172
+ } else {
173
+ // Ensure we don't pass nulls.
174
+ unset($parameters[$paramName]);
175
+ }
176
+ }
177
+
178
+ $this->client->getLogger()->info(
179
+ 'Service Call',
180
+ array(
181
+ 'service' => $this->serviceName,
182
+ 'resource' => $this->resourceName,
183
+ 'method' => $name,
184
+ 'arguments' => $parameters,
185
+ )
186
+ );
187
+
188
+ // build the service uri
189
+ $url = $this->createRequestUri(
190
+ $method['path'],
191
+ $parameters
192
+ );
193
+
194
+ // NOTE: because we're creating the request by hand,
195
+ // and because the service has a rootUrl property
196
+ // the "base_uri" of the Http Client is not accounted for
197
+ $request = new Request(
198
+ $method['httpMethod'],
199
+ $url,
200
+ ['content-type' => 'application/json'],
201
+ $postBody ? json_encode($postBody) : ''
202
+ );
203
+
204
+ // support uploads
205
+ if (isset($parameters['data'])) {
206
+ $mimeType = isset($parameters['mimeType'])
207
+ ? $parameters['mimeType']['value']
208
+ : 'application/octet-stream';
209
+ $data = $parameters['data']['value'];
210
+ $upload = new Google_Http_MediaFileUpload($this->client, $request, $mimeType, $data);
211
+
212
+ // pull down the modified request
213
+ $request = $upload->getRequest();
214
+ }
215
+
216
+ // if this is a media type, we will return the raw response
217
+ // rather than using an expected class
218
+ if (isset($parameters['alt']) && $parameters['alt']['value'] == 'media') {
219
+ $expectedClass = null;
220
+ }
221
+
222
+ // if the client is marked for deferring, rather than
223
+ // execute the request, return the response
224
+ if ($this->client->shouldDefer()) {
225
+ // @TODO find a better way to do this
226
+ $request = $request
227
+ ->withHeader('X-Php-Expected-Class', $expectedClass);
228
+
229
+ return $request;
230
+ }
231
+
232
+ return $this->client->execute($request, $expectedClass);
233
+ }
234
+
235
+ protected function convertToArrayAndStripNulls($o)
236
+ {
237
+ $o = (array) $o;
238
+ foreach ($o as $k => $v) {
239
+ if ($v === null) {
240
+ unset($o[$k]);
241
+ } elseif (is_object($v) || is_array($v)) {
242
+ $o[$k] = $this->convertToArrayAndStripNulls($o[$k]);
243
+ }
244
+ }
245
+ return $o;
246
+ }
247
+
248
+ /**
249
+ * Parse/expand request parameters and create a fully qualified
250
+ * request uri.
251
+ * @static
252
+ * @param string $restPath
253
+ * @param array $params
254
+ * @return string $requestUrl
255
+ */
256
+ public function createRequestUri($restPath, $params)
257
+ {
258
+ // Override the default servicePath address if the $restPath use a /
259
+ if ('/' == substr($restPath, 0, 1)) {
260
+ $requestUrl = substr($restPath, 1);
261
+ } else {
262
+ $requestUrl = $this->servicePath . $restPath;
263
+ }
264
+
265
+ // code for leading slash
266
+ if ($this->rootUrl) {
267
+ if ('/' !== substr($this->rootUrl, -1) && '/' !== substr($requestUrl, 0, 1)) {
268
+ $requestUrl = '/' . $requestUrl;
269
+ }
270
+ $requestUrl = $this->rootUrl . $requestUrl;
271
+ }
272
+ $uriTemplateVars = array();
273
+ $queryVars = array();
274
+ foreach ($params as $paramName => $paramSpec) {
275
+ if ($paramSpec['type'] == 'boolean') {
276
+ $paramSpec['value'] = $paramSpec['value'] ? 'true' : 'false';
277
+ }
278
+ if ($paramSpec['location'] == 'path') {
279
+ $uriTemplateVars[$paramName] = $paramSpec['value'];
280
+ } else if ($paramSpec['location'] == 'query') {
281
+ if (is_array($paramSpec['value'])) {
282
+ foreach ($paramSpec['value'] as $value) {
283
+ $queryVars[] = $paramName . '=' . rawurlencode(rawurldecode($value));
284
+ }
285
+ } else {
286
+ $queryVars[] = $paramName . '=' . rawurlencode(rawurldecode($paramSpec['value']));
287
+ }
288
+ }
289
+ }
290
+
291
+ if (count($uriTemplateVars)) {
292
+ $uriTemplateParser = new Google_Utils_UriTemplate();
293
+ $requestUrl = $uriTemplateParser->parse($requestUrl, $uriTemplateVars);
294
+ }
295
+
296
+ if (count($queryVars)) {
297
+ $requestUrl .= '?' . implode($queryVars, '&');
298
+ }
299
+
300
+ return $requestUrl;
301
+ }
302
+ }
includes/lib/google-api-php-client/src/Google/Task/Exception.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * Copyright 2014 Google Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ class Google_Task_Exception extends Google_Exception
19
+ {
20
+ }
includes/lib/google-api-php-client/src/Google/Task/Retryable.php ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * Copyright 2014 Google Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ /**
19
+ * Interface for checking how many times a given task can be retried following
20
+ * a failure.
21
+ */
22
+ interface Google_Task_Retryable
23
+ {
24
+ }
includes/lib/google-api-php-client/src/Google/Task/Runner.php ADDED
@@ -0,0 +1,281 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * Copyright 2014 Google Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ /**
19
+ * A task runner with exponential backoff support.
20
+ *
21
+ * @see https://developers.google.com/drive/web/handle-errors#implementing_exponential_backoff
22
+ */
23
+ class Google_Task_Runner
24
+ {
25
+ const TASK_RETRY_NEVER = 0;
26
+ const TASK_RETRY_ONCE = 1;
27
+ const TASK_RETRY_ALWAYS = -1;
28
+
29
+ /**
30
+ * @var integer $maxDelay The max time (in seconds) to wait before a retry.
31
+ */
32
+ private $maxDelay = 60;
33
+ /**
34
+ * @var integer $delay The previous delay from which the next is calculated.
35
+ */
36
+ private $delay = 1;
37
+
38
+ /**
39
+ * @var integer $factor The base number for the exponential back off.
40
+ */
41
+ private $factor = 2;
42
+ /**
43
+ * @var float $jitter A random number between -$jitter and $jitter will be
44
+ * added to $factor on each iteration to allow for a better distribution of
45
+ * retries.
46
+ */
47
+ private $jitter = 0.5;
48
+
49
+ /**
50
+ * @var integer $attempts The number of attempts that have been tried so far.
51
+ */
52
+ private $attempts = 0;
53
+ /**
54
+ * @var integer $maxAttempts The max number of attempts allowed.
55
+ */
56
+ private $maxAttempts = 1;
57
+
58
+ /**
59
+ * @var callable $action The task to run and possibly retry.
60
+ */
61
+ private $action;
62
+ /**
63
+ * @var array $arguments The task arguments.
64
+ */
65
+ private $arguments;
66
+
67
+ /**
68
+ * @var array $retryMap Map of errors with retry counts.
69
+ */
70
+ protected $retryMap = [
71
+ '500' => self::TASK_RETRY_ALWAYS,
72
+ '503' => self::TASK_RETRY_ALWAYS,
73
+ 'rateLimitExceeded' => self::TASK_RETRY_ALWAYS,
74
+ 'userRateLimitExceeded' => self::TASK_RETRY_ALWAYS,
75
+ 6 => self::TASK_RETRY_ALWAYS, // CURLE_COULDNT_RESOLVE_HOST
76
+ 7 => self::TASK_RETRY_ALWAYS, // CURLE_COULDNT_CONNECT
77
+ 28 => self::TASK_RETRY_ALWAYS, // CURLE_OPERATION_TIMEOUTED
78
+ 35 => self::TASK_RETRY_ALWAYS, // CURLE_SSL_CONNECT_ERROR
79
+ 52 => self::TASK_RETRY_ALWAYS // CURLE_GOT_NOTHING
80
+ ];
81
+
82
+ /**
83
+ * Creates a new task runner with exponential backoff support.
84
+ *
85
+ * @param array $config The task runner config
86
+ * @param string $name The name of the current task (used for logging)
87
+ * @param callable $action The task to run and possibly retry
88
+ * @param array $arguments The task arguments
89
+ * @throws Google_Task_Exception when misconfigured
90
+ */
91
+ public function __construct(
92
+ $config,
93
+ $name,
94
+ $action,
95
+ array $arguments = array()
96
+ ) {
97
+ if (isset($config['initial_delay'])) {
98
+ if ($config['initial_delay'] < 0) {
99
+ throw new Google_Task_Exception(
100
+ 'Task configuration `initial_delay` must not be negative.'
101
+ );
102
+ }
103
+
104
+ $this->delay = $config['initial_delay'];
105
+ }
106
+
107
+ if (isset($config['max_delay'])) {
108
+ if ($config['max_delay'] <= 0) {
109
+ throw new Google_Task_Exception(
110
+ 'Task configuration `max_delay` must be greater than 0.'
111
+ );
112
+ }
113
+
114
+ $this->maxDelay = $config['max_delay'];
115
+ }
116
+
117
+ if (isset($config['factor'])) {
118
+ if ($config['factor'] <= 0) {
119
+ throw new Google_Task_Exception(
120
+ 'Task configuration `factor` must be greater than 0.'
121
+ );
122
+ }
123
+
124
+ $this->factor = $config['factor'];
125
+ }
126
+
127
+ if (isset($config['jitter'])) {
128
+ if ($config['jitter'] <= 0) {
129
+ throw new Google_Task_Exception(
130
+ 'Task configuration `jitter` must be greater than 0.'
131
+ );
132
+ }
133
+
134
+ $this->jitter = $config['jitter'];
135
+ }
136
+
137
+ if (isset($config['retries'])) {
138
+ if ($config['retries'] < 0) {
139
+ throw new Google_Task_Exception(
140
+ 'Task configuration `retries` must not be negative.'
141
+ );
142
+ }
143
+ $this->maxAttempts += $config['retries'];
144
+ }
145
+
146
+ if (!is_callable($action)) {
147
+ throw new Google_Task_Exception(
148
+ 'Task argument `$action` must be a valid callable.'
149
+ );
150
+ }
151
+
152
+ $this->action = $action;
153
+ $this->arguments = $arguments;
154
+ }
155
+
156
+ /**
157
+ * Checks if a retry can be attempted.
158
+ *
159
+ * @return boolean
160
+ */
161
+ public function canAttempt()
162
+ {
163
+ return $this->attempts < $this->maxAttempts;
164
+ }
165
+
166
+ /**
167
+ * Runs the task and (if applicable) automatically retries when errors occur.
168
+ *
169
+ * @return mixed
170
+ * @throws Google_Task_Retryable on failure when no retries are available.
171
+ */
172
+ public function run()
173
+ {
174
+ while ($this->attempt()) {
175
+ try {
176
+ return call_user_func_array($this->action, $this->arguments);
177
+ } catch (Google_Service_Exception $exception) {
178
+ $allowedRetries = $this->allowedRetries(
179
+ $exception->getCode(),
180
+ $exception->getErrors()
181
+ );
182
+
183
+ if (!$this->canAttempt() || !$allowedRetries) {
184
+ throw $exception;
185
+ }
186
+
187
+ if ($allowedRetries > 0) {
188
+ $this->maxAttempts = min(
189
+ $this->maxAttempts,
190
+ $this->attempts + $allowedRetries
191
+ );
192
+ }
193
+ }
194
+ }
195
+ }
196
+
197
+ /**
198
+ * Runs a task once, if possible. This is useful for bypassing the `run()`
199
+ * loop.
200
+ *
201
+ * NOTE: If this is not the first attempt, this function will sleep in
202
+ * accordance to the backoff configurations before running the task.
203
+ *
204
+ * @return boolean
205
+ */
206
+ public function attempt()
207
+ {
208
+ if (!$this->canAttempt()) {
209
+ return false;
210
+ }
211
+
212
+ if ($this->attempts > 0) {
213
+ $this->backOff();
214
+ }
215
+
216
+ $this->attempts++;
217
+ return true;
218
+ }
219
+
220
+ /**
221
+ * Sleeps in accordance to the backoff configurations.
222
+ */
223
+ private function backOff()
224
+ {
225
+ $delay = $this->getDelay();
226
+
227
+ usleep($delay * 1000000);
228
+ }
229
+
230
+ /**
231
+ * Gets the delay (in seconds) for the current backoff period.
232
+ *
233
+ * @return float
234
+ */
235
+ private function getDelay()
236
+ {
237
+ $jitter = $this->getJitter();
238
+ $factor = $this->attempts > 1 ? $this->factor + $jitter : 1 + abs($jitter);
239
+
240
+ return $this->delay = min($this->maxDelay, $this->delay * $factor);
241
+ }
242
+
243
+ /**
244
+ * Gets the current jitter (random number between -$this->jitter and
245
+ * $this->jitter).
246
+ *
247
+ * @return float
248
+ */
249
+ private function getJitter()
250
+ {
251
+ return $this->jitter * 2 * mt_rand() / mt_getrandmax() - $this->jitter;
252
+ }
253
+
254
+ /**
255
+ * Gets the number of times the associated task can be retried.
256
+ *
257
+ * NOTE: -1 is returned if the task can be retried indefinitely
258
+ *
259
+ * @return integer
260
+ */
261
+ public function allowedRetries($code, $errors = array())
262
+ {
263
+ if (isset($this->retryMap[$code])) {
264
+ return $this->retryMap[$code];
265
+ }
266
+
267
+ if (
268
+ !empty($errors) &&
269
+ isset($errors[0]['reason'], $this->retryMap[$errors[0]['reason']])
270
+ ) {
271
+ return $this->retryMap[$errors[0]['reason']];
272
+ }
273
+
274
+ return 0;
275
+ }
276
+
277
+ public function setRetryMap($retryMap)
278
+ {
279
+ $this->retryMap = $retryMap;
280
+ }
281
+ }
includes/lib/google-api-php-client/src/Google/Utils/UriTemplate.php ADDED
@@ -0,0 +1,333 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * Copyright 2013 Google Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ /**
19
+ * Implementation of levels 1-3 of the URI Template spec.
20
+ * @see http://tools.ietf.org/html/rfc6570
21
+ */
22
+ class Google_Utils_UriTemplate
23
+ {
24
+ const TYPE_MAP = "1";
25
+ const TYPE_LIST = "2";
26
+ const TYPE_SCALAR = "4";
27
+
28
+ /**
29
+ * @var $operators array
30
+ * These are valid at the start of a template block to
31
+ * modify the way in which the variables inside are
32
+ * processed.
33
+ */
34
+ private $operators = array(
35
+ "+" => "reserved",
36
+ "/" => "segments",
37
+ "." => "dotprefix",
38
+ "#" => "fragment",
39
+ ";" => "semicolon",
40
+ "?" => "form",
41
+ "&" => "continuation"
42
+ );
43
+
44
+ /**
45
+ * @var reserved array
46
+ * These are the characters which should not be URL encoded in reserved
47
+ * strings.
48
+ */
49
+ private $reserved = array(
50
+ "=", ",", "!", "@", "|", ":", "/", "?", "#",
51
+ "[", "]",'$', "&", "'", "(", ")", "*", "+", ";"
52
+ );
53
+ private $reservedEncoded = array(
54
+ "%3D", "%2C", "%21", "%40", "%7C", "%3A", "%2F", "%3F",
55
+ "%23", "%5B", "%5D", "%24", "%26", "%27", "%28", "%29",
56
+ "%2A", "%2B", "%3B"
57
+ );
58
+
59
+ public function parse($string, array $parameters)
60
+ {
61
+ return $this->resolveNextSection($string, $parameters);
62
+ }
63
+
64
+ /**
65
+ * This function finds the first matching {...} block and
66
+ * executes the replacement. It then calls itself to find
67
+ * subsequent blocks, if any.
68
+ */
69
+ private function resolveNextSection($string, $parameters)
70
+ {
71
+ $start = strpos($string, "{");
72
+ if ($start === false) {
73
+ return $string;
74
+ }
75
+ $end = strpos($string, "}");
76
+ if ($end === false) {
77
+ return $string;
78
+ }
79
+ $string = $this->replace($string, $start, $end, $parameters);
80
+ return $this->resolveNextSection($string, $parameters);
81
+ }
82
+
83
+ private function replace($string, $start, $end, $parameters)
84
+ {
85
+ // We know a data block will have {} round it, so we can strip that.
86
+ $data = substr($string, $start + 1, $end - $start - 1);
87
+
88
+ // If the first character is one of the reserved operators, it effects
89
+ // the processing of the stream.
90
+ if (isset($this->operators[$data[0]])) {
91
+ $op = $this->operators[$data[0]];
92
+ $data = substr($data, 1);
93
+ $prefix = "";
94
+ $prefix_on_missing = false;
95
+
96
+ switch ($op) {
97
+ case "reserved":
98
+ // Reserved means certain characters should not be URL encoded
99
+ $data = $this->replaceVars($data, $parameters, ",", null, true);
100
+ break;
101
+ case "fragment":
102
+ // Comma separated with fragment prefix. Bare values only.
103
+ $prefix = "#";
104
+ $prefix_on_missing = true;
105
+ $data = $this->replaceVars($data, $parameters, ",", null, true);
106
+ break;
107
+ case "segments":
108
+ // Slash separated data. Bare values only.
109
+ $prefix = "/";
110
+ $data =$this->replaceVars($data, $parameters, "/");
111
+ break;
112
+ case "dotprefix":
113
+ // Dot separated data. Bare values only.
114
+ $prefix = ".";
115
+ $prefix_on_missing = true;
116
+ $data = $this->replaceVars($data, $parameters, ".");
117
+ break;
118
+ case "semicolon":
119
+ // Semicolon prefixed and separated. Uses the key name
120
+ $prefix = ";";
121
+ $data = $this->replaceVars($data, $parameters, ";", "=", false, true, false);
122
+ break;
123
+ case "form":
124
+ // Standard URL format. Uses the key name
125
+ $prefix = "?";
126
+ $data = $this->replaceVars($data, $parameters, "&", "=");
127
+ break;
128
+ case "continuation":
129
+ // Standard URL, but with leading ampersand. Uses key name.
130
+ $prefix = "&";
131
+ $data = $this->replaceVars($data, $parameters, "&", "=");
132
+ break;
133
+ }
134
+
135
+ // Add the initial prefix character if data is valid.
136
+ if ($data || ($data !== false && $prefix_on_missing)) {
137
+ $data = $prefix . $data;
138
+ }
139
+
140
+ } else {
141
+ // If no operator we replace with the defaults.
142
+ $data = $this->replaceVars($data, $parameters);
143
+ }
144
+ // This is chops out the {...} and replaces with the new section.
145
+ return substr($string, 0, $start) . $data . substr($string, $end + 1);
146
+ }
147
+
148
+ private function replaceVars(
149
+ $section,
150
+ $parameters,
151
+ $sep = ",",
152
+ $combine = null,
153
+ $reserved = false,
154
+ $tag_empty = false,
155
+ $combine_on_empty = true
156
+ ) {
157
+ if (strpos($section, ",") === false) {
158
+ // If we only have a single value, we can immediately process.
159
+ return $this->combine(
160
+ $section,
161
+ $parameters,
162
+ $sep,
163
+ $combine,
164
+ $reserved,
165
+ $tag_empty,
166
+ $combine_on_empty
167
+ );
168
+ } else {
169
+ // If we have multiple values, we need to split and loop over them.
170
+ // Each is treated individually, then glued together with the
171
+ // separator character.
172
+ $vars = explode(",", $section);
173
+ return $this->combineList(
174
+ $vars,
175
+ $sep,
176
+ $parameters,
177
+ $combine,
178
+ $reserved,
179
+ false, // Never emit empty strings in multi-param replacements
180
+ $combine_on_empty
181
+ );
182
+ }
183
+ }
184
+
185
+ public function combine(
186
+ $key,
187
+ $parameters,
188
+ $sep,
189
+ $combine,
190
+ $reserved,
191
+ $tag_empty,
192
+ $combine_on_empty
193
+ ) {
194
+ $length = false;
195
+ $explode = false;
196
+ $skip_final_combine = false;
197
+ $value = false;
198
+
199
+ // Check for length restriction.
200
+ if (strpos($key, ":") !== false) {
201
+ list($key, $length) = explode(":", $key);
202
+ }
203
+
204
+ // Check for explode parameter.
205
+ if ($key[strlen($key) - 1] == "*") {
206
+ $explode = true;
207
+ $key = substr($key, 0, -1);
208
+ $skip_final_combine = true;
209
+ }
210
+
211
+ // Define the list separator.
212
+ $list_sep = $explode ? $sep : ",";
213
+
214
+ if (isset($parameters[$key])) {
215
+ $data_type = $this->getDataType($parameters[$key]);
216
+ switch ($data_type) {
217
+ case self::TYPE_SCALAR:
218
+ $value = $this->getValue($parameters[$key], $length);
219
+ break;
220
+ case self::TYPE_LIST:
221
+ $values = array();
222
+ foreach ($parameters[$key] as $pkey => $pvalue) {
223
+ $pvalue = $this->getValue($pvalue, $length);
224
+ if ($combine && $explode) {
225
+ $values[$pkey] = $key . $combine . $pvalue;
226
+ } else {
227
+ $values[$pkey] = $pvalue;
228
+ }
229
+ }
230
+ $value = implode($list_sep, $values);
231
+ if ($value == '') {
232
+ return '';
233
+ }
234
+ break;
235
+ case self::TYPE_MAP:
236
+ $values = array();
237
+ foreach ($parameters[$key] as $pkey => $pvalue) {
238
+ $pvalue = $this->getValue($pvalue, $length);
239
+ if ($explode) {
240
+ $pkey = $this->getValue($pkey, $length);
241
+ $values[] = $pkey . "=" . $pvalue; // Explode triggers = combine.
242
+ } else {
243
+ $values[] = $pkey;
244
+ $values[] = $pvalue;
245
+ }
246
+ }
247
+ $value = implode($list_sep, $values);
248
+ if ($value == '') {
249
+ return false;
250
+ }
251
+ break;
252
+ }
253
+ } else if ($tag_empty) {
254
+ // If we are just indicating empty values with their key name, return that.
255
+ return $key;
256
+ } else {
257
+ // Otherwise we can skip this variable due to not being defined.
258
+ return false;
259
+ }
260
+
261
+ if ($reserved) {
262
+ $value = str_replace($this->reservedEncoded, $this->reserved, $value);
263
+ }
264
+
265
+ // If we do not need to include the key name, we just return the raw
266
+ // value.
267
+ if (!$combine || $skip_final_combine) {
268
+ return $value;
269
+ }
270
+
271
+ // Else we combine the key name: foo=bar, if value is not the empty string.
272
+ return $key . ($value != '' || $combine_on_empty ? $combine . $value : '');
273
+ }
274
+
275
+ /**
276
+ * Return the type of a passed in value
277
+ */
278
+ private function getDataType($data)
279
+ {
280
+ if (is_array($data)) {
281
+ reset($data);
282
+ if (key($data) !== 0) {
283
+ return self::TYPE_MAP;
284
+ }
285
+ return self::TYPE_LIST;
286
+ }
287
+ return self::TYPE_SCALAR;
288
+ }
289
+
290
+ /**
291
+ * Utility function that merges multiple combine calls
292
+ * for multi-key templates.
293
+ */
294
+ private function combineList(
295
+ $vars,
296
+ $sep,
297
+ $parameters,
298
+ $combine,
299
+ $reserved,
300
+ $tag_empty,
301
+ $combine_on_empty
302
+ ) {
303
+ $ret = array();
304
+ foreach ($vars as $var) {
305
+ $response = $this->combine(
306
+ $var,
307
+ $parameters,
308
+ $sep,
309
+ $combine,
310
+ $reserved,
311
+ $tag_empty,
312
+ $combine_on_empty
313
+ );
314
+ if ($response === false) {
315
+ continue;
316
+ }
317
+ $ret[] = $response;
318
+ }
319
+ return implode($sep, $ret);
320
+ }
321
+
322
+ /**
323
+ * Utility function to encode and trim values
324
+ */
325
+ private function getValue($value, $length)
326
+ {
327
+ if ($length) {
328
+ $value = substr($value, 0, $length);
329
+ }
330
+ $value = rawurlencode($value);
331
+ return $value;
332
+ }
333
+ }
includes/lib/google-api-php-client/src/Google/autoload.php ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * THIS FILE IS FOR BACKWARDS COMPATIBLITY ONLY
5
+ *
6
+ * If you were not already including this file in your project, please ignore it
7
+ */
8
+
9
+ $file = __DIR__ . '/../../vendor/autoload.php';
10
+
11
+ if (!file_exists($file)) {
12
+ $exception = 'This library must be installed via composer or by downloading the full package.';
13
+ $exception .= ' See the instructions at https://github.com/google/google-api-php-client#installation.';
14
+ throw new Exception($exception);
15
+ }
16
+
17
+ $error = 'google-api-php-client\'s autoloader was moved to vendor/autoload.php in 2.0.0. This ';
18
+ $error .= 'redirect will be removed in 2.1. Please adjust your code to use the new location.';
19
+ trigger_error($error, E_USER_DEPRECATED);
20
+
21
+ require_once $file;
includes/phpseclib/Crypt/AES.php DELETED
@@ -1,197 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Pure-PHP implementation of AES.
5
- *
6
- * Uses mcrypt, if available/possible, and an internal implementation, otherwise.
7
- *
8
- * PHP versions 4 and 5
9
- *
10
- * NOTE: Since AES.php is (for compatibility and phpseclib-historical reasons) virtually
11
- * just a wrapper to Rijndael.php you may consider using Rijndael.php instead of
12
- * to save one include_once().
13
- *
14
- * If {@link self::setKeyLength() setKeyLength()} isn't called, it'll be calculated from
15
- * {@link self::setKey() setKey()}. ie. if the key is 128-bits, the key length will be 128-bits. If it's 136-bits
16
- * it'll be null-padded to 192-bits and 192 bits will be the key length until {@link self::setKey() setKey()}
17
- * is called, again, at which point, it'll be recalculated.
18
- *
19
- * Since Crypt_AES extends Crypt_Rijndael, some functions are available to be called that, in the context of AES, don't
20
- * make a whole lot of sense. {@link self::setBlockLength() setBlockLength()}, for instance. Calling that function,
21
- * however possible, won't do anything (AES has a fixed block length whereas Rijndael has a variable one).
22
- *
23
- * Here's a short example of how to use this library:
24
- * <code>
25
- * <?php
26
- * include 'Crypt/AES.php';
27
- *
28
- * $aes = new Crypt_AES();
29
- *
30
- * $aes->setKey('abcdefghijklmnop');
31
- *
32
- * $size = 10 * 1024;
33
- * $plaintext = '';
34
- * for ($i = 0; $i < $size; $i++) {
35
- * $plaintext.= 'a';
36
- * }
37
- *
38
- * echo $aes->decrypt($aes->encrypt($plaintext));
39
- * ?>
40
- * </code>
41
- *
42
- * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
43
- * of this software and associated documentation files (the "Software"), to deal
44
- * in the Software without restriction, including without limitation the rights
45
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
46
- * copies of the Software, and to permit persons to whom the Software is
47
- * furnished to do so, subject to the following conditions:
48
- *
49
- * The above copyright notice and this permission notice shall be included in
50
- * all copies or substantial portions of the Software.
51
- *
52
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
53
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
54
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
55
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
56
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
57
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
58
- * THE SOFTWARE.
59
- *
60
- * @category Crypt
61
- * @package Crypt_AES
62
- * @author Jim Wigginton <terrafrost@php.net>
63
- * @copyright 2008 Jim Wigginton
64
- * @license http://www.opensource.org/licenses/mit-license.html MIT License
65
- * @link http://phpseclib.sourceforge.net
66
- */
67
-
68
- /**
69
- * Include Crypt_Rijndael
70
- */
71
- if (!class_exists('Crypt_Rijndael')) {
72
- include_once 'Rijndael.php';
73
- }
74
-
75
- /**#@+
76
- * @access public
77
- * @see self::encrypt()
78
- * @see self::decrypt()
79
- */
80
- /**
81
- * Encrypt / decrypt using the Counter mode.
82
- *
83
- * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
84
- *
85
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
86
- */
87
- define('CRYPT_AES_MODE_CTR', CRYPT_MODE_CTR);
88
- /**
89
- * Encrypt / decrypt using the Electronic Code Book mode.
90
- *
91
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
92
- */
93
- define('CRYPT_AES_MODE_ECB', CRYPT_MODE_ECB);
94
- /**
95
- * Encrypt / decrypt using the Code Book Chaining mode.
96
- *
97
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
98
- */
99
- define('CRYPT_AES_MODE_CBC', CRYPT_MODE_CBC);
100
- /**
101
- * Encrypt / decrypt using the Cipher Feedback mode.
102
- *
103
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
104
- */
105
- define('CRYPT_AES_MODE_CFB', CRYPT_MODE_CFB);
106
- /**
107
- * Encrypt / decrypt using the Cipher Feedback mode.
108
- *
109
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
110
- */
111
- define('CRYPT_AES_MODE_OFB', CRYPT_MODE_OFB);
112
- /**#@-*/
113
-
114
- /**
115
- * Pure-PHP implementation of AES.
116
- *
117
- * @package Crypt_AES
118
- * @author Jim Wigginton <terrafrost@php.net>
119
- * @access public
120
- */
121
- class Crypt_AES extends Crypt_Rijndael
122
- {
123
- /**
124
- * The namespace used by the cipher for its constants.
125
- *
126
- * @see Crypt_Base::const_namespace
127
- * @var string
128
- * @access private
129
- */
130
- var $const_namespace = 'AES';
131
-
132
- /**
133
- * Dummy function
134
- *
135
- * Since Crypt_AES extends Crypt_Rijndael, this function is, technically, available, but it doesn't do anything.
136
- *
137
- * @see Crypt_Rijndael::setBlockLength()
138
- * @access public
139
- * @param int $length
140
- */
141
- function setBlockLength($length)
142
- {
143
- return;
144
- }
145
-
146
- /**
147
- * Sets the key length
148
- *
149
- * Valid key lengths are 128, 192, and 256. If the length is less than 128, it will be rounded up to
150
- * 128. If the length is greater than 128 and invalid, it will be rounded down to the closest valid amount.
151
- *
152
- * @see Crypt_Rijndael:setKeyLength()
153
- * @access public
154
- * @param int $length
155
- */
156
- function setKeyLength($length)
157
- {
158
- switch ($length) {
159
- case 160:
160
- $length = 192;
161
- break;
162
- case 224:
163
- $length = 256;
164
- }
165
- parent::setKeyLength($length);
166
- }
167
-
168
- /**
169
- * Sets the key.
170
- *
171
- * Rijndael supports five different key lengths, AES only supports three.
172
- *
173
- * @see Crypt_Rijndael:setKey()
174
- * @see setKeyLength()
175
- * @access public
176
- * @param string $key
177
- */
178
- function setKey($key)
179
- {
180
- parent::setKey($key);
181
-
182
- if (!$this->explicit_key_length) {
183
- $length = strlen($key);
184
- switch (true) {
185
- case $length <= 16:
186
- $this->key_length = 16;
187
- break;
188
- case $length <= 24:
189
- $this->key_length = 24;
190
- break;
191
- default:
192
- $this->key_length = 32;
193
- }
194
- $this->_setEngine();
195
- }
196
- }
197
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/phpseclib/Crypt/Base.php DELETED
@@ -1,2611 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Base Class for all Crypt_* cipher classes
5
- *
6
- * PHP versions 4 and 5
7
- *
8
- * Internally for phpseclib developers:
9
- * If you plan to add a new cipher class, please note following rules:
10
- *
11
- * - The new Crypt_* cipher class should extend Crypt_Base
12
- *
13
- * - Following methods are then required to be overridden/overloaded:
14
- *
15
- * - _encryptBlock()
16
- *
17
- * - _decryptBlock()
18
- *
19
- * - _setupKey()
20
- *
21
- * - All other methods are optional to be overridden/overloaded
22
- *
23
- * - Look at the source code of the current ciphers how they extend Crypt_Base
24
- * and take one of them as a start up for the new cipher class.
25
- *
26
- * - Please read all the other comments/notes/hints here also for each class var/method
27
- *
28
- * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
29
- * of this software and associated documentation files (the "Software"), to deal
30
- * in the Software without restriction, including without limitation the rights
31
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
32
- * copies of the Software, and to permit persons to whom the Software is
33
- * furnished to do so, subject to the following conditions:
34
- *
35
- * The above copyright notice and this permission notice shall be included in
36
- * all copies or substantial portions of the Software.
37
- *
38
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
39
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
40
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
41
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
42
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
43
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
44
- * THE SOFTWARE.
45
- *
46
- * @category Crypt
47
- * @package Crypt_Base
48
- * @author Jim Wigginton <terrafrost@php.net>
49
- * @author Hans-Juergen Petrich <petrich@tronic-media.com>
50
- * @copyright 2007 Jim Wigginton
51
- * @license http://www.opensource.org/licenses/mit-license.html MIT License
52
- * @link http://phpseclib.sourceforge.net
53
- */
54
-
55
- /**#@+
56
- * @access public
57
- * @see self::encrypt()
58
- * @see self::decrypt()
59
- */
60
- /**
61
- * Encrypt / decrypt using the Counter mode.
62
- *
63
- * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
64
- *
65
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
66
- */
67
- define('CRYPT_MODE_CTR', -1);
68
- /**
69
- * Encrypt / decrypt using the Electronic Code Book mode.
70
- *
71
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
72
- */
73
- define('CRYPT_MODE_ECB', 1);
74
- /**
75
- * Encrypt / decrypt using the Code Book Chaining mode.
76
- *
77
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
78
- */
79
- define('CRYPT_MODE_CBC', 2);
80
- /**
81
- * Encrypt / decrypt using the Cipher Feedback mode.
82
- *
83
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
84
- */
85
- define('CRYPT_MODE_CFB', 3);
86
- /**
87
- * Encrypt / decrypt using the Output Feedback mode.
88
- *
89
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
90
- */
91
- define('CRYPT_MODE_OFB', 4);
92
- /**
93
- * Encrypt / decrypt using streaming mode.
94
- */
95
- define('CRYPT_MODE_STREAM', 5);
96
- /**#@-*/
97
-
98
- /**#@+
99
- * @access private
100
- * @see self::Crypt_Base()
101
- * @internal These constants are for internal use only
102
- */
103
- /**
104
- * Base value for the internal implementation $engine switch
105
- */
106
- define('CRYPT_ENGINE_INTERNAL', 1);
107
- /**
108
- * Base value for the mcrypt implementation $engine switch
109
- */
110
- define('CRYPT_ENGINE_MCRYPT', 2);
111
- /**
112
- * Base value for the OpenSSL implementation $engine switch
113
- */
114
- define('CRYPT_ENGINE_OPENSSL', 3);
115
- /**#@-*/
116
-
117
- /**
118
- * Base Class for all Crypt_* cipher classes
119
- *
120
- * @package Crypt_Base
121
- * @author Jim Wigginton <terrafrost@php.net>
122
- * @author Hans-Juergen Petrich <petrich@tronic-media.com>
123
- * @access public
124
- */
125
- class Crypt_Base
126
- {
127
- /**
128
- * The Encryption Mode
129
- *
130
- * @see self::Crypt_Base()
131
- * @var int
132
- * @access private
133
- */
134
- var $mode;
135
-
136
- /**
137
- * The Block Length of the block cipher
138
- *
139
- * @var int
140
- * @access private
141
- */
142
- var $block_size = 16;
143
-
144
- /**
145
- * The Key
146
- *
147
- * @see self::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 self::setIV()
157
- * @var string
158
- * @access private
159
- */
160
- var $iv;
161
-
162
- /**
163
- * A "sliding" Initialization Vector
164
- *
165
- * @see self::enableContinuousBuffer()
166
- * @see self::_clearBuffers()
167
- * @var string
168
- * @access private
169
- */
170
- var $encryptIV;
171
-
172
- /**
173
- * A "sliding" Initialization Vector
174
- *
175
- * @see self::enableContinuousBuffer()
176
- * @see self::_clearBuffers()
177
- * @var string
178
- * @access private
179
- */
180
- var $decryptIV;
181
-
182
- /**
183
- * Continuous Buffer status
184
- *
185
- * @see self::enableContinuousBuffer()
186
- * @var bool
187
- * @access private
188
- */
189
- var $continuousBuffer = false;
190
-
191
- /**
192
- * Encryption buffer for CTR, OFB and CFB modes
193
- *
194
- * @see self::encrypt()
195
- * @see self::_clearBuffers()
196
- * @var array
197
- * @access private
198
- */
199
- var $enbuffer;
200
-
201
- /**
202
- * Decryption buffer for CTR, OFB and CFB modes
203
- *
204
- * @see self::decrypt()
205
- * @see self::_clearBuffers()
206
- * @var array
207
- * @access private
208
- */
209
- var $debuffer;
210
-
211
- /**
212
- * mcrypt resource for encryption
213
- *
214
- * The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
215
- * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
216
- *
217
- * @see self::encrypt()
218
- * @var resource
219
- * @access private
220
- */
221
- var $enmcrypt;
222
-
223
- /**
224
- * mcrypt resource for decryption
225
- *
226
- * The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
227
- * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
228
- *
229
- * @see self::decrypt()
230
- * @var resource
231
- * @access private
232
- */
233
- var $demcrypt;
234
-
235
- /**
236
- * Does the enmcrypt resource need to be (re)initialized?
237
- *
238
- * @see Crypt_Twofish::setKey()
239
- * @see Crypt_Twofish::setIV()
240
- * @var bool
241
- * @access private
242
- */
243
- var $enchanged = true;
244
-
245
- /**
246
- * Does the demcrypt resource need to be (re)initialized?
247
- *
248
- * @see Crypt_Twofish::setKey()
249
- * @see Crypt_Twofish::setIV()
250
- * @var bool
251
- * @access private
252
- */
253
- var $dechanged = true;
254
-
255
- /**
256
- * mcrypt resource for CFB mode
257
- *
258
- * mcrypt's CFB mode, in (and only in) buffered context,
259
- * is broken, so phpseclib implements the CFB mode by it self,
260
- * even when the mcrypt php extension is available.
261
- *
262
- * In order to do the CFB-mode work (fast) phpseclib
263
- * use a separate ECB-mode mcrypt resource.
264
- *
265
- * @link http://phpseclib.sourceforge.net/cfb-demo.phps
266
- * @see self::encrypt()
267
- * @see self::decrypt()
268
- * @see self::_setupMcrypt()
269
- * @var resource
270
- * @access private
271
- */
272
- var $ecb;
273
-
274
- /**
275
- * Optimizing value while CFB-encrypting
276
- *
277
- * Only relevant if $continuousBuffer enabled
278
- * and $engine == CRYPT_ENGINE_MCRYPT
279
- *
280
- * It's faster to re-init $enmcrypt if
281
- * $buffer bytes > $cfb_init_len than
282
- * using the $ecb resource furthermore.
283
- *
284
- * This value depends of the chosen cipher
285
- * and the time it would be needed for it's
286
- * initialization [by mcrypt_generic_init()]
287
- * which, typically, depends on the complexity
288
- * on its internaly Key-expanding algorithm.
289
- *
290
- * @see self::encrypt()
291
- * @var int
292
- * @access private
293
- */
294
- var $cfb_init_len = 600;
295
-
296
- /**
297
- * Does internal cipher state need to be (re)initialized?
298
- *
299
- * @see self::setKey()
300
- * @see self::setIV()
301
- * @see self::disableContinuousBuffer()
302
- * @var bool
303
- * @access private
304
- */
305
- var $changed = true;
306
-
307
- /**
308
- * Padding status
309
- *
310
- * @see self::enablePadding()
311
- * @var bool
312
- * @access private
313
- */
314
- var $padding = true;
315
-
316
- /**
317
- * Is the mode one that is paddable?
318
- *
319
- * @see self::Crypt_Base()
320
- * @var bool
321
- * @access private
322
- */
323
- var $paddable = false;
324
-
325
- /**
326
- * Holds which crypt engine internaly should be use,
327
- * which will be determined automatically on __construct()
328
- *
329
- * Currently available $engines are:
330
- * - CRYPT_ENGINE_OPENSSL (very fast, php-extension: openssl, extension_loaded('openssl') required)
331
- * - CRYPT_ENGINE_MCRYPT (fast, php-extension: mcrypt, extension_loaded('mcrypt') required)
332
- * - CRYPT_ENGINE_INTERNAL (slower, pure php-engine, no php-extension required)
333
- *
334
- * @see self::_setEngine()
335
- * @see self::encrypt()
336
- * @see self::decrypt()
337
- * @var int
338
- * @access private
339
- */
340
- var $engine;
341
-
342
- /**
343
- * Holds the preferred crypt engine
344
- *
345
- * @see self::_setEngine()
346
- * @see self::setPreferredEngine()
347
- * @var int
348
- * @access private
349
- */
350
- var $preferredEngine;
351
-
352
- /**
353
- * The mcrypt specific name of the cipher
354
- *
355
- * Only used if $engine == CRYPT_ENGINE_MCRYPT
356
- *
357
- * @link http://www.php.net/mcrypt_module_open
358
- * @link http://www.php.net/mcrypt_list_algorithms
359
- * @see self::_setupMcrypt()
360
- * @var string
361
- * @access private
362
- */
363
- var $cipher_name_mcrypt;
364
-
365
- /**
366
- * The openssl specific name of the cipher
367
- *
368
- * Only used if $engine == CRYPT_ENGINE_OPENSSL
369
- *
370
- * @link http://www.php.net/openssl-get-cipher-methods
371
- * @var string
372
- * @access private
373
- */
374
- var $cipher_name_openssl;
375
-
376
- /**
377
- * The openssl specific name of the cipher in ECB mode
378
- *
379
- * If OpenSSL does not support the mode we're trying to use (CTR)
380
- * it can still be emulated with ECB mode.
381
- *
382
- * @link http://www.php.net/openssl-get-cipher-methods
383
- * @var string
384
- * @access private
385
- */
386
- var $cipher_name_openssl_ecb;
387
-
388
- /**
389
- * The default salt used by setPassword()
390
- *
391
- * @see self::setPassword()
392
- * @var string
393
- * @access private
394
- */
395
- var $password_default_salt = 'phpseclib/salt';
396
-
397
- /**
398
- * The namespace used by the cipher for its constants.
399
- *
400
- * ie: AES.php is using CRYPT_AES_MODE_* for its constants
401
- * so $const_namespace is AES
402
- *
403
- * DES.php is using CRYPT_DES_MODE_* for its constants
404
- * so $const_namespace is DES... and so on
405
- *
406
- * All CRYPT_<$const_namespace>_MODE_* are aliases of
407
- * the generic CRYPT_MODE_* constants, so both could be used
408
- * for each cipher.
409
- *
410
- * Example:
411
- * $aes = new Crypt_AES(CRYPT_AES_MODE_CFB); // $aes will operate in cfb mode
412
- * $aes = new Crypt_AES(CRYPT_MODE_CFB); // identical
413
- *
414
- * @see self::Crypt_Base()
415
- * @var string
416
- * @access private
417
- */
418
- var $const_namespace;
419
-
420
- /**
421
- * The name of the performance-optimized callback function
422
- *
423
- * Used by encrypt() / decrypt()
424
- * only if $engine == CRYPT_ENGINE_INTERNAL
425
- *
426
- * @see self::encrypt()
427
- * @see self::decrypt()
428
- * @see self::_setupInlineCrypt()
429
- * @see self::$use_inline_crypt
430
- * @var Callback
431
- * @access private
432
- */
433
- var $inline_crypt;
434
-
435
- /**
436
- * Holds whether performance-optimized $inline_crypt() can/should be used.
437
- *
438
- * @see self::encrypt()
439
- * @see self::decrypt()
440
- * @see self::inline_crypt
441
- * @var mixed
442
- * @access private
443
- */
444
- var $use_inline_crypt;
445
-
446
- /**
447
- * If OpenSSL can be used in ECB but not in CTR we can emulate CTR
448
- *
449
- * @see self::_openssl_ctr_process()
450
- * @var bool
451
- * @access private
452
- */
453
- var $openssl_emulate_ctr = false;
454
-
455
- /**
456
- * Determines what options are passed to openssl_encrypt/decrypt
457
- *
458
- * @see self::isValidEngine()
459
- * @var mixed
460
- * @access private
461
- */
462
- var $openssl_options;
463
-
464
- /**
465
- * Has the key length explicitly been set or should it be derived from the key, itself?
466
- *
467
- * @see self::setKeyLength()
468
- * @var bool
469
- * @access private
470
- */
471
- var $explicit_key_length = false;
472
-
473
- /**
474
- * Don't truncate / null pad key
475
- *
476
- * @see self::_clearBuffers()
477
- * @var bool
478
- * @access private
479
- */
480
- var $skip_key_adjustment = false;
481
-
482
- /**
483
- * Default Constructor.
484
- *
485
- * Determines whether or not the mcrypt extension should be used.
486
- *
487
- * $mode could be:
488
- *
489
- * - CRYPT_MODE_ECB
490
- *
491
- * - CRYPT_MODE_CBC
492
- *
493
- * - CRYPT_MODE_CTR
494
- *
495
- * - CRYPT_MODE_CFB
496
- *
497
- * - CRYPT_MODE_OFB
498
- *
499
- * (or the alias constants of the chosen cipher, for example for AES: CRYPT_AES_MODE_ECB or CRYPT_AES_MODE_CBC ...)
500
- *
501
- * If not explicitly set, CRYPT_MODE_CBC will be used.
502
- *
503
- * @param int $mode
504
- * @access public
505
- */
506
- function __construct($mode = CRYPT_MODE_CBC)
507
- {
508
- // $mode dependent settings
509
- switch ($mode) {
510
- case CRYPT_MODE_ECB:
511
- $this->paddable = true;
512
- $this->mode = CRYPT_MODE_ECB;
513
- break;
514
- case CRYPT_MODE_CTR:
515
- case CRYPT_MODE_CFB:
516
- case CRYPT_MODE_OFB:
517
- case CRYPT_MODE_STREAM:
518
- $this->mode = $mode;
519
- break;
520
- case CRYPT_MODE_CBC:
521
- default:
522
- $this->paddable = true;
523
- $this->mode = CRYPT_MODE_CBC;
524
- }
525
-
526
- $this->_setEngine();
527
-
528
- // Determining whether inline crypting can be used by the cipher
529
- if ($this->use_inline_crypt !== false && function_exists('create_function')) {
530
- $this->use_inline_crypt = true;
531
- }
532
- }
533
-
534
- /**
535
- * PHP4 compatible Default Constructor.
536
- *
537
- * @see self::__construct()
538
- * @param int $mode
539
- * @access public
540
- */
541
- function Crypt_Base($mode = CRYPT_MODE_CBC)
542
- {
543
- $this->__construct($mode);
544
- }
545
-
546
- /**
547
- * Sets the initialization vector. (optional)
548
- *
549
- * SetIV is not required when CRYPT_MODE_ECB (or ie for AES: CRYPT_AES_MODE_ECB) is being used. If not explicitly set, it'll be assumed
550
- * to be all zero's.
551
- *
552
- * @access public
553
- * @param string $iv
554
- * @internal Can be overwritten by a sub class, but does not have to be
555
- */
556
- function setIV($iv)
557
- {
558
- if ($this->mode == CRYPT_MODE_ECB) {
559
- return;
560
- }
561
-
562
- $this->iv = $iv;
563
- $this->changed = true;
564
- }
565
-
566
- /**
567
- * Sets the key length.
568
- *
569
- * Keys with explicitly set lengths need to be treated accordingly
570
- *
571
- * @access public
572
- * @param int $length
573
- */
574
- function setKeyLength($length)
575
- {
576
- $this->explicit_key_length = true;
577
- $this->changed = true;
578
- $this->_setEngine();
579
- }
580
-
581
- /**
582
- * Returns the current key length in bits
583
- *
584
- * @access public
585
- * @return int
586
- */
587
- function getKeyLength()
588
- {
589
- return $this->key_length << 3;
590
- }
591
-
592
- /**
593
- * Returns the current block length in bits
594
- *
595
- * @access public
596
- * @return int
597
- */
598
- function getBlockLength()
599
- {
600
- return $this->block_size << 3;
601
- }
602
-
603
- /**
604
- * Sets the key.
605
- *
606
- * The min/max length(s) of the key depends on the cipher which is used.
607
- * If the key not fits the length(s) of the cipher it will paded with null bytes
608
- * up to the closest valid key length. If the key is more than max length,
609
- * we trim the excess bits.
610
- *
611
- * If the key is not explicitly set, it'll be assumed to be all null bytes.
612
- *
613
- * @access public
614
- * @param string $key
615
- * @internal Could, but not must, extend by the child Crypt_* class
616
- */
617
- function setKey($key)
618
- {
619
- if (!$this->explicit_key_length) {
620
- $this->setKeyLength(strlen($key) << 3);
621
- $this->explicit_key_length = false;
622
- }
623
-
624
- $this->key = $key;
625
- $this->changed = true;
626
- $this->_setEngine();
627
- }
628
-
629
- /**
630
- * Sets the password.
631
- *
632
- * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows:
633
- * {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2} or pbkdf1:
634
- * $hash, $salt, $count, $dkLen
635
- *
636
- * Where $hash (default = sha1) currently supports the following hashes: see: Crypt/Hash.php
637
- *
638
- * @see Crypt/Hash.php
639
- * @param string $password
640
- * @param string $method
641
- * @return bool
642
- * @access public
643
- * @internal Could, but not must, extend by the child Crypt_* class
644
- */
645
- function setPassword($password, $method = 'pbkdf2')
646
- {
647
- $key = '';
648
-
649
- switch ($method) {
650
- default: // 'pbkdf2' or 'pbkdf1'
651
- $func_args = func_get_args();
652
-
653
- // Hash function
654
- $hash = isset($func_args[2]) ? $func_args[2] : 'sha1';
655
-
656
- // WPA and WPA2 use the SSID as the salt
657
- $salt = isset($func_args[3]) ? $func_args[3] : $this->password_default_salt;
658
-
659
- // RFC2898#section-4.2 uses 1,000 iterations by default
660
- // WPA and WPA2 use 4,096.
661
- $count = isset($func_args[4]) ? $func_args[4] : 1000;
662
-
663
- // Keylength
664
- if (isset($func_args[5])) {
665
- $dkLen = $func_args[5];
666
- } else {
667
- $dkLen = $method == 'pbkdf1' ? 2 * $this->key_length : $this->key_length;
668
- }
669
-
670
- switch (true) {
671
- case $method == 'pbkdf1':
672
- if (!class_exists('Crypt_Hash')) {
673
- include_once 'Crypt/Hash.php';
674
- }
675
- $hashObj = new Crypt_Hash();
676
- $hashObj->setHash($hash);
677
- if ($dkLen > $hashObj->getLength()) {
678
- user_error('Derived key too long');
679
- return false;
680
- }
681
- $t = $password . $salt;
682
- for ($i = 0; $i < $count; ++$i) {
683
- $t = $hashObj->hash($t);
684
- }
685
- $key = substr($t, 0, $dkLen);
686
-
687
- $this->setKey(substr($key, 0, $dkLen >> 1));
688
- $this->setIV(substr($key, $dkLen >> 1));
689
-
690
- return true;
691
- // Determining if php[>=5.5.0]'s hash_pbkdf2() function avail- and useable
692
- case !function_exists('hash_pbkdf2'):
693
- case !function_exists('hash_algos'):
694
- case !in_array($hash, hash_algos()):
695
- if (!class_exists('Crypt_Hash')) {
696
- include_once 'Crypt/Hash.php';
697
- }
698
- $i = 1;
699
- while (strlen($key) < $dkLen) {
700
- $hmac = new Crypt_Hash();
701
- $hmac->setHash($hash);
702
- $hmac->setKey($password);
703
- $f = $u = $hmac->hash($salt . pack('N', $i++));
704
- for ($j = 2; $j <= $count; ++$j) {
705
- $u = $hmac->hash($u);
706
- $f^= $u;
707
- }
708
- $key.= $f;
709
- }
710
- $key = substr($key, 0, $dkLen);
711
- break;
712
- default:
713
- $key = hash_pbkdf2($hash, $password, $salt, $count, $dkLen, true);
714
- }
715
- }
716
-
717
- $this->setKey($key);
718
-
719
- return true;
720
- }
721
-
722
- /**
723
- * Encrypts a message.
724
- *
725
- * $plaintext will be padded with additional bytes such that it's length is a multiple of the block size. Other cipher
726
- * implementations may or may not pad in the same manner. Other common approaches to padding and the reasons why it's
727
- * necessary are discussed in the following
728
- * URL:
729
- *
730
- * {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html}
731
- *
732
- * An alternative to padding is to, separately, send the length of the file. This is what SSH, in fact, does.
733
- * strlen($plaintext) will still need to be a multiple of the block size, however, arbitrary values can be added to make it that
734
- * length.
735
- *
736
- * @see self::decrypt()
737
- * @access public
738
- * @param string $plaintext
739
- * @return string $ciphertext
740
- * @internal Could, but not must, extend by the child Crypt_* class
741
- */
742
- function encrypt($plaintext)
743
- {
744
- if ($this->paddable) {
745
- $plaintext = $this->_pad($plaintext);
746
- }
747
-
748
- if ($this->engine === CRYPT_ENGINE_OPENSSL) {
749
- if ($this->changed) {
750
- $this->_clearBuffers();
751
- $this->changed = false;
752
- }
753
- switch ($this->mode) {
754
- case CRYPT_MODE_STREAM:
755
- return openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options);
756
- case CRYPT_MODE_ECB:
757
- $result = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options);
758
- return !defined('OPENSSL_RAW_DATA') ? substr($result, 0, -$this->block_size) : $result;
759
- case CRYPT_MODE_CBC:
760
- $result = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $this->encryptIV);
761
- if (!defined('OPENSSL_RAW_DATA')) {
762
- $result = substr($result, 0, -$this->block_size);
763
- }
764
- if ($this->continuousBuffer) {
765
- $this->encryptIV = substr($result, -$this->block_size);
766
- }
767
- return $result;
768
- case CRYPT_MODE_CTR:
769
- return $this->_openssl_ctr_process($plaintext, $this->encryptIV, $this->enbuffer);
770
- case CRYPT_MODE_CFB:
771
- // cfb loosely routines inspired by openssl's:
772
- // {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1}
773
- $ciphertext = '';
774
- if ($this->continuousBuffer) {
775
- $iv = &$this->encryptIV;
776
- $pos = &$this->enbuffer['pos'];
777
- } else {
778
- $iv = $this->encryptIV;
779
- $pos = 0;
780
- }
781
- $len = strlen($plaintext);
782
- $i = 0;
783
- if ($pos) {
784
- $orig_pos = $pos;
785
- $max = $this->block_size - $pos;
786
- if ($len >= $max) {
787
- $i = $max;
788
- $len-= $max;
789
- $pos = 0;
790
- } else {
791
- $i = $len;
792
- $pos+= $len;
793
- $len = 0;
794
- }
795
- // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
796
- $ciphertext = substr($iv, $orig_pos) ^ $plaintext;
797
- $iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
798
- $plaintext = substr($plaintext, $i);
799
- }
800
-
801
- $overflow = $len % $this->block_size;
802
-
803
- if ($overflow) {
804
- $ciphertext.= openssl_encrypt(substr($plaintext, 0, -$overflow) . str_repeat("\0", $this->block_size), $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv);
805
- $iv = $this->_string_pop($ciphertext, $this->block_size);
806
-
807
- $size = $len - $overflow;
808
- $block = $iv ^ substr($plaintext, -$overflow);
809
- $iv = substr_replace($iv, $block, 0, $overflow);
810
- $ciphertext.= $block;
811
- $pos = $overflow;
812
- } elseif ($len) {
813
- $ciphertext = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv);
814
- $iv = substr($ciphertext, -$this->block_size);
815
- }
816
-
817
- return $ciphertext;
818
- case CRYPT_MODE_OFB:
819
- return $this->_openssl_ofb_process($plaintext, $this->encryptIV, $this->enbuffer);
820
- }
821
- }
822
-
823
- if ($this->engine === CRYPT_ENGINE_MCRYPT) {
824
- if ($this->changed) {
825
- $this->_setupMcrypt();
826
- $this->changed = false;
827
- }
828
- if ($this->enchanged) {
829
- @mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
830
- $this->enchanged = false;
831
- }
832
-
833
- // re: {@link http://phpseclib.sourceforge.net/cfb-demo.phps}
834
- // using mcrypt's default handing of CFB the above would output two different things. using phpseclib's
835
- // rewritten CFB implementation the above outputs the same thing twice.
836
- if ($this->mode == CRYPT_MODE_CFB && $this->continuousBuffer) {
837
- $block_size = $this->block_size;
838
- $iv = &$this->encryptIV;
839
- $pos = &$this->enbuffer['pos'];
840
- $len = strlen($plaintext);
841
- $ciphertext = '';
842
- $i = 0;
843
- if ($pos) {
844
- $orig_pos = $pos;
845
- $max = $block_size - $pos;
846
- if ($len >= $max) {
847
- $i = $max;
848
- $len-= $max;
849
- $pos = 0;
850
- } else {
851
- $i = $len;
852
- $pos+= $len;
853
- $len = 0;
854
- }
855
- $ciphertext = substr($iv, $orig_pos) ^ $plaintext;
856
- $iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
857
- $this->enbuffer['enmcrypt_init'] = true;
858
- }
859
- if ($len >= $block_size) {
860
- if ($this->enbuffer['enmcrypt_init'] === false || $len > $this->cfb_init_len) {
861
- if ($this->enbuffer['enmcrypt_init'] === true) {
862
- @mcrypt_generic_init($this->enmcrypt, $this->key, $iv);
863
- $this->enbuffer['enmcrypt_init'] = false;
864
- }
865
- $ciphertext.= @mcrypt_generic($this->enmcrypt, substr($plaintext, $i, $len - $len % $block_size));
866
- $iv = substr($ciphertext, -$block_size);
867
- $len%= $block_size;
868
- } else {
869
- while ($len >= $block_size) {
870
- $iv = @mcrypt_generic($this->ecb, $iv) ^ substr($plaintext, $i, $block_size);
871
- $ciphertext.= $iv;
872
- $len-= $block_size;
873
- $i+= $block_size;
874
- }
875
- }
876
- }
877
-
878
- if ($len) {
879
- $iv = @mcrypt_generic($this->ecb, $iv);
880
- $block = $iv ^ substr($plaintext, -$len);
881
- $iv = substr_replace($iv, $block, 0, $len);
882
- $ciphertext.= $block;
883
- $pos = $len;
884
- }
885
-
886
- return $ciphertext;
887
- }
888
-
889
- $ciphertext = @mcrypt_generic($this->enmcrypt, $plaintext);
890
-
891
- if (!$this->continuousBuffer) {
892
- @mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
893
- }
894
-
895
- return $ciphertext;
896
- }
897
-
898
- if ($this->changed) {
899
- $this->_setup();
900
- $this->changed = false;
901
- }
902
- if ($this->use_inline_crypt) {
903
- $inline = $this->inline_crypt;
904
- return $inline('encrypt', $this, $plaintext);
905
- }
906
-
907
- $buffer = &$this->enbuffer;
908
- $block_size = $this->block_size;
909
- $ciphertext = '';
910
- switch ($this->mode) {
911
- case CRYPT_MODE_ECB:
912
- for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
913
- $ciphertext.= $this->_encryptBlock(substr($plaintext, $i, $block_size));
914
- }
915
- break;
916
- case CRYPT_MODE_CBC:
917
- $xor = $this->encryptIV;
918
- for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
919
- $block = substr($plaintext, $i, $block_size);
920
- $block = $this->_encryptBlock($block ^ $xor);
921
- $xor = $block;
922
- $ciphertext.= $block;
923
- }
924
- if ($this->continuousBuffer) {
925
- $this->encryptIV = $xor;
926
- }
927
- break;
928
- case CRYPT_MODE_CTR:
929
- $xor = $this->encryptIV;
930
- if (strlen($buffer['ciphertext'])) {
931
- for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
932
- $block = substr($plaintext, $i, $block_size);
933
- if (strlen($block) > strlen($buffer['ciphertext'])) {
934
- $buffer['ciphertext'].= $this->_encryptBlock($xor);
935
- }
936
- $this->_increment_str($xor);
937
- $key = $this->_string_shift($buffer['ciphertext'], $block_size);
938
- $ciphertext.= $block ^ $key;
939
- }
940
- } else {
941
- for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
942
- $block = substr($plaintext, $i, $block_size);
943
- $key = $this->_encryptBlock($xor);
944
- $this->_increment_str($xor);
945
- $ciphertext.= $block ^ $key;
946
- }
947
- }
948
- if ($this->continuousBuffer) {
949
- $this->encryptIV = $xor;
950
- if ($start = strlen($plaintext) % $block_size) {
951
- $buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext'];
952
- }
953
- }
954
- break;
955
- case CRYPT_MODE_CFB:
956
- // cfb loosely routines inspired by openssl's:
957
- // {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1}
958
- if ($this->continuousBuffer) {
959
- $iv = &$this->encryptIV;
960
- $pos = &$buffer['pos'];
961
- } else {
962
- $iv = $this->encryptIV;
963
- $pos = 0;
964
- }
965
- $len = strlen($plaintext);
966
- $i = 0;
967
- if ($pos) {
968
- $orig_pos = $pos;
969
- $max = $block_size - $pos;
970
- if ($len >= $max) {
971
- $i = $max;
972
- $len-= $max;
973
- $pos = 0;
974
- } else {
975
- $i = $len;
976
- $pos+= $len;
977
- $len = 0;
978
- }
979
- // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
980
- $ciphertext = substr($iv, $orig_pos) ^ $plaintext;
981
- $iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
982
- }
983
- while ($len >= $block_size) {
984
- $iv = $this->_encryptBlock($iv) ^ substr($plaintext, $i, $block_size);
985
- $ciphertext.= $iv;
986
- $len-= $block_size;
987
- $i+= $block_size;
988
- }
989
- if ($len) {
990
- $iv = $this->_encryptBlock($iv);
991
- $block = $iv ^ substr($plaintext, $i);
992
- $iv = substr_replace($iv, $block, 0, $len);
993
- $ciphertext.= $block;
994
- $pos = $len;
995
- }
996
- break;
997
- case CRYPT_MODE_OFB:
998
- $xor = $this->encryptIV;
999
- if (strlen($buffer['xor'])) {
1000
- for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
1001
- $block = substr($plaintext, $i, $block_size);
1002
- if (strlen($block) > strlen($buffer['xor'])) {
1003
- $xor = $this->_encryptBlock($xor);
1004
- $buffer['xor'].= $xor;
1005
- }
1006
- $key = $this->_string_shift($buffer['xor'], $block_size);
1007
- $ciphertext.= $block ^ $key;
1008
- }
1009
- } else {
1010
- for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
1011
- $xor = $this->_encryptBlock($xor);
1012
- $ciphertext.= substr($plaintext, $i, $block_size) ^ $xor;
1013
- }
1014
- $key = $xor;
1015
- }
1016
- if ($this->continuousBuffer) {
1017
- $this->encryptIV = $xor;
1018
- if ($start = strlen($plaintext) % $block_size) {
1019
- $buffer['xor'] = substr($key, $start) . $buffer['xor'];
1020
- }
1021
- }
1022
- break;
1023
- case CRYPT_MODE_STREAM:
1024
- $ciphertext = $this->_encryptBlock($plaintext);
1025
- break;
1026
- }
1027
-
1028
- return $ciphertext;
1029
- }
1030
-
1031
- /**
1032
- * Decrypts a message.
1033
- *
1034
- * If strlen($ciphertext) is not a multiple of the block size, null bytes will be added to the end of the string until
1035
- * it is.
1036
- *
1037
- * @see self::encrypt()
1038
- * @access public
1039
- * @param string $ciphertext
1040
- * @return string $plaintext
1041
- * @internal Could, but not must, extend by the child Crypt_* class
1042
- */
1043
- function decrypt($ciphertext)
1044
- {
1045
- if ($this->paddable) {
1046
- // we pad with chr(0) since that's what mcrypt_generic does. to quote from {@link http://www.php.net/function.mcrypt-generic}:
1047
- // "The data is padded with "\0" to make sure the length of the data is n * blocksize."
1048
- $ciphertext = str_pad($ciphertext, strlen($ciphertext) + ($this->block_size - strlen($ciphertext) % $this->block_size) % $this->block_size, chr(0));
1049
- }
1050
-
1051
- if ($this->engine === CRYPT_ENGINE_OPENSSL) {
1052
- if ($this->changed) {
1053
- $this->_clearBuffers();
1054
- $this->changed = false;
1055
- }
1056
- switch ($this->mode) {
1057
- case CRYPT_MODE_STREAM:
1058
- $plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options);
1059
- break;
1060
- case CRYPT_MODE_ECB:
1061
- if (!defined('OPENSSL_RAW_DATA')) {
1062
- $ciphertext.= openssl_encrypt('', $this->cipher_name_openssl_ecb, $this->key, true);
1063
- }
1064
- $plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options);
1065
- break;
1066
- case CRYPT_MODE_CBC:
1067
- if (!defined('OPENSSL_RAW_DATA')) {
1068
- $padding = str_repeat(chr($this->block_size), $this->block_size) ^ substr($ciphertext, -$this->block_size);
1069
- $ciphertext.= substr(openssl_encrypt($padding, $this->cipher_name_openssl_ecb, $this->key, true), 0, $this->block_size);
1070
- $offset = 2 * $this->block_size;
1071
- } else {
1072
- $offset = $this->block_size;
1073
- }
1074
- $plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $this->decryptIV);
1075
- if ($this->continuousBuffer) {
1076
- $this->decryptIV = substr($ciphertext, -$offset, $this->block_size);
1077
- }
1078
- break;
1079
- case CRYPT_MODE_CTR:
1080
- $plaintext = $this->_openssl_ctr_process($ciphertext, $this->decryptIV, $this->debuffer);
1081
- break;
1082
- case CRYPT_MODE_CFB:
1083
- // cfb loosely routines inspired by openssl's:
1084
- // {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1}
1085
- $plaintext = '';
1086
- if ($this->continuousBuffer) {
1087
- $iv = &$this->decryptIV;
1088
- $pos = &$this->buffer['pos'];
1089
- } else {
1090
- $iv = $this->decryptIV;
1091
- $pos = 0;
1092
- }
1093
- $len = strlen($ciphertext);
1094
- $i = 0;
1095
- if ($pos) {
1096
- $orig_pos = $pos;
1097
- $max = $this->block_size - $pos;
1098
- if ($len >= $max) {
1099
- $i = $max;
1100
- $len-= $max;
1101
- $pos = 0;
1102
- } else {
1103
- $i = $len;
1104
- $pos+= $len;
1105
- $len = 0;
1106
- }
1107
- // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $this->blocksize
1108
- $plaintext = substr($iv, $orig_pos) ^ $ciphertext;
1109
- $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
1110
- $ciphertext = substr($ciphertext, $i);
1111
- }
1112
- $overflow = $len % $this->block_size;
1113
- if ($overflow) {
1114
- $plaintext.= openssl_decrypt(substr($ciphertext, 0, -$overflow), $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv);
1115
- if ($len - $overflow) {
1116
- $iv = substr($ciphertext, -$overflow - $this->block_size, -$overflow);
1117
- }
1118
- $iv = openssl_encrypt(str_repeat("\0", $this->block_size), $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv);
1119
- $plaintext.= $iv ^ substr($ciphertext, -$overflow);
1120
- $iv = substr_replace($iv, substr($ciphertext, -$overflow), 0, $overflow);
1121
- $pos = $overflow;
1122
- } elseif ($len) {
1123
- $plaintext.= openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv);
1124
- $iv = substr($ciphertext, -$this->block_size);
1125
- }
1126
- break;
1127
- case CRYPT_MODE_OFB:
1128
- $plaintext = $this->_openssl_ofb_process($ciphertext, $this->decryptIV, $this->debuffer);
1129
- }
1130
-
1131
- return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
1132
- }
1133
-
1134
- if ($this->engine === CRYPT_ENGINE_MCRYPT) {
1135
- $block_size = $this->block_size;
1136
- if ($this->changed) {
1137
- $this->_setupMcrypt();
1138
- $this->changed = false;
1139
- }
1140
- if ($this->dechanged) {
1141
- @mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
1142
- $this->dechanged = false;
1143
- }
1144
-
1145
- if ($this->mode == CRYPT_MODE_CFB && $this->continuousBuffer) {
1146
- $iv = &$this->decryptIV;
1147
- $pos = &$this->debuffer['pos'];
1148
- $len = strlen($ciphertext);
1149
- $plaintext = '';
1150
- $i = 0;
1151
- if ($pos) {
1152
- $orig_pos = $pos;
1153
- $max = $block_size - $pos;
1154
- if ($len >= $max) {
1155
- $i = $max;
1156
- $len-= $max;
1157
- $pos = 0;
1158
- } else {
1159
- $i = $len;
1160
- $pos+= $len;
1161
- $len = 0;
1162
- }
1163
- // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
1164
- $plaintext = substr($iv, $orig_pos) ^ $ciphertext;
1165
- $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
1166
- }
1167
- if ($len >= $block_size) {
1168
- $cb = substr($ciphertext, $i, $len - $len % $block_size);
1169
- $plaintext.= @mcrypt_generic($this->ecb, $iv . $cb) ^ $cb;
1170
- $iv = substr($cb, -$block_size);
1171
- $len%= $block_size;
1172
- }
1173
- if ($len) {
1174
- $iv = @mcrypt_generic($this->ecb, $iv);
1175
- $plaintext.= $iv ^ substr($ciphertext, -$len);
1176
- $iv = substr_replace($iv, substr($ciphertext, -$len), 0, $len);
1177
- $pos = $len;
1178
- }
1179
-
1180
- return $plaintext;
1181
- }
1182
-
1183
- $plaintext = @mdecrypt_generic($this->demcrypt, $ciphertext);
1184
-
1185
- if (!$this->continuousBuffer) {
1186
- @mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
1187
- }
1188
-
1189
- return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
1190
- }
1191
-
1192
- if ($this->changed) {
1193
- $this->_setup();
1194
- $this->changed = false;
1195
- }
1196
- if ($this->use_inline_crypt) {
1197
- $inline = $this->inline_crypt;
1198
- return $inline('decrypt', $this, $ciphertext);
1199
- }
1200
-
1201
- $block_size = $this->block_size;
1202
-
1203
- $buffer = &$this->debuffer;
1204
- $plaintext = '';
1205
- switch ($this->mode) {
1206
- case CRYPT_MODE_ECB:
1207
- for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
1208
- $plaintext.= $this->_decryptBlock(substr($ciphertext, $i, $block_size));
1209
- }
1210
- break;
1211
- case CRYPT_MODE_CBC:
1212
- $xor = $this->decryptIV;
1213
- for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
1214
- $block = substr($ciphertext, $i, $block_size);
1215
- $plaintext.= $this->_decryptBlock($block) ^ $xor;
1216
- $xor = $block;
1217
- }
1218
- if ($this->continuousBuffer) {
1219
- $this->decryptIV = $xor;
1220
- }
1221
- break;
1222
- case CRYPT_MODE_CTR:
1223
- $xor = $this->decryptIV;
1224
- if (strlen($buffer['ciphertext'])) {
1225
- for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
1226
- $block = substr($ciphertext, $i, $block_size);
1227
- if (strlen($block) > strlen($buffer['ciphertext'])) {
1228
- $buffer['ciphertext'].= $this->_encryptBlock($xor);
1229
- $this->_increment_str($xor);
1230
- }
1231
- $key = $this->_string_shift($buffer['ciphertext'], $block_size);
1232
- $plaintext.= $block ^ $key;
1233
- }
1234
- } else {
1235
- for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
1236
- $block = substr($ciphertext, $i, $block_size);
1237
- $key = $this->_encryptBlock($xor);
1238
- $this->_increment_str($xor);
1239
- $plaintext.= $block ^ $key;
1240
- }
1241
- }
1242
- if ($this->continuousBuffer) {
1243
- $this->decryptIV = $xor;
1244
- if ($start = strlen($ciphertext) % $block_size) {
1245
- $buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext'];
1246
- }
1247
- }
1248
- break;
1249
- case CRYPT_MODE_CFB:
1250
- if ($this->continuousBuffer) {
1251
- $iv = &$this->decryptIV;
1252
- $pos = &$buffer['pos'];
1253
- } else {
1254
- $iv = $this->decryptIV;
1255
- $pos = 0;
1256
- }
1257
- $len = strlen($ciphertext);
1258
- $i = 0;
1259
- if ($pos) {
1260
- $orig_pos = $pos;
1261
- $max = $block_size - $pos;
1262
- if ($len >= $max) {
1263
- $i = $max;
1264
- $len-= $max;
1265
- $pos = 0;
1266
- } else {
1267
- $i = $len;
1268
- $pos+= $len;
1269
- $len = 0;
1270
- }
1271
- // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
1272
- $plaintext = substr($iv, $orig_pos) ^ $ciphertext;
1273
- $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
1274
- }
1275
- while ($len >= $block_size) {
1276
- $iv = $this->_encryptBlock($iv);
1277
- $cb = substr($ciphertext, $i, $block_size);
1278
- $plaintext.= $iv ^ $cb;
1279
- $iv = $cb;
1280
- $len-= $block_size;
1281
- $i+= $block_size;
1282
- }
1283
- if ($len) {
1284
- $iv = $this->_encryptBlock($iv);
1285
- $plaintext.= $iv ^ substr($ciphertext, $i);
1286
- $iv = substr_replace($iv, substr($ciphertext, $i), 0, $len);
1287
- $pos = $len;
1288
- }
1289
- break;
1290
- case CRYPT_MODE_OFB:
1291
- $xor = $this->decryptIV;
1292
- if (strlen($buffer['xor'])) {
1293
- for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
1294
- $block = substr($ciphertext, $i, $block_size);
1295
- if (strlen($block) > strlen($buffer['xor'])) {
1296
- $xor = $this->_encryptBlock($xor);
1297
- $buffer['xor'].= $xor;
1298
- }
1299
- $key = $this->_string_shift($buffer['xor'], $block_size);
1300
- $plaintext.= $block ^ $key;
1301
- }
1302
- } else {
1303
- for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
1304
- $xor = $this->_encryptBlock($xor);
1305
- $plaintext.= substr($ciphertext, $i, $block_size) ^ $xor;
1306
- }
1307
- $key = $xor;
1308
- }
1309
- if ($this->continuousBuffer) {
1310
- $this->decryptIV = $xor;
1311
- if ($start = strlen($ciphertext) % $block_size) {
1312
- $buffer['xor'] = substr($key, $start) . $buffer['xor'];
1313
- }
1314
- }
1315
- break;
1316
- case CRYPT_MODE_STREAM:
1317
- $plaintext = $this->_decryptBlock($ciphertext);
1318
- break;
1319
- }
1320
- return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
1321
- }
1322
-
1323
- /**
1324
- * OpenSSL CTR Processor
1325
- *
1326
- * PHP's OpenSSL bindings do not operate in continuous mode so we'll wrap around it. Since the keystream
1327
- * for CTR is the same for both encrypting and decrypting this function is re-used by both Crypt_Base::encrypt()
1328
- * and Crypt_Base::decrypt(). Also, OpenSSL doesn't implement CTR for all of it's symmetric ciphers so this
1329
- * function will emulate CTR with ECB when necessary.
1330
- *
1331
- * @see self::encrypt()
1332
- * @see self::decrypt()
1333
- * @param string $plaintext
1334
- * @param string $encryptIV
1335
- * @param array $buffer
1336
- * @return string
1337
- * @access private
1338
- */
1339
- function _openssl_ctr_process($plaintext, &$encryptIV, &$buffer)
1340
- {
1341
- $ciphertext = '';
1342
-
1343
- $block_size = $this->block_size;
1344
- $key = $this->key;
1345
-
1346
- if ($this->openssl_emulate_ctr) {
1347
- $xor = $encryptIV;
1348
- if (strlen($buffer['ciphertext'])) {
1349
- for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
1350
- $block = substr($plaintext, $i, $block_size);
1351
- if (strlen($block) > strlen($buffer['ciphertext'])) {
1352
- $result = openssl_encrypt($xor, $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
1353
- $result = !defined('OPENSSL_RAW_DATA') ? substr($result, 0, -$this->block_size) : $result;
1354
- $buffer['ciphertext'].= $result;
1355
- }
1356
- $this->_increment_str($xor);
1357
- $otp = $this->_string_shift($buffer['ciphertext'], $block_size);
1358
- $ciphertext.= $block ^ $otp;
1359
- }
1360
- } else {
1361
- for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
1362
- $block = substr($plaintext, $i, $block_size);
1363
- $otp = openssl_encrypt($xor, $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
1364
- $otp = !defined('OPENSSL_RAW_DATA') ? substr($otp, 0, -$this->block_size) : $otp;
1365
- $this->_increment_str($xor);
1366
- $ciphertext.= $block ^ $otp;
1367
- }
1368
- }
1369
- if ($this->continuousBuffer) {
1370
- $encryptIV = $xor;
1371
- if ($start = strlen($plaintext) % $block_size) {
1372
- $buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext'];
1373
- }
1374
- }
1375
-
1376
- return $ciphertext;
1377
- }
1378
-
1379
- if (strlen($buffer['ciphertext'])) {
1380
- $ciphertext = $plaintext ^ $this->_string_shift($buffer['ciphertext'], strlen($plaintext));
1381
- $plaintext = substr($plaintext, strlen($ciphertext));
1382
-
1383
- if (!strlen($plaintext)) {
1384
- return $ciphertext;
1385
- }
1386
- }
1387
-
1388
- $overflow = strlen($plaintext) % $block_size;
1389
- if ($overflow) {
1390
- $plaintext2 = $this->_string_pop($plaintext, $overflow); // ie. trim $plaintext to a multiple of $block_size and put rest of $plaintext in $plaintext2
1391
- $encrypted = openssl_encrypt($plaintext . str_repeat("\0", $block_size), $this->cipher_name_openssl, $key, $this->openssl_options, $encryptIV);
1392
- $temp = $this->_string_pop($encrypted, $block_size);
1393
- $ciphertext.= $encrypted . ($plaintext2 ^ $temp);
1394
- if ($this->continuousBuffer) {
1395
- $buffer['ciphertext'] = substr($temp, $overflow);
1396
- $encryptIV = $temp;
1397
- }
1398
- } elseif (!strlen($buffer['ciphertext'])) {
1399
- $ciphertext.= openssl_encrypt($plaintext . str_repeat("\0", $block_size), $this->cipher_name_openssl, $key, $this->openssl_options, $encryptIV);
1400
- $temp = $this->_string_pop($ciphertext, $block_size);
1401
- if ($this->continuousBuffer) {
1402
- $encryptIV = $temp;
1403
- }
1404
- }
1405
- if ($this->continuousBuffer) {
1406
- if (!defined('OPENSSL_RAW_DATA')) {
1407
- $encryptIV.= openssl_encrypt('', $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
1408
- }
1409
- $encryptIV = openssl_decrypt($encryptIV, $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
1410
- if ($overflow) {
1411
- $this->_increment_str($encryptIV);
1412
- }
1413
- }
1414
-
1415
- return $ciphertext;
1416
- }
1417
-
1418
- /**
1419
- * OpenSSL OFB Processor
1420
- *
1421
- * PHP's OpenSSL bindings do not operate in continuous mode so we'll wrap around it. Since the keystream
1422
- * for OFB is the same for both encrypting and decrypting this function is re-used by both Crypt_Base::encrypt()
1423
- * and Crypt_Base::decrypt().
1424
- *
1425
- * @see self::encrypt()
1426
- * @see self::decrypt()
1427
- * @param string $plaintext
1428
- * @param string $encryptIV
1429
- * @param array $buffer
1430
- * @return string
1431
- * @access private
1432
- */
1433
- function _openssl_ofb_process($plaintext, &$encryptIV, &$buffer)
1434
- {
1435
- if (strlen($buffer['xor'])) {
1436
- $ciphertext = $plaintext ^ $buffer['xor'];
1437
- $buffer['xor'] = substr($buffer['xor'], strlen($ciphertext));
1438
- $plaintext = substr($plaintext, strlen($ciphertext));
1439
- } else {
1440
- $ciphertext = '';
1441
- }
1442
-
1443
- $block_size = $this->block_size;
1444
-
1445
- $len = strlen($plaintext);
1446
- $key = $this->key;
1447
- $overflow = $len % $block_size;
1448
-
1449
- if (strlen($plaintext)) {
1450
- if ($overflow) {
1451
- $ciphertext.= openssl_encrypt(substr($plaintext, 0, -$overflow) . str_repeat("\0", $block_size), $this->cipher_name_openssl, $key, $this->openssl_options, $encryptIV);
1452
- $xor = $this->_string_pop($ciphertext, $block_size);
1453
- if ($this->continuousBuffer) {
1454
- $encryptIV = $xor;
1455
- }
1456
- $ciphertext.= $this->_string_shift($xor, $overflow) ^ substr($plaintext, -$overflow);
1457
- if ($this->continuousBuffer) {
1458
- $buffer['xor'] = $xor;
1459
- }
1460
- } else {
1461
- $ciphertext = openssl_encrypt($plaintext, $this->cipher_name_openssl, $key, $this->openssl_options, $encryptIV);
1462
- if ($this->continuousBuffer) {
1463
- $encryptIV = substr($ciphertext, -$block_size) ^ substr($plaintext, -$block_size);
1464
- }
1465
- }
1466
- }
1467
-
1468
- return $ciphertext;
1469
- }
1470
-
1471
- /**
1472
- * phpseclib <-> OpenSSL Mode Mapper
1473
- *
1474
- * May need to be overwritten by classes extending this one in some cases
1475
- *
1476
- * @return int
1477
- * @access private
1478
- */
1479
- function _openssl_translate_mode()
1480
- {
1481
- switch ($this->mode) {
1482
- case CRYPT_MODE_ECB:
1483
- return 'ecb';
1484
- case CRYPT_MODE_CBC:
1485
- return 'cbc';
1486
- case CRYPT_MODE_CTR:
1487
- return 'ctr';
1488
- case CRYPT_MODE_CFB:
1489
- return 'cfb';
1490
- case CRYPT_MODE_OFB:
1491
- return 'ofb';
1492
- }
1493
- }
1494
-
1495
- /**
1496
- * Pad "packets".
1497
- *
1498
- * Block ciphers working by encrypting between their specified [$this->]block_size at a time
1499
- * If you ever need to encrypt or decrypt something that isn't of the proper length, it becomes necessary to
1500
- * pad the input so that it is of the proper length.
1501
- *
1502
- * Padding is enabled by default. Sometimes, however, it is undesirable to pad strings. Such is the case in SSH,
1503
- * where "packets" are padded with random bytes before being encrypted. Unpad these packets and you risk stripping
1504
- * away characters that shouldn't be stripped away. (SSH knows how many bytes are added because the length is
1505
- * transmitted separately)
1506
- *
1507
- * @see self::disablePadding()
1508
- * @access public
1509
- */
1510
- function enablePadding()
1511
- {
1512
- $this->padding = true;
1513
- }
1514
-
1515
- /**
1516
- * Do not pad packets.
1517
- *
1518
- * @see self::enablePadding()
1519
- * @access public
1520
- */
1521
- function disablePadding()
1522
- {
1523
- $this->padding = false;
1524
- }
1525
-
1526
- /**
1527
- * Treat consecutive "packets" as if they are a continuous buffer.
1528
- *
1529
- * Say you have a 32-byte plaintext $plaintext. Using the default behavior, the two following code snippets
1530
- * will yield different outputs:
1531
- *
1532
- * <code>
1533
- * echo $rijndael->encrypt(substr($plaintext, 0, 16));
1534
- * echo $rijndael->encrypt(substr($plaintext, 16, 16));
1535
- * </code>
1536
- * <code>
1537
- * echo $rijndael->encrypt($plaintext);
1538
- * </code>
1539
- *
1540
- * The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates
1541
- * another, as demonstrated with the following:
1542
- *
1543
- * <code>
1544
- * $rijndael->encrypt(substr($plaintext, 0, 16));
1545
- * echo $rijndael->decrypt($rijndael->encrypt(substr($plaintext, 16, 16)));
1546
- * </code>
1547
- * <code>
1548
- * echo $rijndael->decrypt($rijndael->encrypt(substr($plaintext, 16, 16)));
1549
- * </code>
1550
- *
1551
- * With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different
1552
- * outputs. The reason is due to the fact that the initialization vector's change after every encryption /
1553
- * decryption round when the continuous buffer is enabled. When it's disabled, they remain constant.
1554
- *
1555
- * Put another way, when the continuous buffer is enabled, the state of the Crypt_*() object changes after each
1556
- * encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that
1557
- * continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them),
1558
- * however, they are also less intuitive and more likely to cause you problems.
1559
- *
1560
- * @see self::disableContinuousBuffer()
1561
- * @access public
1562
- * @internal Could, but not must, extend by the child Crypt_* class
1563
- */
1564
- function enableContinuousBuffer()
1565
- {
1566
- if ($this->mode == CRYPT_MODE_ECB) {
1567
- return;
1568
- }
1569
-
1570
- $this->continuousBuffer = true;
1571
-
1572
- $this->_setEngine();
1573
- }
1574
-
1575
- /**
1576
- * Treat consecutive packets as if they are a discontinuous buffer.
1577
- *
1578
- * The default behavior.
1579
- *
1580
- * @see self::enableContinuousBuffer()
1581
- * @access public
1582
- * @internal Could, but not must, extend by the child Crypt_* class
1583
- */
1584
- function disableContinuousBuffer()
1585
- {
1586
- if ($this->mode == CRYPT_MODE_ECB) {
1587
- return;
1588
- }
1589
- if (!$this->continuousBuffer) {
1590
- return;
1591
- }
1592
-
1593
- $this->continuousBuffer = false;
1594
- $this->changed = true;
1595
-
1596
- $this->_setEngine();
1597
- }
1598
-
1599
- /**
1600
- * Test for engine validity
1601
- *
1602
- * @see self::Crypt_Base()
1603
- * @param int $engine
1604
- * @access public
1605
- * @return bool
1606
- */
1607
- function isValidEngine($engine)
1608
- {
1609
- switch ($engine) {
1610
- case CRYPT_ENGINE_OPENSSL:
1611
- if ($this->mode == CRYPT_MODE_STREAM && $this->continuousBuffer) {
1612
- return false;
1613
- }
1614
- $this->openssl_emulate_ctr = false;
1615
- $result = $this->cipher_name_openssl &&
1616
- extension_loaded('openssl') &&
1617
- // PHP 5.3.0 - 5.3.2 did not let you set IV's
1618
- version_compare(PHP_VERSION, '5.3.3', '>=');
1619
- if (!$result) {
1620
- return false;
1621
- }
1622
-
1623
- // prior to PHP 5.4.0 OPENSSL_RAW_DATA and OPENSSL_ZERO_PADDING were not defined. instead of expecting an integer
1624
- // $options openssl_encrypt expected a boolean $raw_data.
1625
- if (!defined('OPENSSL_RAW_DATA')) {
1626
- $this->openssl_options = true;
1627
- } else {
1628
- $this->openssl_options = OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING;
1629
- }
1630
-
1631
- $methods = openssl_get_cipher_methods();
1632
- if (in_array($this->cipher_name_openssl, $methods)) {
1633
- return true;
1634
- }
1635
- // not all of openssl's symmetric cipher's support ctr. for those
1636
- // that don't we'll emulate it
1637
- switch ($this->mode) {
1638
- case CRYPT_MODE_CTR:
1639
- if (in_array($this->cipher_name_openssl_ecb, $methods)) {
1640
- $this->openssl_emulate_ctr = true;
1641
- return true;
1642
- }
1643
- }
1644
- return false;
1645
- case CRYPT_ENGINE_MCRYPT:
1646
- return $this->cipher_name_mcrypt &&
1647
- extension_loaded('mcrypt') &&
1648
- in_array($this->cipher_name_mcrypt, @mcrypt_list_algorithms());
1649
- case CRYPT_ENGINE_INTERNAL:
1650
- return true;
1651
- }
1652
-
1653
- return false;
1654
- }
1655
-
1656
- /**
1657
- * Sets the preferred crypt engine
1658
- *
1659
- * Currently, $engine could be:
1660
- *
1661
- * - CRYPT_ENGINE_OPENSSL [very fast]
1662
- *
1663
- * - CRYPT_ENGINE_MCRYPT [fast]
1664
- *
1665
- * - CRYPT_ENGINE_INTERNAL [slow]
1666
- *
1667
- * If the preferred crypt engine is not available the fastest available one will be used
1668
- *
1669
- * @see self::Crypt_Base()
1670
- * @param int $engine
1671
- * @access public
1672
- */
1673
- function setPreferredEngine($engine)
1674
- {
1675
- switch ($engine) {
1676
- //case CRYPT_ENGINE_OPENSSL:
1677
- case CRYPT_ENGINE_MCRYPT:
1678
- case CRYPT_ENGINE_INTERNAL:
1679
- $this->preferredEngine = $engine;
1680
- break;
1681
- default:
1682
- $this->preferredEngine = CRYPT_ENGINE_OPENSSL;
1683
- }
1684
-
1685
- $this->_setEngine();
1686
- }
1687
-
1688
- /**
1689
- * Returns the engine currently being utilized
1690
- *
1691
- * @see self::_setEngine()
1692
- * @access public
1693
- */
1694
- function getEngine()
1695
- {
1696
- return $this->engine;
1697
- }
1698
-
1699
- /**
1700
- * Sets the engine as appropriate
1701
- *
1702
- * @see self::Crypt_Base()
1703
- * @access private
1704
- */
1705
- function _setEngine()
1706
- {
1707
- $this->engine = null;
1708
-
1709
- $candidateEngines = array(
1710
- $this->preferredEngine,
1711
- CRYPT_ENGINE_OPENSSL,
1712
- CRYPT_ENGINE_MCRYPT
1713
- );
1714
- foreach ($candidateEngines as $engine) {
1715
- if ($this->isValidEngine($engine)) {
1716
- $this->engine = $engine;
1717
- break;
1718
- }
1719
- }
1720
- if (!$this->engine) {
1721
- $this->engine = CRYPT_ENGINE_INTERNAL;
1722
- }
1723
-
1724
- if ($this->engine != CRYPT_ENGINE_MCRYPT && $this->enmcrypt) {
1725
- // Closing the current mcrypt resource(s). _mcryptSetup() will, if needed,
1726
- // (re)open them with the module named in $this->cipher_name_mcrypt
1727
- @mcrypt_module_close($this->enmcrypt);
1728
- @mcrypt_module_close($this->demcrypt);
1729
- $this->enmcrypt = null;
1730
- $this->demcrypt = null;
1731
-
1732
- if ($this->ecb) {
1733
- @mcrypt_module_close($this->ecb);
1734
- $this->ecb = null;
1735
- }
1736
- }
1737
-
1738
- $this->changed = true;
1739
- }
1740
-
1741
- /**
1742
- * Encrypts a block
1743
- *
1744
- * @access private
1745
- * @param string $in
1746
- * @return string
1747
- * @internal Must be extended by the child Crypt_* class
1748
- */
1749
- function _encryptBlock($in)
1750
- {
1751
- user_error((version_compare(PHP_VERSION, '5.0.0', '>=') ? __METHOD__ : __FUNCTION__) . '() must extend by class ' . get_class($this), E_USER_ERROR);
1752
- }
1753
-
1754
- /**
1755
- * Decrypts a block
1756
- *
1757
- * @access private
1758
- * @param string $in
1759
- * @return string
1760
- * @internal Must be extended by the child Crypt_* class
1761
- */
1762
- function _decryptBlock($in)
1763
- {
1764
- user_error((version_compare(PHP_VERSION, '5.0.0', '>=') ? __METHOD__ : __FUNCTION__) . '() must extend by class ' . get_class($this), E_USER_ERROR);
1765
- }
1766
-
1767
- /**
1768
- * Setup the key (expansion)
1769
- *
1770
- * Only used if $engine == CRYPT_ENGINE_INTERNAL
1771
- *
1772
- * @see self::_setup()
1773
- * @access private
1774
- * @internal Must be extended by the child Crypt_* class
1775
- */
1776
- function _setupKey()
1777
- {
1778
- user_error((version_compare(PHP_VERSION, '5.0.0', '>=') ? __METHOD__ : __FUNCTION__) . '() must extend by class ' . get_class($this), E_USER_ERROR);
1779
- }
1780
-
1781
- /**
1782
- * Setup the CRYPT_ENGINE_INTERNAL $engine
1783
- *
1784
- * (re)init, if necessary, the internal cipher $engine and flush all $buffers
1785
- * Used (only) if $engine == CRYPT_ENGINE_INTERNAL
1786
- *
1787
- * _setup() will be called each time if $changed === true
1788
- * typically this happens when using one or more of following public methods:
1789
- *
1790
- * - setKey()
1791
- *
1792
- * - setIV()
1793
- *
1794
- * - disableContinuousBuffer()
1795
- *
1796
- * - First run of encrypt() / decrypt() with no init-settings
1797
- *
1798
- * @see self::setKey()
1799
- * @see self::setIV()
1800
- * @see self::disableContinuousBuffer()
1801
- * @access private
1802
- * @internal _setup() is always called before en/decryption.
1803
- * @internal Could, but not must, extend by the child Crypt_* class
1804
- */
1805
- function _setup()
1806
- {
1807
- $this->_clearBuffers();
1808
- $this->_setupKey();
1809
-
1810
- if ($this->use_inline_crypt) {
1811
- $this->_setupInlineCrypt();
1812
- }
1813
- }
1814
-
1815
- /**
1816
- * Setup the CRYPT_ENGINE_MCRYPT $engine
1817
- *
1818
- * (re)init, if necessary, the (ext)mcrypt resources and flush all $buffers
1819
- * Used (only) if $engine = CRYPT_ENGINE_MCRYPT
1820
- *
1821
- * _setupMcrypt() will be called each time if $changed === true
1822
- * typically this happens when using one or more of following public methods:
1823
- *
1824
- * - setKey()
1825
- *
1826
- * - setIV()
1827
- *
1828
- * - disableContinuousBuffer()
1829
- *
1830
- * - First run of encrypt() / decrypt()
1831
- *
1832
- * @see self::setKey()
1833
- * @see self::setIV()
1834
- * @see self::disableContinuousBuffer()
1835
- * @access private
1836
- * @internal Could, but not must, extend by the child Crypt_* class
1837
- */
1838
- function _setupMcrypt()
1839
- {
1840
- $this->_clearBuffers();
1841
- $this->enchanged = $this->dechanged = true;
1842
-
1843
- if (!isset($this->enmcrypt)) {
1844
- static $mcrypt_modes = array(
1845
- CRYPT_MODE_CTR => 'ctr',
1846
- CRYPT_MODE_ECB => MCRYPT_MODE_ECB,
1847
- CRYPT_MODE_CBC => MCRYPT_MODE_CBC,
1848
- CRYPT_MODE_CFB => 'ncfb',
1849
- CRYPT_MODE_OFB => MCRYPT_MODE_NOFB,
1850
- CRYPT_MODE_STREAM => MCRYPT_MODE_STREAM,
1851
- );
1852
-
1853
- $this->demcrypt = @mcrypt_module_open($this->cipher_name_mcrypt, '', $mcrypt_modes[$this->mode], '');
1854
- $this->enmcrypt = @mcrypt_module_open($this->cipher_name_mcrypt, '', $mcrypt_modes[$this->mode], '');
1855
-
1856
- // we need the $ecb mcrypt resource (only) in MODE_CFB with enableContinuousBuffer()
1857
- // to workaround mcrypt's broken ncfb implementation in buffered mode
1858
- // see: {@link http://phpseclib.sourceforge.net/cfb-demo.phps}
1859
- if ($this->mode == CRYPT_MODE_CFB) {
1860
- $this->ecb = @mcrypt_module_open($this->cipher_name_mcrypt, '', MCRYPT_MODE_ECB, '');
1861
- }
1862
- } // else should mcrypt_generic_deinit be called?
1863
-
1864
- if ($this->mode == CRYPT_MODE_CFB) {
1865
- @mcrypt_generic_init($this->ecb, $this->key, str_repeat("\0", $this->block_size));
1866
- }
1867
- }
1868
-
1869
- /**
1870
- * Pads a string
1871
- *
1872
- * Pads a string using the RSA PKCS padding standards so that its length is a multiple of the blocksize.
1873
- * $this->block_size - (strlen($text) % $this->block_size) bytes are added, each of which is equal to
1874
- * chr($this->block_size - (strlen($text) % $this->block_size)
1875
- *
1876
- * If padding is disabled and $text is not a multiple of the blocksize, the string will be padded regardless
1877
- * and padding will, hence forth, be enabled.
1878
- *
1879
- * @see self::_unpad()
1880
- * @param string $text
1881
- * @access private
1882
- * @return string
1883
- */
1884
- function _pad($text)
1885
- {
1886
- $length = strlen($text);
1887
-
1888
- if (!$this->padding) {
1889
- if ($length % $this->block_size == 0) {
1890
- return $text;
1891
- } else {
1892
- user_error("The plaintext's length ($length) is not a multiple of the block size ({$this->block_size})");
1893
- $this->padding = true;
1894
- }
1895
- }
1896
-
1897
- $pad = $this->block_size - ($length % $this->block_size);
1898
-
1899
- return str_pad($text, $length + $pad, chr($pad));
1900
- }
1901
-
1902
- /**
1903
- * Unpads a string.
1904
- *
1905
- * If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong
1906
- * and false will be returned.
1907
- *
1908
- * @see self::_pad()
1909
- * @param string $text
1910
- * @access private
1911
- * @return string
1912
- */
1913
- function _unpad($text)
1914
- {
1915
- if (!$this->padding) {
1916
- return $text;
1917
- }
1918
-
1919
- $length = ord($text[strlen($text) - 1]);
1920
-
1921
- if (!$length || $length > $this->block_size) {
1922
- return false;
1923
- }
1924
-
1925
- return substr($text, 0, -$length);
1926
- }
1927
-
1928
- /**
1929
- * Clears internal buffers
1930
- *
1931
- * Clearing/resetting the internal buffers is done everytime
1932
- * after disableContinuousBuffer() or on cipher $engine (re)init
1933
- * ie after setKey() or setIV()
1934
- *
1935
- * @access public
1936
- * @internal Could, but not must, extend by the child Crypt_* class
1937
- */
1938
- function _clearBuffers()
1939
- {
1940
- $this->enbuffer = $this->debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true);
1941
-
1942
- // mcrypt's handling of invalid's $iv:
1943
- // $this->encryptIV = $this->decryptIV = strlen($this->iv) == $this->block_size ? $this->iv : str_repeat("\0", $this->block_size);
1944
- $this->encryptIV = $this->decryptIV = str_pad(substr($this->iv, 0, $this->block_size), $this->block_size, "\0");
1945
-
1946
- if (!$this->skip_key_adjustment) {
1947
- $this->key = str_pad(substr($this->key, 0, $this->key_length), $this->key_length, "\0");
1948
- }
1949
- }
1950
-
1951
- /**
1952
- * String Shift
1953
- *
1954
- * Inspired by array_shift
1955
- *
1956
- * @param string $string
1957
- * @param int $index
1958
- * @access private
1959
- * @return string
1960
- */
1961
- function _string_shift(&$string, $index = 1)
1962
- {
1963
- $substr = substr($string, 0, $index);
1964
- $string = substr($string, $index);
1965
- return $substr;
1966
- }
1967
-
1968
- /**
1969
- * String Pop
1970
- *
1971
- * Inspired by array_pop
1972
- *
1973
- * @param string $string
1974
- * @param int $index
1975
- * @access private
1976
- * @return string
1977
- */
1978
- function _string_pop(&$string, $index = 1)
1979
- {
1980
- $substr = substr($string, -$index);
1981
- $string = substr($string, 0, -$index);
1982
- return $substr;
1983
- }
1984
-
1985
- /**
1986
- * Increment the current string
1987
- *
1988
- * @see self::decrypt()
1989
- * @see self::encrypt()
1990
- * @param string $var
1991
- * @access private
1992
- */
1993
- function _increment_str(&$var)
1994
- {
1995
- for ($i = 4; $i <= strlen($var); $i+= 4) {
1996
- $temp = substr($var, -$i, 4);
1997
- switch ($temp) {
1998
- case "\xFF\xFF\xFF\xFF":
1999
- $var = substr_replace($var, "\x00\x00\x00\x00", -$i, 4);
2000
- break;
2001
- case "\x7F\xFF\xFF\xFF":
2002
- $var = substr_replace($var, "\x80\x00\x00\x00", -$i, 4);
2003
- return;
2004
- default:
2005
- $temp = unpack('Nnum', $temp);
2006
- $var = substr_replace($var, pack('N', $temp['num'] + 1), -$i, 4);
2007
- return;
2008
- }
2009
- }
2010
-
2011
- $remainder = strlen($var) % 4;
2012
-
2013
- if ($remainder == 0) {
2014
- return;
2015
- }
2016
-
2017
- $temp = unpack('Nnum', str_pad(substr($var, 0, $remainder), 4, "\0", STR_PAD_LEFT));
2018
- $temp = substr(pack('N', $temp['num'] + 1), -$remainder);
2019
- $var = substr_replace($var, $temp, 0, $remainder);
2020
- }
2021
-
2022
- /**
2023
- * Setup the performance-optimized function for de/encrypt()
2024
- *
2025
- * Stores the created (or existing) callback function-name
2026
- * in $this->inline_crypt
2027
- *
2028
- * Internally for phpseclib developers:
2029
- *
2030
- * _setupInlineCrypt() would be called only if:
2031
- *
2032
- * - $engine == CRYPT_ENGINE_INTERNAL and
2033
- *
2034
- * - $use_inline_crypt === true
2035
- *
2036
- * - each time on _setup(), after(!) _setupKey()
2037
- *
2038
- *
2039
- * This ensures that _setupInlineCrypt() has always a
2040
- * full ready2go initializated internal cipher $engine state
2041
- * where, for example, the keys allready expanded,
2042
- * keys/block_size calculated and such.
2043
- *
2044
- * It is, each time if called, the responsibility of _setupInlineCrypt():
2045
- *
2046
- * - to set $this->inline_crypt to a valid and fully working callback function
2047
- * as a (faster) replacement for encrypt() / decrypt()
2048
- *
2049
- * - NOT to create unlimited callback functions (for memory reasons!)
2050
- * no matter how often _setupInlineCrypt() would be called. At some
2051
- * point of amount they must be generic re-useable.
2052
- *
2053
- * - the code of _setupInlineCrypt() it self,
2054
- * and the generated callback code,
2055
- * must be, in following order:
2056
- * - 100% safe
2057
- * - 100% compatible to encrypt()/decrypt()
2058
- * - using only php5+ features/lang-constructs/php-extensions if
2059
- * compatibility (down to php4) or fallback is provided
2060
- * - readable/maintainable/understandable/commented and... not-cryptic-styled-code :-)
2061
- * - >= 10% faster than encrypt()/decrypt() [which is, by the way,
2062
- * the reason for the existence of _setupInlineCrypt() :-)]
2063
- * - memory-nice
2064
- * - short (as good as possible)
2065
- *
2066
- * Note: - _setupInlineCrypt() is using _createInlineCryptFunction() to create the full callback function code.
2067
- * - In case of using inline crypting, _setupInlineCrypt() must extend by the child Crypt_* class.
2068
- * - The following variable names are reserved:
2069
- * - $_* (all variable names prefixed with an underscore)
2070
- * - $self (object reference to it self. Do not use $this, but $self instead)
2071
- * - $in (the content of $in has to en/decrypt by the generated code)
2072
- * - The callback function should not use the 'return' statement, but en/decrypt'ing the content of $in only
2073
- *
2074
- *
2075
- * @see self::_setup()
2076
- * @see self::_createInlineCryptFunction()
2077
- * @see self::encrypt()
2078
- * @see self::decrypt()
2079
- * @access private
2080
- * @internal If a Crypt_* class providing inline crypting it must extend _setupInlineCrypt()
2081
- */
2082
- function _setupInlineCrypt()
2083
- {
2084
- // If, for any reason, an extending Crypt_Base() Crypt_* class
2085
- // not using inline crypting then it must be ensured that: $this->use_inline_crypt = false
2086
- // ie in the class var declaration of $use_inline_crypt in general for the Crypt_* class,
2087
- // in the constructor at object instance-time
2088
- // or, if it's runtime-specific, at runtime
2089
-
2090
- $this->use_inline_crypt = false;
2091
- }
2092
-
2093
- /**
2094
- * Creates the performance-optimized function for en/decrypt()
2095
- *
2096
- * Internally for phpseclib developers:
2097
- *
2098
- * _createInlineCryptFunction():
2099
- *
2100
- * - merge the $cipher_code [setup'ed by _setupInlineCrypt()]
2101
- * with the current [$this->]mode of operation code
2102
- *
2103
- * - create the $inline function, which called by encrypt() / decrypt()
2104
- * as its replacement to speed up the en/decryption operations.
2105
- *
2106
- * - return the name of the created $inline callback function
2107
- *
2108
- * - used to speed up en/decryption
2109
- *
2110
- *
2111
- *
2112
- * The main reason why can speed up things [up to 50%] this way are:
2113
- *
2114
- * - using variables more effective then regular.
2115
- * (ie no use of expensive arrays but integers $k_0, $k_1 ...
2116
- * or even, for example, the pure $key[] values hardcoded)
2117
- *
2118
- * - avoiding 1000's of function calls of ie _encryptBlock()
2119
- * but inlining the crypt operations.
2120
- * in the mode of operation for() loop.
2121
- *
2122
- * - full loop unroll the (sometimes key-dependent) rounds
2123
- * avoiding this way ++$i counters and runtime-if's etc...
2124
- *
2125
- * The basic code architectur of the generated $inline en/decrypt()
2126
- * lambda function, in pseudo php, is:
2127
- *
2128
- * <code>
2129
- * +----------------------------------------------------------------------------------------------+
2130
- * | callback $inline = create_function: |
2131
- * | lambda_function_0001_crypt_ECB($action, $text) |
2132
- * | { |
2133
- * | INSERT PHP CODE OF: |
2134
- * | $cipher_code['init_crypt']; // general init code. |
2135
- * | // ie: $sbox'es declarations used for |
2136
- * | // encrypt and decrypt'ing. |
2137
- * | |
2138
- * | switch ($action) { |
2139
- * | case 'encrypt': |
2140
- * | INSERT PHP CODE OF: |
2141
- * | $cipher_code['init_encrypt']; // encrypt sepcific init code. |
2142
- * | ie: specified $key or $box |
2143
- * | declarations for encrypt'ing. |
2144
- * | |
2145
- * | foreach ($ciphertext) { |
2146
- * | $in = $block_size of $ciphertext; |
2147
- * | |
2148
- * | INSERT PHP CODE OF: |
2149
- * | $cipher_code['encrypt_block']; // encrypt's (string) $in, which is always: |
2150
- * | // strlen($in) == $this->block_size |
2151
- * | // here comes the cipher algorithm in action |
2152
- * | // for encryption. |
2153
- * | // $cipher_code['encrypt_block'] has to |
2154
- * | // encrypt the content of the $in variable |
2155
- * | |
2156
- * | $plaintext .= $in; |
2157
- * | } |
2158
- * | return $plaintext; |
2159
- * | |
2160
- * | case 'decrypt': |
2161
- * | INSERT PHP CODE OF: |
2162
- * | $cipher_code['init_decrypt']; // decrypt sepcific init code |
2163
- * | ie: specified $key or $box |
2164
- * | declarations for decrypt'ing. |
2165
- * | foreach ($plaintext) { |
2166
- * | $in = $block_size of $plaintext; |
2167
- * | |
2168
- * | INSERT PHP CODE OF: |
2169
- * | $cipher_code['decrypt_block']; // decrypt's (string) $in, which is always |
2170
- * | // strlen($in) == $this->block_size |
2171
- * | // here comes the cipher algorithm in action |
2172
- * | // for decryption. |
2173
- * | // $cipher_code['decrypt_block'] has to |
2174
- * | // decrypt the content of the $in variable |
2175
- * | $ciphertext .= $in; |
2176
- * | } |
2177
- * | return $ciphertext; |
2178
- * | } |
2179
- * | } |
2180
- * +----------------------------------------------------------------------------------------------+
2181
- * </code>
2182
- *
2183
- * See also the Crypt_*::_setupInlineCrypt()'s for
2184
- * productive inline $cipher_code's how they works.
2185
- *
2186
- * Structure of:
2187
- * <code>
2188
- * $cipher_code = array(
2189
- * 'init_crypt' => (string) '', // optional
2190
- * 'init_encrypt' => (string) '', // optional
2191
- * 'init_decrypt' => (string) '', // optional
2192
- * 'encrypt_block' => (string) '', // required
2193
- * 'decrypt_block' => (string) '' // required
2194
- * );
2195
- * </code>
2196
- *
2197
- * @see self::_setupInlineCrypt()
2198
- * @see self::encrypt()
2199
- * @see self::decrypt()
2200
- * @param array $cipher_code
2201
- * @access private
2202
- * @return string (the name of the created callback function)
2203
- */
2204
- function _createInlineCryptFunction($cipher_code)
2205
- {
2206
- $block_size = $this->block_size;
2207
-
2208
- // optional
2209
- $init_crypt = isset($cipher_code['init_crypt']) ? $cipher_code['init_crypt'] : '';
2210
- $init_encrypt = isset($cipher_code['init_encrypt']) ? $cipher_code['init_encrypt'] : '';
2211
- $init_decrypt = isset($cipher_code['init_decrypt']) ? $cipher_code['init_decrypt'] : '';
2212
- // required
2213
- $encrypt_block = $cipher_code['encrypt_block'];
2214
- $decrypt_block = $cipher_code['decrypt_block'];
2215
-
2216
- // Generating mode of operation inline code,
2217
- // merged with the $cipher_code algorithm
2218
- // for encrypt- and decryption.
2219
- switch ($this->mode) {
2220
- case CRYPT_MODE_ECB:
2221
- $encrypt = $init_encrypt . '
2222
- $_ciphertext = "";
2223
- $_plaintext_len = strlen($_text);
2224
-
2225
- for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
2226
- $in = substr($_text, $_i, '.$block_size.');
2227
- '.$encrypt_block.'
2228
- $_ciphertext.= $in;
2229
- }
2230
-
2231
- return $_ciphertext;
2232
- ';
2233
-
2234
- $decrypt = $init_decrypt . '
2235
- $_plaintext = "";
2236
- $_text = str_pad($_text, strlen($_text) + ('.$block_size.' - strlen($_text) % '.$block_size.') % '.$block_size.', chr(0));
2237
- $_ciphertext_len = strlen($_text);
2238
-
2239
- for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
2240
- $in = substr($_text, $_i, '.$block_size.');
2241
- '.$decrypt_block.'
2242
- $_plaintext.= $in;
2243
- }
2244
-
2245
- return $self->_unpad($_plaintext);
2246
- ';
2247
- break;
2248
- case CRYPT_MODE_CTR:
2249
- $encrypt = $init_encrypt . '
2250
- $_ciphertext = "";
2251
- $_plaintext_len = strlen($_text);
2252
- $_xor = $self->encryptIV;
2253
- $_buffer = &$self->enbuffer;
2254
- if (strlen($_buffer["ciphertext"])) {
2255
- for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
2256
- $_block = substr($_text, $_i, '.$block_size.');
2257
- if (strlen($_block) > strlen($_buffer["ciphertext"])) {
2258
- $in = $_xor;
2259
- '.$encrypt_block.'
2260
- $self->_increment_str($_xor);
2261
- $_buffer["ciphertext"].= $in;
2262
- }
2263
- $_key = $self->_string_shift($_buffer["ciphertext"], '.$block_size.');
2264
- $_ciphertext.= $_block ^ $_key;
2265
- }
2266
- } else {
2267
- for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
2268
- $_block = substr($_text, $_i, '.$block_size.');
2269
- $in = $_xor;
2270
- '.$encrypt_block.'
2271
- $self->_increment_str($_xor);
2272
- $_key = $in;
2273
- $_ciphertext.= $_block ^ $_key;
2274
- }
2275
- }
2276
- if ($self->continuousBuffer) {
2277
- $self->encryptIV = $_xor;
2278
- if ($_start = $_plaintext_len % '.$block_size.') {
2279
- $_buffer["ciphertext"] = substr($_key, $_start) . $_buffer["ciphertext"];
2280
- }
2281
- }
2282
-
2283
- return $_ciphertext;
2284
- ';
2285
-
2286
- $decrypt = $init_encrypt . '
2287
- $_plaintext = "";
2288
- $_ciphertext_len = strlen($_text);
2289
- $_xor = $self->decryptIV;
2290
- $_buffer = &$self->debuffer;
2291
-
2292
- if (strlen($_buffer["ciphertext"])) {
2293
- for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
2294
- $_block = substr($_text, $_i, '.$block_size.');
2295
- if (strlen($_block) > strlen($_buffer["ciphertext"])) {
2296
- $in = $_xor;
2297
- '.$encrypt_block.'
2298
- $self->_increment_str($_xor);
2299
- $_buffer["ciphertext"].= $in;
2300
- }
2301
- $_key = $self->_string_shift($_buffer["ciphertext"], '.$block_size.');
2302
- $_plaintext.= $_block ^ $_key;
2303
- }
2304
- } else {
2305
- for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
2306
- $_block = substr($_text, $_i, '.$block_size.');
2307
- $in = $_xor;
2308
- '.$encrypt_block.'
2309
- $self->_increment_str($_xor);
2310
- $_key = $in;
2311
- $_plaintext.= $_block ^ $_key;
2312
- }
2313
- }
2314
- if ($self->continuousBuffer) {
2315
- $self->decryptIV = $_xor;
2316
- if ($_start = $_ciphertext_len % '.$block_size.') {
2317
- $_buffer["ciphertext"] = substr($_key, $_start) . $_buffer["ciphertext"];
2318
- }
2319
- }
2320
-
2321
- return $_plaintext;
2322
- ';
2323
- break;
2324
- case CRYPT_MODE_CFB:
2325
- $encrypt = $init_encrypt . '
2326
- $_ciphertext = "";
2327
- $_buffer = &$self->enbuffer;
2328
-
2329
- if ($self->continuousBuffer) {
2330
- $_iv = &$self->encryptIV;
2331
- $_pos = &$_buffer["pos"];
2332
- } else {
2333
- $_iv = $self->encryptIV;
2334
- $_pos = 0;
2335
- }
2336
- $_len = strlen($_text);
2337
- $_i = 0;
2338
- if ($_pos) {
2339
- $_orig_pos = $_pos;
2340
- $_max = '.$block_size.' - $_pos;
2341
- if ($_len >= $_max) {
2342
- $_i = $_max;
2343
- $_len-= $_max;
2344
- $_pos = 0;
2345
- } else {
2346
- $_i = $_len;
2347
- $_pos+= $_len;
2348
- $_len = 0;
2349
- }
2350
- $_ciphertext = substr($_iv, $_orig_pos) ^ $_text;
2351
- $_iv = substr_replace($_iv, $_ciphertext, $_orig_pos, $_i);
2352
- }
2353
- while ($_len >= '.$block_size.') {
2354
- $in = $_iv;
2355
- '.$encrypt_block.';
2356
- $_iv = $in ^ substr($_text, $_i, '.$block_size.');
2357
- $_ciphertext.= $_iv;
2358
- $_len-= '.$block_size.';
2359
- $_i+= '.$block_size.';
2360
- }
2361
- if ($_len) {
2362
- $in = $_iv;
2363
- '.$encrypt_block.'
2364
- $_iv = $in;
2365
- $_block = $_iv ^ substr($_text, $_i);
2366
- $_iv = substr_replace($_iv, $_block, 0, $_len);
2367
- $_ciphertext.= $_block;
2368
- $_pos = $_len;
2369
- }
2370
- return $_ciphertext;
2371
- ';
2372
-
2373
- $decrypt = $init_encrypt . '
2374
- $_plaintext = "";
2375
- $_buffer = &$self->debuffer;
2376
-
2377
- if ($self->continuousBuffer) {
2378
- $_iv = &$self->decryptIV;
2379
- $_pos = &$_buffer["pos"];
2380
- } else {
2381
- $_iv = $self->decryptIV;
2382
- $_pos = 0;
2383
- }
2384
- $_len = strlen($_text);
2385
- $_i = 0;
2386
- if ($_pos) {
2387
- $_orig_pos = $_pos;
2388
- $_max = '.$block_size.' - $_pos;
2389
- if ($_len >= $_max) {
2390
- $_i = $_max;
2391
- $_len-= $_max;
2392
- $_pos = 0;
2393
- } else {
2394
- $_i = $_len;
2395
- $_pos+= $_len;
2396
- $_len = 0;
2397
- }
2398
- $_plaintext = substr($_iv, $_orig_pos) ^ $_text;
2399
- $_iv = substr_replace($_iv, substr($_text, 0, $_i), $_orig_pos, $_i);
2400
- }
2401
- while ($_len >= '.$block_size.') {
2402
- $in = $_iv;
2403
- '.$encrypt_block.'
2404
- $_iv = $in;
2405
- $cb = substr($_text, $_i, '.$block_size.');
2406
- $_plaintext.= $_iv ^ $cb;
2407
- $_iv = $cb;
2408
- $_len-= '.$block_size.';
2409
- $_i+= '.$block_size.';
2410
- }
2411
- if ($_len) {
2412
- $in = $_iv;
2413
- '.$encrypt_block.'
2414
- $_iv = $in;
2415
- $_plaintext.= $_iv ^ substr($_text, $_i);
2416
- $_iv = substr_replace($_iv, substr($_text, $_i), 0, $_len);
2417
- $_pos = $_len;
2418
- }
2419
-
2420
- return $_plaintext;
2421
- ';
2422
- break;
2423
- case CRYPT_MODE_OFB:
2424
- $encrypt = $init_encrypt . '
2425
- $_ciphertext = "";
2426
- $_plaintext_len = strlen($_text);
2427
- $_xor = $self->encryptIV;
2428
- $_buffer = &$self->enbuffer;
2429
-
2430
- if (strlen($_buffer["xor"])) {
2431
- for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
2432
- $_block = substr($_text, $_i, '.$block_size.');
2433
- if (strlen($_block) > strlen($_buffer["xor"])) {
2434
- $in = $_xor;
2435
- '.$encrypt_block.'
2436
- $_xor = $in;
2437
- $_buffer["xor"].= $_xor;
2438
- }
2439
- $_key = $self->_string_shift($_buffer["xor"], '.$block_size.');
2440
- $_ciphertext.= $_block ^ $_key;
2441
- }
2442
- } else {
2443
- for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
2444
- $in = $_xor;
2445
- '.$encrypt_block.'
2446
- $_xor = $in;
2447
- $_ciphertext.= substr($_text, $_i, '.$block_size.') ^ $_xor;
2448
- }
2449
- $_key = $_xor;
2450
- }
2451
- if ($self->continuousBuffer) {
2452
- $self->encryptIV = $_xor;
2453
- if ($_start = $_plaintext_len % '.$block_size.') {
2454
- $_buffer["xor"] = substr($_key, $_start) . $_buffer["xor"];
2455
- }
2456
- }
2457
- return $_ciphertext;
2458
- ';
2459
-
2460
- $decrypt = $init_encrypt . '
2461
- $_plaintext = "";
2462
- $_ciphertext_len = strlen($_text);
2463
- $_xor = $self->decryptIV;
2464
- $_buffer = &$self->debuffer;
2465
-
2466
- if (strlen($_buffer["xor"])) {
2467
- for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
2468
- $_block = substr($_text, $_i, '.$block_size.');
2469
- if (strlen($_block) > strlen($_buffer["xor"])) {
2470
- $in = $_xor;
2471
- '.$encrypt_block.'
2472
- $_xor = $in;
2473
- $_buffer["xor"].= $_xor;
2474
- }
2475
- $_key = $self->_string_shift($_buffer["xor"], '.$block_size.');
2476
- $_plaintext.= $_block ^ $_key;
2477
- }
2478
- } else {
2479
- for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
2480
- $in = $_xor;
2481
- '.$encrypt_block.'
2482
- $_xor = $in;
2483
- $_plaintext.= substr($_text, $_i, '.$block_size.') ^ $_xor;
2484
- }
2485
- $_key = $_xor;
2486
- }
2487
- if ($self->continuousBuffer) {
2488
- $self->decryptIV = $_xor;
2489
- if ($_start = $_ciphertext_len % '.$block_size.') {
2490
- $_buffer["xor"] = substr($_key, $_start) . $_buffer["xor"];
2491
- }
2492
- }
2493
- return $_plaintext;
2494
- ';
2495
- break;
2496
- case CRYPT_MODE_STREAM:
2497
- $encrypt = $init_encrypt . '
2498
- $_ciphertext = "";
2499
- '.$encrypt_block.'
2500
- return $_ciphertext;
2501
- ';
2502
- $decrypt = $init_decrypt . '
2503
- $_plaintext = "";
2504
- '.$decrypt_block.'
2505
- return $_plaintext;
2506
- ';
2507
- break;
2508
- // case CRYPT_MODE_CBC:
2509
- default:
2510
- $encrypt = $init_encrypt . '
2511
- $_ciphertext = "";
2512
- $_plaintext_len = strlen($_text);
2513
-
2514
- $in = $self->encryptIV;
2515
-
2516
- for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
2517
- $in = substr($_text, $_i, '.$block_size.') ^ $in;
2518
- '.$encrypt_block.'
2519
- $_ciphertext.= $in;
2520
- }
2521
-
2522
- if ($self->continuousBuffer) {
2523
- $self->encryptIV = $in;
2524
- }
2525
-
2526
- return $_ciphertext;
2527
- ';
2528
-
2529
- $decrypt = $init_decrypt . '
2530
- $_plaintext = "";
2531
- $_text = str_pad($_text, strlen($_text) + ('.$block_size.' - strlen($_text) % '.$block_size.') % '.$block_size.', chr(0));
2532
- $_ciphertext_len = strlen($_text);
2533
-
2534
- $_iv = $self->decryptIV;
2535
-
2536
- for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
2537
- $in = $_block = substr($_text, $_i, '.$block_size.');
2538
- '.$decrypt_block.'
2539
- $_plaintext.= $in ^ $_iv;
2540
- $_iv = $_block;
2541
- }
2542
-
2543
- if ($self->continuousBuffer) {
2544
- $self->decryptIV = $_iv;
2545
- }
2546
-
2547
- return $self->_unpad($_plaintext);
2548
- ';
2549
- break;
2550
- }
2551
-
2552
- // Create the $inline function and return its name as string. Ready to run!
2553
- return create_function('$_action, &$self, $_text', $init_crypt . 'if ($_action == "encrypt") { ' . $encrypt . ' } else { ' . $decrypt . ' }');
2554
- }
2555
-
2556
- /**
2557
- * Holds the lambda_functions table (classwide)
2558
- *
2559
- * Each name of the lambda function, created from
2560
- * _setupInlineCrypt() && _createInlineCryptFunction()
2561
- * is stored, classwide (!), here for reusing.
2562
- *
2563
- * The string-based index of $function is a classwide
2564
- * unique value representing, at least, the $mode of
2565
- * operation (or more... depends of the optimizing level)
2566
- * for which $mode the lambda function was created.
2567
- *
2568
- * @access private
2569
- * @return array &$functions
2570
- */
2571
- function &_getLambdaFunctions()
2572
- {
2573
- static $functions = array();
2574
- return $functions;
2575
- }
2576
-
2577
- /**
2578
- * Generates a digest from $bytes
2579
- *
2580
- * @see self::_setupInlineCrypt()
2581
- * @access private
2582
- * @param $bytes
2583
- * @return string
2584
- */
2585
- function _hashInlineCryptFunction($bytes)
2586
- {
2587
- if (!defined('CRYPT_BASE_WHIRLPOOL_AVAILABLE')) {
2588
- define('CRYPT_BASE_WHIRLPOOL_AVAILABLE', (bool)(extension_loaded('hash') && in_array('whirlpool', hash_algos())));
2589
- }
2590
-
2591
- $result = '';
2592
- $hash = $bytes;
2593
-
2594
- switch (true) {
2595
- case CRYPT_BASE_WHIRLPOOL_AVAILABLE:
2596
- foreach (str_split($bytes, 64) as $t) {
2597
- $hash = hash('whirlpool', $hash, true);
2598
- $result .= $t ^ $hash;
2599
- }
2600
- return $result . hash('whirlpool', $hash, true);
2601
- default:
2602
- $len = strlen($bytes);
2603
- for ($i = 0; $i < $len; $i+=20) {
2604
- $t = substr($bytes, $i, 20);
2605
- $hash = pack('H*', sha1($hash));
2606
- $result .= $t ^ $hash;
2607
- }
2608
- return $result . pack('H*', sha1($hash));
2609
- }
2610
- }
2611
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/phpseclib/Crypt/Blowfish.php DELETED
@@ -1,671 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Pure-PHP implementation of Blowfish.
5
- *
6
- * Uses mcrypt, if available, and an internal implementation, otherwise.
7
- *
8
- * PHP versions 4 and 5
9
- *
10
- * Useful resources are as follows:
11
- *
12
- * - {@link http://en.wikipedia.org/wiki/Blowfish_(cipher) Wikipedia description of Blowfish}
13
- *
14
- * Here's a short example of how to use this library:
15
- * <code>
16
- * <?php
17
- * include 'Crypt/Blowfish.php';
18
- *
19
- * $blowfish = new Crypt_Blowfish();
20
- *
21
- * $blowfish->setKey('12345678901234567890123456789012');
22
- *
23
- * $plaintext = str_repeat('a', 1024);
24
- *
25
- * echo $blowfish->decrypt($blowfish->encrypt($plaintext));
26
- * ?>
27
- * </code>
28
- *
29
- * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
30
- * of this software and associated documentation files (the "Software"), to deal
31
- * in the Software without restriction, including without limitation the rights
32
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
33
- * copies of the Software, and to permit persons to whom the Software is
34
- * furnished to do so, subject to the following conditions:
35
- *
36
- * The above copyright notice and this permission notice shall be included in
37
- * all copies or substantial portions of the Software.
38
- *
39
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
40
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
41
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
42
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
43
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
44
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
45
- * THE SOFTWARE.
46
- *
47
- * @category Crypt
48
- * @package Crypt_Blowfish
49
- * @author Jim Wigginton <terrafrost@php.net>
50
- * @author Hans-Juergen Petrich <petrich@tronic-media.com>
51
- * @copyright 2007 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_Base
58
- *
59
- * Base cipher class
60
- */
61
- if (!class_exists('Crypt_Base')) {
62
- include_once 'Base.php';
63
- }
64
-
65
- /**#@+
66
- * @access public
67
- * @see self::encrypt()
68
- * @see self::decrypt()
69
- */
70
- /**
71
- * Encrypt / decrypt using the Counter mode.
72
- *
73
- * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
74
- *
75
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
76
- */
77
- define('CRYPT_BLOWFISH_MODE_CTR', CRYPT_MODE_CTR);
78
- /**
79
- * Encrypt / decrypt using the Electronic Code Book mode.
80
- *
81
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
82
- */
83
- define('CRYPT_BLOWFISH_MODE_ECB', CRYPT_MODE_ECB);
84
- /**
85
- * Encrypt / decrypt using the Code Book Chaining mode.
86
- *
87
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
88
- */
89
- define('CRYPT_BLOWFISH_MODE_CBC', CRYPT_MODE_CBC);
90
- /**
91
- * Encrypt / decrypt using the Cipher Feedback mode.
92
- *
93
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
94
- */
95
- define('CRYPT_BLOWFISH_MODE_CFB', CRYPT_MODE_CFB);
96
- /**
97
- * Encrypt / decrypt using the Cipher Feedback mode.
98
- *
99
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
100
- */
101
- define('CRYPT_BLOWFISH_MODE_OFB', CRYPT_MODE_OFB);
102
- /**#@-*/
103
-
104
- /**
105
- * Pure-PHP implementation of Blowfish.
106
- *
107
- * @package Crypt_Blowfish
108
- * @author Jim Wigginton <terrafrost@php.net>
109
- * @author Hans-Juergen Petrich <petrich@tronic-media.com>
110
- * @access public
111
- */
112
- class Crypt_Blowfish extends Crypt_Base
113
- {
114
- /**
115
- * Block Length of the cipher
116
- *
117
- * @see Crypt_Base::block_size
118
- * @var int
119
- * @access private
120
- */
121
- var $block_size = 8;
122
-
123
- /**
124
- * The namespace used by the cipher for its constants.
125
- *
126
- * @see Crypt_Base::const_namespace
127
- * @var string
128
- * @access private
129
- */
130
- var $const_namespace = 'BLOWFISH';
131
-
132
- /**
133
- * The mcrypt specific name of the cipher
134
- *
135
- * @see Crypt_Base::cipher_name_mcrypt
136
- * @var string
137
- * @access private
138
- */
139
- var $cipher_name_mcrypt = 'blowfish';
140
-
141
- /**
142
- * Optimizing value while CFB-encrypting
143
- *
144
- * @see Crypt_Base::cfb_init_len
145
- * @var int
146
- * @access private
147
- */
148
- var $cfb_init_len = 500;
149
-
150
- /**
151
- * The fixed subkeys boxes ($sbox0 - $sbox3) with 256 entries each
152
- *
153
- * S-Box 0
154
- *
155
- * @access private
156
- * @var array
157
- */
158
- var $sbox0 = array(
159
- 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99,
160
- 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e,
161
- 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
162
- 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e,
163
- 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440,
164
- 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
165
- 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677,
166
- 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032,
167
- 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
168
- 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0,
169
- 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98,
170
- 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
171
- 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d,
172
- 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7,
173
- 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
174
- 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09,
175
- 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb,
176
- 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
177
- 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82,
178
- 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573,
179
- 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
180
- 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8,
181
- 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0,
182
- 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
183
- 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1,
184
- 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9,
185
- 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
186
- 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af,
187
- 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5,
188
- 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
189
- 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915,
190
- 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a
191
- );
192
-
193
- /**
194
- * S-Box 1
195
- *
196
- * @access private
197
- * @var array
198
- */
199
- var $sbox1 = array(
200
- 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,
201
- 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e,
202
- 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
203
- 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,
204
- 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8,
205
- 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
206
- 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,
207
- 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331,
208
- 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
209
- 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,
210
- 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2,
211
- 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
212
- 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,
213
- 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3,
214
- 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
215
- 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960,
216
- 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28,
217
- 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
218
- 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,
219
- 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e,
220
- 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
221
- 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281,
222
- 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696,
223
- 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
224
- 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0,
225
- 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250,
226
- 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
227
- 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,
228
- 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e,
229
- 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
230
- 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,
231
- 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7
232
- );
233
-
234
- /**
235
- * S-Box 2
236
- *
237
- * @access private
238
- * @var array
239
- */
240
- var $sbox2 = array(
241
- 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068,
242
- 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,
243
- 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
244
- 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb,
245
- 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,
246
- 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
247
- 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb,
248
- 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,
249
- 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
250
- 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc,
251
- 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,
252
- 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
253
- 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728,
254
- 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,
255
- 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
256
- 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b,
257
- 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,
258
- 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
259
- 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9,
260
- 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,
261
- 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
262
- 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61,
263
- 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,
264
- 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
265
- 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633,
266
- 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,
267
- 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
268
- 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62,
269
- 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,
270
- 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
271
- 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c,
272
- 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0
273
- );
274
-
275
- /**
276
- * S-Box 3
277
- *
278
- * @access private
279
- * @var array
280
- */
281
- var $sbox3 = array(
282
- 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe,
283
- 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4,
284
- 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
285
- 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22,
286
- 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6,
287
- 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
288
- 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51,
289
- 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c,
290
- 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
291
- 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd,
292
- 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319,
293
- 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
294
- 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32,
295
- 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166,
296
- 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
297
- 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47,
298
- 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d,
299
- 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
300
- 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd,
301
- 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7,
302
- 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
303
- 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525,
304
- 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442,
305
- 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
306
- 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d,
307
- 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299,
308
- 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
309
- 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a,
310
- 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b,
311
- 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
312
- 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9,
313
- 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6
314
- );
315
-
316
- /**
317
- * P-Array consists of 18 32-bit subkeys
318
- *
319
- * @var array
320
- * @access private
321
- */
322
- var $parray = array(
323
- 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0,
324
- 0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
325
- 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b
326
- );
327
-
328
- /**
329
- * The BCTX-working Array
330
- *
331
- * Holds the expanded key [p] and the key-depended s-boxes [sb]
332
- *
333
- * @var array
334
- * @access private
335
- */
336
- var $bctx;
337
-
338
- /**
339
- * Holds the last used key
340
- *
341
- * @var array
342
- * @access private
343
- */
344
- var $kl;
345
-
346
- /**
347
- * The Key Length (in bytes)
348
- *
349
- * @see Crypt_Base::setKeyLength()
350
- * @var int
351
- * @access private
352
- * @internal The max value is 256 / 8 = 32, the min value is 128 / 8 = 16. Exists in conjunction with $Nk
353
- * because the encryption / decryption / key schedule creation requires this number and not $key_length. We could
354
- * derive this from $key_length or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu
355
- * of that, we'll just precompute it once.
356
- */
357
- var $key_length = 16;
358
-
359
- /**
360
- * Sets the key length.
361
- *
362
- * Key lengths can be between 32 and 448 bits.
363
- *
364
- * @access public
365
- * @param int $length
366
- */
367
- function setKeyLength($length)
368
- {
369
- if ($length < 32) {
370
- $this->key_length = 7;
371
- } elseif ($length > 448) {
372
- $this->key_length = 56;
373
- } else {
374
- $this->key_length = $length >> 3;
375
- }
376
-
377
- parent::setKeyLength($length);
378
- }
379
-
380
- /**
381
- * Test for engine validity
382
- *
383
- * This is mainly just a wrapper to set things up for Crypt_Base::isValidEngine()
384
- *
385
- * @see Crypt_Base::isValidEngine()
386
- * @param int $engine
387
- * @access public
388
- * @return bool
389
- */
390
- function isValidEngine($engine)
391
- {
392
- if ($engine == CRYPT_ENGINE_OPENSSL) {
393
- if ($this->key_length != 16) {
394
- return false;
395
- }
396
- $this->cipher_name_openssl_ecb = 'bf-ecb';
397
- $this->cipher_name_openssl = 'bf-' . $this->_openssl_translate_mode();
398
- }
399
-
400
- return parent::isValidEngine($engine);
401
- }
402
-
403
- /**
404
- * Setup the key (expansion)
405
- *
406
- * @see Crypt_Base::_setupKey()
407
- * @access private
408
- */
409
- function _setupKey()
410
- {
411
- if (isset($this->kl['key']) && $this->key === $this->kl['key']) {
412
- // already expanded
413
- return;
414
- }
415
- $this->kl = array('key' => $this->key);
416
-
417
- /* key-expanding p[] and S-Box building sb[] */
418
- $this->bctx = array(
419
- 'p' => array(),
420
- 'sb' => array(
421
- $this->sbox0,
422
- $this->sbox1,
423
- $this->sbox2,
424
- $this->sbox3
425
- )
426
- );
427
-
428
- // unpack binary string in unsigned chars
429
- $key = array_values(unpack('C*', $this->key));
430
- $keyl = count($key);
431
- for ($j = 0, $i = 0; $i < 18; ++$i) {
432
- // xor P1 with the first 32-bits of the key, xor P2 with the second 32-bits ...
433
- for ($data = 0, $k = 0; $k < 4; ++$k) {
434
- $data = ($data << 8) | $key[$j];
435
- if (++$j >= $keyl) {
436
- $j = 0;
437
- }
438
- }
439
- $this->bctx['p'][] = $this->parray[$i] ^ $data;
440
- }
441
-
442
- // encrypt the zero-string, replace P1 and P2 with the encrypted data,
443
- // encrypt P3 and P4 with the new P1 and P2, do it with all P-array and subkeys
444
- $data = "\0\0\0\0\0\0\0\0";
445
- for ($i = 0; $i < 18; $i += 2) {
446
- list($l, $r) = array_values(unpack('N*', $data = $this->_encryptBlock($data)));
447
- $this->bctx['p'][$i ] = $l;
448
- $this->bctx['p'][$i + 1] = $r;
449
- }
450
- for ($i = 0; $i < 4; ++$i) {
451
- for ($j = 0; $j < 256; $j += 2) {
452
- list($l, $r) = array_values(unpack('N*', $data = $this->_encryptBlock($data)));
453
- $this->bctx['sb'][$i][$j ] = $l;
454
- $this->bctx['sb'][$i][$j + 1] = $r;
455
- }
456
- }
457
- }
458
-
459
- /**
460
- * Encrypts a block
461
- *
462
- * @access private
463
- * @param string $in
464
- * @return string
465
- */
466
- function _encryptBlock($in)
467
- {
468
- $p = $this->bctx["p"];
469
- // extract($this->bctx["sb"], EXTR_PREFIX_ALL, "sb"); // slower
470
- $sb_0 = $this->bctx["sb"][0];
471
- $sb_1 = $this->bctx["sb"][1];
472
- $sb_2 = $this->bctx["sb"][2];
473
- $sb_3 = $this->bctx["sb"][3];
474
-
475
- $in = unpack("N*", $in);
476
- $l = $in[1];
477
- $r = $in[2];
478
-
479
- for ($i = 0; $i < 16; $i+= 2) {
480
- $l^= $p[$i];
481
- $r^= $this->safe_intval(($this->safe_intval($sb_0[$l >> 24 & 0xff] + $sb_1[$l >> 16 & 0xff]) ^
482
- $sb_2[$l >> 8 & 0xff]) +
483
- $sb_3[$l & 0xff]);
484
-
485
- $r^= $p[$i + 1];
486
- $l^= $this->safe_intval(($this->safe_intval($sb_0[$r >> 24 & 0xff] + $sb_1[$r >> 16 & 0xff]) ^
487
- $sb_2[$r >> 8 & 0xff]) +
488
- $sb_3[$r & 0xff]);
489
- }
490
- return pack("N*", $r ^ $p[17], $l ^ $p[16]);
491
- }
492
-
493
- /**
494
- * Decrypts a block
495
- *
496
- * @access private
497
- * @param string $in
498
- * @return string
499
- */
500
- function _decryptBlock($in)
501
- {
502
- $p = $this->bctx["p"];
503
- $sb_0 = $this->bctx["sb"][0];
504
- $sb_1 = $this->bctx["sb"][1];
505
- $sb_2 = $this->bctx["sb"][2];
506
- $sb_3 = $this->bctx["sb"][3];
507
-
508
- $in = unpack("N*", $in);
509
- $l = $in[1];
510
- $r = $in[2];
511
-
512
- for ($i = 17; $i > 2; $i-= 2) {
513
- $l^= $p[$i];
514
- $r^= $this->safe_intval(($this->safe_intval($sb_0[$l >> 24 & 0xff] + $sb_1[$l >> 16 & 0xff]) ^
515
- $sb_2[$l >> 8 & 0xff]) +
516
- $sb_3[$l & 0xff]);
517
-
518
- $r^= $p[$i - 1];
519
- $l^= $this->safe_intval(($this->safe_intval($sb_0[$r >> 24 & 0xff] + $sb_1[$r >> 16 & 0xff]) ^
520
- $sb_2[$r >> 8 & 0xff]) +
521
- $sb_3[$r & 0xff]);
522
- }
523
- return pack("N*", $r ^ $p[0], $l ^ $p[1]);
524
- }
525
-
526
- /**
527
- * Setup the performance-optimized function for de/encrypt()
528
- *
529
- * @see Crypt_Base::_setupInlineCrypt()
530
- * @access private
531
- */
532
- function _setupInlineCrypt()
533
- {
534
- $lambda_functions =& Crypt_Blowfish::_getLambdaFunctions();
535
-
536
- // We create max. 10 hi-optimized code for memory reason. Means: For each $key one ultra fast inline-crypt function.
537
- // (Currently, for Crypt_Blowfish, one generated $lambda_function cost on php5.5@32bit ~100kb unfreeable mem and ~180kb on php5.5@64bit)
538
- // After that, we'll still create very fast optimized code but not the hi-ultimative code, for each $mode one.
539
- $gen_hi_opt_code = (bool)(count($lambda_functions) < 10);
540
-
541
- // Generation of a unique hash for our generated code
542
- $code_hash = "Crypt_Blowfish, {$this->mode}";
543
- if ($gen_hi_opt_code) {
544
- $code_hash = str_pad($code_hash, 32) . $this->_hashInlineCryptFunction($this->key);
545
- }
546
-
547
- // on 32-bit linux systems with PHP < 5.3 float to integer conversion is bad
548
- switch (true) {
549
- case defined('PHP_INT_SIZE') && PHP_INT_SIZE == 8:
550
- case version_compare(PHP_VERSION, '5.3.0') >= 0:
551
- case (PHP_OS & "\xDF\xDF\xDF") === 'WIN':
552
- $safeint = '%s';
553
- break;
554
- default:
555
- $safeint = '(is_int($temp = %s) ? $temp : (fmod($temp, 0x80000000) & 0x7FFFFFFF) | ';
556
- $safeint.= '((fmod(floor($temp / 0x80000000), 2) & 1) << 31))';
557
- }
558
-
559
- if (!isset($lambda_functions[$code_hash])) {
560
- switch (true) {
561
- case $gen_hi_opt_code:
562
- $p = $this->bctx['p'];
563
- $init_crypt = '
564
- static $sb_0, $sb_1, $sb_2, $sb_3;
565
- if (!$sb_0) {
566
- $sb_0 = $self->bctx["sb"][0];
567
- $sb_1 = $self->bctx["sb"][1];
568
- $sb_2 = $self->bctx["sb"][2];
569
- $sb_3 = $self->bctx["sb"][3];
570
- }
571
- ';
572
- break;
573
- default:
574
- $p = array();
575
- for ($i = 0; $i < 18; ++$i) {
576
- $p[] = '$p_' . $i;
577
- }
578
- $init_crypt = '
579
- list($sb_0, $sb_1, $sb_2, $sb_3) = $self->bctx["sb"];
580
- list(' . implode(',', $p) . ') = $self->bctx["p"];
581
-
582
- ';
583
- }
584
-
585
- // Generating encrypt code:
586
- $encrypt_block = '
587
- $in = unpack("N*", $in);
588
- $l = $in[1];
589
- $r = $in[2];
590
- ';
591
- for ($i = 0; $i < 16; $i+= 2) {
592
- $encrypt_block.= '
593
- $l^= ' . $p[$i] . ';
594
- $r^= ' . sprintf($safeint, '(' . sprintf($safeint, '$sb_0[$l >> 24 & 0xff] + $sb_1[$l >> 16 & 0xff]') . ' ^
595
- $sb_2[$l >> 8 & 0xff]) +
596
- $sb_3[$l & 0xff]') . ';
597
-
598
- $r^= ' . $p[$i + 1] . ';
599
- $l^= ' . sprintf($safeint, '(' . sprintf($safeint, '$sb_0[$r >> 24 & 0xff] + $sb_1[$r >> 16 & 0xff]') . ' ^
600
- $sb_2[$r >> 8 & 0xff]) +
601
- $sb_3[$r & 0xff]') . ';
602
- ';
603
- }
604
- $encrypt_block.= '
605
- $in = pack("N*",
606
- $r ^ ' . $p[17] . ',
607
- $l ^ ' . $p[16] . '
608
- );
609
- ';
610
-
611
- // Generating decrypt code:
612
- $decrypt_block = '
613
- $in = unpack("N*", $in);
614
- $l = $in[1];
615
- $r = $in[2];
616
- ';
617
-
618
- for ($i = 17; $i > 2; $i-= 2) {
619
- $decrypt_block.= '
620
- $l^= ' . $p[$i] . ';
621
- $r^= ' . sprintf($safeint, '(' . sprintf($safeint, '$sb_0[$l >> 24 & 0xff] + $sb_1[$l >> 16 & 0xff]') . ' ^
622
- $sb_2[$l >> 8 & 0xff]) +
623
- $sb_3[$l & 0xff]') . ';
624
-
625
- $r^= ' . $p[$i - 1] . ';
626
- $l^= ' . sprintf($safeint, '(' . sprintf($safeint, '$sb_0[$r >> 24 & 0xff] + $sb_1[$r >> 16 & 0xff]') . ' ^
627
- $sb_2[$r >> 8 & 0xff]) +
628
- $sb_3[$r & 0xff]') . ';
629
- ';
630
- }
631
-
632
- $decrypt_block.= '
633
- $in = pack("N*",
634
- $r ^ ' . $p[0] . ',
635
- $l ^ ' . $p[1] . '
636
- );
637
- ';
638
-
639
- $lambda_functions[$code_hash] = $this->_createInlineCryptFunction(
640
- array(
641
- 'init_crypt' => $init_crypt,
642
- 'init_encrypt' => '',
643
- 'init_decrypt' => '',
644
- 'encrypt_block' => $encrypt_block,
645
- 'decrypt_block' => $decrypt_block
646
- )
647
- );
648
- }
649
- $this->inline_crypt = $lambda_functions[$code_hash];
650
- }
651
-
652
- /**
653
- * Convert float to int
654
- *
655
- * On 32-bit Linux installs running PHP < 5.3 converting floats to ints doesn't always work
656
- *
657
- * @access private
658
- * @param string $x
659
- * @return int
660
- */
661
- function safe_intval($x)
662
- {
663
- // PHP 5.3, per http://php.net/releases/5_3_0.php, introduced "more consistent float rounding"
664
- // PHP_OS & "\xDF\xDF\xDF" == strtoupper(substr(PHP_OS, 0, 3)), but a lot faster
665
- if (is_int($x) || version_compare(PHP_VERSION, '5.3.0') >= 0 || (PHP_OS & "\xDF\xDF\xDF") === 'WIN') {
666
- return $x;
667
- }
668
- return (fmod($x, 0x80000000) & 0x7FFFFFFF) |
669
- ((fmod(floor($x / 0x80000000), 2) & 1) << 31);
670
- }
671
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/phpseclib/Crypt/DES.php DELETED
@@ -1,1516 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Pure-PHP implementation of DES.
5
- *
6
- * Uses mcrypt, if available, and an internal implementation, otherwise.
7
- *
8
- * PHP versions 4 and 5
9
- *
10
- * Useful resources are as follows:
11
- *
12
- * - {@link http://en.wikipedia.org/wiki/DES_supplementary_material Wikipedia: DES supplementary material}
13
- * - {@link http://www.itl.nist.gov/fipspubs/fip46-2.htm FIPS 46-2 - (DES), Data Encryption Standard}
14
- * - {@link http://www.cs.eku.edu/faculty/styer/460/Encrypt/JS-DES.html JavaScript DES Example}
15
- *
16
- * Here's a short example of how to use this library:
17
- * <code>
18
- * <?php
19
- * include 'Crypt/DES.php';
20
- *
21
- * $des = new Crypt_DES();
22
- *
23
- * $des->setKey('abcdefgh');
24
- *
25
- * $size = 10 * 1024;
26
- * $plaintext = '';
27
- * for ($i = 0; $i < $size; $i++) {
28
- * $plaintext.= 'a';
29
- * }
30
- *
31
- * echo $des->decrypt($des->encrypt($plaintext));
32
- * ?>
33
- * </code>
34
- *
35
- * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
36
- * of this software and associated documentation files (the "Software"), to deal
37
- * in the Software without restriction, including without limitation the rights
38
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
39
- * copies of the Software, and to permit persons to whom the Software is
40
- * furnished to do so, subject to the following conditions:
41
- *
42
- * The above copyright notice and this permission notice shall be included in
43
- * all copies or substantial portions of the Software.
44
- *
45
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
46
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
47
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
48
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
49
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
50
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
51
- * THE SOFTWARE.
52
- *
53
- * @category Crypt
54
- * @package Crypt_DES
55
- * @author Jim Wigginton <terrafrost@php.net>
56
- * @copyright 2007 Jim Wigginton
57
- * @license http://www.opensource.org/licenses/mit-license.html MIT License
58
- * @link http://phpseclib.sourceforge.net
59
- */
60
-
61
- /**
62
- * Include Crypt_Base
63
- *
64
- * Base cipher class
65
- */
66
- if (!class_exists('Crypt_Base')) {
67
- include_once 'Base.php';
68
- }
69
-
70
- /**#@+
71
- * @access private
72
- * @see self::_setupKey()
73
- * @see self::_processBlock()
74
- */
75
- /**
76
- * Contains $keys[CRYPT_DES_ENCRYPT]
77
- */
78
- define('CRYPT_DES_ENCRYPT', 0);
79
- /**
80
- * Contains $keys[CRYPT_DES_DECRYPT]
81
- */
82
- define('CRYPT_DES_DECRYPT', 1);
83
- /**#@-*/
84
-
85
- /**#@+
86
- * @access public
87
- * @see self::encrypt()
88
- * @see self::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', CRYPT_MODE_CTR);
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', CRYPT_MODE_ECB);
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', CRYPT_MODE_CBC);
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', CRYPT_MODE_CFB);
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', CRYPT_MODE_OFB);
122
- /**#@-*/
123
-
124
- /**
125
- * Pure-PHP implementation of DES.
126
- *
127
- * @package Crypt_DES
128
- * @author Jim Wigginton <terrafrost@php.net>
129
- * @access public
130
- */
131
- class Crypt_DES extends Crypt_Base
132
- {
133
- /**
134
- * Block Length of the cipher
135
- *
136
- * @see Crypt_Base::block_size
137
- * @var int
138
- * @access private
139
- */
140
- var $block_size = 8;
141
-
142
- /**
143
- * Key Length (in bytes)
144
- *
145
- * @see Crypt_Base::setKeyLength()
146
- * @var int
147
- * @access private
148
- */
149
- var $key_length = 8;
150
-
151
- /**
152
- * The namespace used by the cipher for its constants.
153
- *
154
- * @see Crypt_Base::const_namespace
155
- * @var string
156
- * @access private
157
- */
158
- var $const_namespace = 'DES';
159
-
160
- /**
161
- * The mcrypt specific name of the cipher
162
- *
163
- * @see Crypt_Base::cipher_name_mcrypt
164
- * @var string
165
- * @access private
166
- */
167
- var $cipher_name_mcrypt = 'des';
168
-
169
- /**
170
- * The OpenSSL names of the cipher / modes
171
- *
172
- * @see Crypt_Base::openssl_mode_names
173
- * @var array
174
- * @access private
175
- */
176
- var $openssl_mode_names = array(
177
- CRYPT_MODE_ECB => 'des-ecb',
178
- CRYPT_MODE_CBC => 'des-cbc',
179
- CRYPT_MODE_CFB => 'des-cfb',
180
- CRYPT_MODE_OFB => 'des-ofb'
181
- // CRYPT_MODE_CTR is undefined for DES
182
- );
183
-
184
- /**
185
- * Optimizing value while CFB-encrypting
186
- *
187
- * @see Crypt_Base::cfb_init_len
188
- * @var int
189
- * @access private
190
- */
191
- var $cfb_init_len = 500;
192
-
193
- /**
194
- * Switch for DES/3DES encryption
195
- *
196
- * Used only if $engine == CRYPT_DES_MODE_INTERNAL
197
- *
198
- * @see self::_setupKey()
199
- * @see self::_processBlock()
200
- * @var int
201
- * @access private
202
- */
203
- var $des_rounds = 1;
204
-
205
- /**
206
- * max possible size of $key
207
- *
208
- * @see self::setKey()
209
- * @var string
210
- * @access private
211
- */
212
- var $key_length_max = 8;
213
-
214
- /**
215
- * The Key Schedule
216
- *
217
- * @see self::_setupKey()
218
- * @var array
219
- * @access private
220
- */
221
- var $keys;
222
-
223
- /**
224
- * Shuffle table.
225
- *
226
- * For each byte value index, the entry holds an 8-byte string
227
- * with each byte containing all bits in the same state as the
228
- * corresponding bit in the index value.
229
- *
230
- * @see self::_processBlock()
231
- * @see self::_setupKey()
232
- * @var array
233
- * @access private
234
- */
235
- var $shuffle = array(
236
- "\x00\x00\x00\x00\x00\x00\x00\x00", "\x00\x00\x00\x00\x00\x00\x00\xFF",
237
- "\x00\x00\x00\x00\x00\x00\xFF\x00", "\x00\x00\x00\x00\x00\x00\xFF\xFF",
238
- "\x00\x00\x00\x00\x00\xFF\x00\x00", "\x00\x00\x00\x00\x00\xFF\x00\xFF",
239
- "\x00\x00\x00\x00\x00\xFF\xFF\x00", "\x00\x00\x00\x00\x00\xFF\xFF\xFF",
240
- "\x00\x00\x00\x00\xFF\x00\x00\x00", "\x00\x00\x00\x00\xFF\x00\x00\xFF",
241
- "\x00\x00\x00\x00\xFF\x00\xFF\x00", "\x00\x00\x00\x00\xFF\x00\xFF\xFF",
242
- "\x00\x00\x00\x00\xFF\xFF\x00\x00", "\x00\x00\x00\x00\xFF\xFF\x00\xFF",
243
- "\x00\x00\x00\x00\xFF\xFF\xFF\x00", "\x00\x00\x00\x00\xFF\xFF\xFF\xFF",
244
- "\x00\x00\x00\xFF\x00\x00\x00\x00", "\x00\x00\x00\xFF\x00\x00\x00\xFF",
245
- "\x00\x00\x00\xFF\x00\x00\xFF\x00", "\x00\x00\x00\xFF\x00\x00\xFF\xFF",
246
- "\x00\x00\x00\xFF\x00\xFF\x00\x00", "\x00\x00\x00\xFF\x00\xFF\x00\xFF",
247
- "\x00\x00\x00\xFF\x00\xFF\xFF\x00", "\x00\x00\x00\xFF\x00\xFF\xFF\xFF",
248
- "\x00\x00\x00\xFF\xFF\x00\x00\x00", "\x00\x00\x00\xFF\xFF\x00\x00\xFF",
249
- "\x00\x00\x00\xFF\xFF\x00\xFF\x00", "\x00\x00\x00\xFF\xFF\x00\xFF\xFF",
250
- "\x00\x00\x00\xFF\xFF\xFF\x00\x00", "\x00\x00\x00\xFF\xFF\xFF\x00\xFF",
251
- "\x00\x00\x00\xFF\xFF\xFF\xFF\x00", "\x00\x00\x00\xFF\xFF\xFF\xFF\xFF",
252
- "\x00\x00\xFF\x00\x00\x00\x00\x00", "\x00\x00\xFF\x00\x00\x00\x00\xFF",
253
- "\x00\x00\xFF\x00\x00\x00\xFF\x00", "\x00\x00\xFF\x00\x00\x00\xFF\xFF",
254
- "\x00\x00\xFF\x00\x00\xFF\x00\x00", "\x00\x00\xFF\x00\x00\xFF\x00\xFF",
255
- "\x00\x00\xFF\x00\x00\xFF\xFF\x00", "\x00\x00\xFF\x00\x00\xFF\xFF\xFF",
256
- "\x00\x00\xFF\x00\xFF\x00\x00\x00", "\x00\x00\xFF\x00\xFF\x00\x00\xFF",
257
- "\x00\x00\xFF\x00\xFF\x00\xFF\x00", "\x00\x00\xFF\x00\xFF\x00\xFF\xFF",
258
- "\x00\x00\xFF\x00\xFF\xFF\x00\x00", "\x00\x00\xFF\x00\xFF\xFF\x00\xFF",
259
- "\x00\x00\xFF\x00\xFF\xFF\xFF\x00", "\x00\x00\xFF\x00\xFF\xFF\xFF\xFF",
260
- "\x00\x00\xFF\xFF\x00\x00\x00\x00", "\x00\x00\xFF\xFF\x00\x00\x00\xFF",
261
- "\x00\x00\xFF\xFF\x00\x00\xFF\x00", "\x00\x00\xFF\xFF\x00\x00\xFF\xFF",
262
- "\x00\x00\xFF\xFF\x00\xFF\x00\x00", "\x00\x00\xFF\xFF\x00\xFF\x00\xFF",
263
- "\x00\x00\xFF\xFF\x00\xFF\xFF\x00", "\x00\x00\xFF\xFF\x00\xFF\xFF\xFF",
264
- "\x00\x00\xFF\xFF\xFF\x00\x00\x00", "\x00\x00\xFF\xFF\xFF\x00\x00\xFF",
265
- "\x00\x00\xFF\xFF\xFF\x00\xFF\x00", "\x00\x00\xFF\xFF\xFF\x00\xFF\xFF",
266
- "\x00\x00\xFF\xFF\xFF\xFF\x00\x00", "\x00\x00\xFF\xFF\xFF\xFF\x00\xFF",
267
- "\x00\x00\xFF\xFF\xFF\xFF\xFF\x00", "\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF",
268
- "\x00\xFF\x00\x00\x00\x00\x00\x00", "\x00\xFF\x00\x00\x00\x00\x00\xFF",
269
- "\x00\xFF\x00\x00\x00\x00\xFF\x00", "\x00\xFF\x00\x00\x00\x00\xFF\xFF",
270
- "\x00\xFF\x00\x00\x00\xFF\x00\x00", "\x00\xFF\x00\x00\x00\xFF\x00\xFF",
271
- "\x00\xFF\x00\x00\x00\xFF\xFF\x00", "\x00\xFF\x00\x00\x00\xFF\xFF\xFF",
272
- "\x00\xFF\x00\x00\xFF\x00\x00\x00", "\x00\xFF\x00\x00\xFF\x00\x00\xFF",
273
- "\x00\xFF\x00\x00\xFF\x00\xFF\x00", "\x00\xFF\x00\x00\xFF\x00\xFF\xFF",
274
- "\x00\xFF\x00\x00\xFF\xFF\x00\x00", "\x00\xFF\x00\x00\xFF\xFF\x00\xFF",
275
- "\x00\xFF\x00\x00\xFF\xFF\xFF\x00", "\x00\xFF\x00\x00\xFF\xFF\xFF\xFF",
276
- "\x00\xFF\x00\xFF\x00\x00\x00\x00", "\x00\xFF\x00\xFF\x00\x00\x00\xFF",
277
- "\x00\xFF\x00\xFF\x00\x00\xFF\x00", "\x00\xFF\x00\xFF\x00\x00\xFF\xFF",
278
- "\x00\xFF\x00\xFF\x00\xFF\x00\x00", "\x00\xFF\x00\xFF\x00\xFF\x00\xFF",
279
- "\x00\xFF\x00\xFF\x00\xFF\xFF\x00", "\x00\xFF\x00\xFF\x00\xFF\xFF\xFF",
280
- "\x00\xFF\x00\xFF\xFF\x00\x00\x00", "\x00\xFF\x00\xFF\xFF\x00\x00\xFF",
281
- "\x00\xFF\x00\xFF\xFF\x00\xFF\x00", "\x00\xFF\x00\xFF\xFF\x00\xFF\xFF",
282
- "\x00\xFF\x00\xFF\xFF\xFF\x00\x00", "\x00\xFF\x00\xFF\xFF\xFF\x00\xFF",
283
- "\x00\xFF\x00\xFF\xFF\xFF\xFF\x00", "\x00\xFF\x00\xFF\xFF\xFF\xFF\xFF",
284
- "\x00\xFF\xFF\x00\x00\x00\x00\x00", "\x00\xFF\xFF\x00\x00\x00\x00\xFF",
285
- "\x00\xFF\xFF\x00\x00\x00\xFF\x00", "\x00\xFF\xFF\x00\x00\x00\xFF\xFF",
286
- "\x00\xFF\xFF\x00\x00\xFF\x00\x00", "\x00\xFF\xFF\x00\x00\xFF\x00\xFF",
287
- "\x00\xFF\xFF\x00\x00\xFF\xFF\x00", "\x00\xFF\xFF\x00\x00\xFF\xFF\xFF",
288
- "\x00\xFF\xFF\x00\xFF\x00\x00\x00", "\x00\xFF\xFF\x00\xFF\x00\x00\xFF",
289
- "\x00\xFF\xFF\x00\xFF\x00\xFF\x00", "\x00\xFF\xFF\x00\xFF\x00\xFF\xFF",
290
- "\x00\xFF\xFF\x00\xFF\xFF\x00\x00", "\x00\xFF\xFF\x00\xFF\xFF\x00\xFF",
291
- "\x00\xFF\xFF\x00\xFF\xFF\xFF\x00", "\x00\xFF\xFF\x00\xFF\xFF\xFF\xFF",
292
- "\x00\xFF\xFF\xFF\x00\x00\x00\x00", "\x00\xFF\xFF\xFF\x00\x00\x00\xFF",
293
- "\x00\xFF\xFF\xFF\x00\x00\xFF\x00", "\x00\xFF\xFF\xFF\x00\x00\xFF\xFF",
294
- "\x00\xFF\xFF\xFF\x00\xFF\x00\x00", "\x00\xFF\xFF\xFF\x00\xFF\x00\xFF",
295
- "\x00\xFF\xFF\xFF\x00\xFF\xFF\x00", "\x00\xFF\xFF\xFF\x00\xFF\xFF\xFF",
296
- "\x00\xFF\xFF\xFF\xFF\x00\x00\x00", "\x00\xFF\xFF\xFF\xFF\x00\x00\xFF",
297
- "\x00\xFF\xFF\xFF\xFF\x00\xFF\x00", "\x00\xFF\xFF\xFF\xFF\x00\xFF\xFF",
298
- "\x00\xFF\xFF\xFF\xFF\xFF\x00\x00", "\x00\xFF\xFF\xFF\xFF\xFF\x00\xFF",
299
- "\x00\xFF\xFF\xFF\xFF\xFF\xFF\x00", "\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF",
300
- "\xFF\x00\x00\x00\x00\x00\x00\x00", "\xFF\x00\x00\x00\x00\x00\x00\xFF",
301
- "\xFF\x00\x00\x00\x00\x00\xFF\x00", "\xFF\x00\x00\x00\x00\x00\xFF\xFF",
302
- "\xFF\x00\x00\x00\x00\xFF\x00\x00", "\xFF\x00\x00\x00\x00\xFF\x00\xFF",
303
- "\xFF\x00\x00\x00\x00\xFF\xFF\x00", "\xFF\x00\x00\x00\x00\xFF\xFF\xFF",
304
- "\xFF\x00\x00\x00\xFF\x00\x00\x00", "\xFF\x00\x00\x00\xFF\x00\x00\xFF",
305
- "\xFF\x00\x00\x00\xFF\x00\xFF\x00", "\xFF\x00\x00\x00\xFF\x00\xFF\xFF",
306
- "\xFF\x00\x00\x00\xFF\xFF\x00\x00", "\xFF\x00\x00\x00\xFF\xFF\x00\xFF",
307
- "\xFF\x00\x00\x00\xFF\xFF\xFF\x00", "\xFF\x00\x00\x00\xFF\xFF\xFF\xFF",
308
- "\xFF\x00\x00\xFF\x00\x00\x00\x00", "\xFF\x00\x00\xFF\x00\x00\x00\xFF",
309
- "\xFF\x00\x00\xFF\x00\x00\xFF\x00", "\xFF\x00\x00\xFF\x00\x00\xFF\xFF",
310
- "\xFF\x00\x00\xFF\x00\xFF\x00\x00", "\xFF\x00\x00\xFF\x00\xFF\x00\xFF",
311
- "\xFF\x00\x00\xFF\x00\xFF\xFF\x00", "\xFF\x00\x00\xFF\x00\xFF\xFF\xFF",
312
- "\xFF\x00\x00\xFF\xFF\x00\x00\x00", "\xFF\x00\x00\xFF\xFF\x00\x00\xFF",
313
- "\xFF\x00\x00\xFF\xFF\x00\xFF\x00", "\xFF\x00\x00\xFF\xFF\x00\xFF\xFF",
314
- "\xFF\x00\x00\xFF\xFF\xFF\x00\x00", "\xFF\x00\x00\xFF\xFF\xFF\x00\xFF",
315
- "\xFF\x00\x00\xFF\xFF\xFF\xFF\x00", "\xFF\x00\x00\xFF\xFF\xFF\xFF\xFF",
316
- "\xFF\x00\xFF\x00\x00\x00\x00\x00", "\xFF\x00\xFF\x00\x00\x00\x00\xFF",
317
- "\xFF\x00\xFF\x00\x00\x00\xFF\x00", "\xFF\x00\xFF\x00\x00\x00\xFF\xFF",
318
- "\xFF\x00\xFF\x00\x00\xFF\x00\x00", "\xFF\x00\xFF\x00\x00\xFF\x00\xFF",
319
- "\xFF\x00\xFF\x00\x00\xFF\xFF\x00", "\xFF\x00\xFF\x00\x00\xFF\xFF\xFF",
320
- "\xFF\x00\xFF\x00\xFF\x00\x00\x00", "\xFF\x00\xFF\x00\xFF\x00\x00\xFF",
321
- "\xFF\x00\xFF\x00\xFF\x00\xFF\x00", "\xFF\x00\xFF\x00\xFF\x00\xFF\xFF",
322
- "\xFF\x00\xFF\x00\xFF\xFF\x00\x00", "\xFF\x00\xFF\x00\xFF\xFF\x00\xFF",
323
- "\xFF\x00\xFF\x00\xFF\xFF\xFF\x00", "\xFF\x00\xFF\x00\xFF\xFF\xFF\xFF",
324
- "\xFF\x00\xFF\xFF\x00\x00\x00\x00", "\xFF\x00\xFF\xFF\x00\x00\x00\xFF",
325
- "\xFF\x00\xFF\xFF\x00\x00\xFF\x00", "\xFF\x00\xFF\xFF\x00\x00\xFF\xFF",
326
- "\xFF\x00\xFF\xFF\x00\xFF\x00\x00", "\xFF\x00\xFF\xFF\x00\xFF\x00\xFF",
327
- "\xFF\x00\xFF\xFF\x00\xFF\xFF\x00", "\xFF\x00\xFF\xFF\x00\xFF\xFF\xFF",
328
- "\xFF\x00\xFF\xFF\xFF\x00\x00\x00", "\xFF\x00\xFF\xFF\xFF\x00\x00\xFF",
329
- "\xFF\x00\xFF\xFF\xFF\x00\xFF\x00", "\xFF\x00\xFF\xFF\xFF\x00\xFF\xFF",
330
- "\xFF\x00\xFF\xFF\xFF\xFF\x00\x00", "\xFF\x00\xFF\xFF\xFF\xFF\x00\xFF",
331
- "\xFF\x00\xFF\xFF\xFF\xFF\xFF\x00", "\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF",
332
- "\xFF\xFF\x00\x00\x00\x00\x00\x00", "\xFF\xFF\x00\x00\x00\x00\x00\xFF",
333
- "\xFF\xFF\x00\x00\x00\x00\xFF\x00", "\xFF\xFF\x00\x00\x00\x00\xFF\xFF",
334
- "\xFF\xFF\x00\x00\x00\xFF\x00\x00", "\xFF\xFF\x00\x00\x00\xFF\x00\xFF",
335
- "\xFF\xFF\x00\x00\x00\xFF\xFF\x00", "\xFF\xFF\x00\x00\x00\xFF\xFF\xFF",
336
- "\xFF\xFF\x00\x00\xFF\x00\x00\x00", "\xFF\xFF\x00\x00\xFF\x00\x00\xFF",
337
- "\xFF\xFF\x00\x00\xFF\x00\xFF\x00", "\xFF\xFF\x00\x00\xFF\x00\xFF\xFF",
338
- "\xFF\xFF\x00\x00\xFF\xFF\x00\x00", "\xFF\xFF\x00\x00\xFF\xFF\x00\xFF",
339
- "\xFF\xFF\x00\x00\xFF\xFF\xFF\x00", "\xFF\xFF\x00\x00\xFF\xFF\xFF\xFF",
340
- "\xFF\xFF\x00\xFF\x00\x00\x00\x00", "\xFF\xFF\x00\xFF\x00\x00\x00\xFF",
341
- "\xFF\xFF\x00\xFF\x00\x00\xFF\x00", "\xFF\xFF\x00\xFF\x00\x00\xFF\xFF",
342
- "\xFF\xFF\x00\xFF\x00\xFF\x00\x00", "\xFF\xFF\x00\xFF\x00\xFF\x00\xFF",
343
- "\xFF\xFF\x00\xFF\x00\xFF\xFF\x00", "\xFF\xFF\x00\xFF\x00\xFF\xFF\xFF",
344
- "\xFF\xFF\x00\xFF\xFF\x00\x00\x00", "\xFF\xFF\x00\xFF\xFF\x00\x00\xFF",
345
- "\xFF\xFF\x00\xFF\xFF\x00\xFF\x00", "\xFF\xFF\x00\xFF\xFF\x00\xFF\xFF",
346
- "\xFF\xFF\x00\xFF\xFF\xFF\x00\x00", "\xFF\xFF\x00\xFF\xFF\xFF\x00\xFF",
347
- "\xFF\xFF\x00\xFF\xFF\xFF\xFF\x00", "\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF",
348
- "\xFF\xFF\xFF\x00\x00\x00\x00\x00", "\xFF\xFF\xFF\x00\x00\x00\x00\xFF",
349
- "\xFF\xFF\xFF\x00\x00\x00\xFF\x00", "\xFF\xFF\xFF\x00\x00\x00\xFF\xFF",
350
- "\xFF\xFF\xFF\x00\x00\xFF\x00\x00", "\xFF\xFF\xFF\x00\x00\xFF\x00\xFF",
351
- "\xFF\xFF\xFF\x00\x00\xFF\xFF\x00", "\xFF\xFF\xFF\x00\x00\xFF\xFF\xFF",
352
- "\xFF\xFF\xFF\x00\xFF\x00\x00\x00", "\xFF\xFF\xFF\x00\xFF\x00\x00\xFF",
353
- "\xFF\xFF\xFF\x00\xFF\x00\xFF\x00", "\xFF\xFF\xFF\x00\xFF\x00\xFF\xFF",
354
- "\xFF\xFF\xFF\x00\xFF\xFF\x00\x00", "\xFF\xFF\xFF\x00\xFF\xFF\x00\xFF",
355
- "\xFF\xFF\xFF\x00\xFF\xFF\xFF\x00", "\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF",
356
- "\xFF\xFF\xFF\xFF\x00\x00\x00\x00", "\xFF\xFF\xFF\xFF\x00\x00\x00\xFF",
357
- "\xFF\xFF\xFF\xFF\x00\x00\xFF\x00", "\xFF\xFF\xFF\xFF\x00\x00\xFF\xFF",
358
- "\xFF\xFF\xFF\xFF\x00\xFF\x00\x00", "\xFF\xFF\xFF\xFF\x00\xFF\x00\xFF",
359
- "\xFF\xFF\xFF\xFF\x00\xFF\xFF\x00", "\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF",
360
- "\xFF\xFF\xFF\xFF\xFF\x00\x00\x00", "\xFF\xFF\xFF\xFF\xFF\x00\x00\xFF",
361
- "\xFF\xFF\xFF\xFF\xFF\x00\xFF\x00", "\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF",
362
- "\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00", "\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF",
363
- "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00", "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
364
- );
365
-
366
- /**
367
- * IP mapping helper table.
368
- *
369
- * Indexing this table with each source byte performs the initial bit permutation.
370
- *
371
- * @var array
372
- * @access private
373
- */
374
- var $ipmap = array(
375
- 0x00, 0x10, 0x01, 0x11, 0x20, 0x30, 0x21, 0x31,
376
- 0x02, 0x12, 0x03, 0x13, 0x22, 0x32, 0x23, 0x33,
377
- 0x40, 0x50, 0x41, 0x51, 0x60, 0x70, 0x61, 0x71,
378
- 0x42, 0x52, 0x43, 0x53, 0x62, 0x72, 0x63, 0x73,
379
- 0x04, 0x14, 0x05, 0x15, 0x24, 0x34, 0x25, 0x35,
380
- 0x06, 0x16, 0x07, 0x17, 0x26, 0x36, 0x27, 0x37,
381
- 0x44, 0x54, 0x45, 0x55, 0x64, 0x74, 0x65, 0x75,
382
- 0x46, 0x56, 0x47, 0x57, 0x66, 0x76, 0x67, 0x77,
383
- 0x80, 0x90, 0x81, 0x91, 0xA0, 0xB0, 0xA1, 0xB1,
384
- 0x82, 0x92, 0x83, 0x93, 0xA2, 0xB2, 0xA3, 0xB3,
385
- 0xC0, 0xD0, 0xC1, 0xD1, 0xE0, 0xF0, 0xE1, 0xF1,
386
- 0xC2, 0xD2, 0xC3, 0xD3, 0xE2, 0xF2, 0xE3, 0xF3,
387
- 0x84, 0x94, 0x85, 0x95, 0xA4, 0xB4, 0xA5, 0xB5,
388
- 0x86, 0x96, 0x87, 0x97, 0xA6, 0xB6, 0xA7, 0xB7,
389
- 0xC4, 0xD4, 0xC5, 0xD5, 0xE4, 0xF4, 0xE5, 0xF5,
390
- 0xC6, 0xD6, 0xC7, 0xD7, 0xE6, 0xF6, 0xE7, 0xF7,
391
- 0x08, 0x18, 0x09, 0x19, 0x28, 0x38, 0x29, 0x39,
392
- 0x0A, 0x1A, 0x0B, 0x1B, 0x2A, 0x3A, 0x2B, 0x3B,
393
- 0x48, 0x58, 0x49, 0x59, 0x68, 0x78, 0x69, 0x79,
394
- 0x4A, 0x5A, 0x4B, 0x5B, 0x6A, 0x7A, 0x6B, 0x7B,
395
- 0x0C, 0x1C, 0x0D, 0x1D, 0x2C, 0x3C, 0x2D, 0x3D,
396
- 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
397
- 0x4C, 0x5C, 0x4D, 0x5D, 0x6C, 0x7C, 0x6D, 0x7D,
398
- 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
399
- 0x88, 0x98, 0x89, 0x99, 0xA8, 0xB8, 0xA9, 0xB9,
400
- 0x8A, 0x9A, 0x8B, 0x9B, 0xAA, 0xBA, 0xAB, 0xBB,
401
- 0xC8, 0xD8, 0xC9, 0xD9, 0xE8, 0xF8, 0xE9, 0xF9,
402
- 0xCA, 0xDA, 0xCB, 0xDB, 0xEA, 0xFA, 0xEB, 0xFB,
403
- 0x8C, 0x9C, 0x8D, 0x9D, 0xAC, 0xBC, 0xAD, 0xBD,
404
- 0x8E, 0x9E, 0x8F, 0x9F, 0xAE, 0xBE, 0xAF, 0xBF,
405
- 0xCC, 0xDC, 0xCD, 0xDD, 0xEC, 0xFC, 0xED, 0xFD,
406
- 0xCE, 0xDE, 0xCF, 0xDF, 0xEE, 0xFE, 0xEF, 0xFF
407
- );
408
-
409
- /**
410
- * Inverse IP mapping helper table.
411
- * Indexing this table with a byte value reverses the bit order.
412
- *
413
- * @var array
414
- * @access private
415
- */
416
- var $invipmap = array(
417
- 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0,
418
- 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
419
- 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,
420
- 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
421
- 0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4,
422
- 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
423
- 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC,
424
- 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
425
- 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2,
426
- 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
427
- 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA,
428
- 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
429
- 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6,
430
- 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
431
- 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE,
432
- 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
433
- 0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1,
434
- 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
435
- 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9,
436
- 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
437
- 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5,
438
- 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
439
- 0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED,
440
- 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
441
- 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3,
442
- 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
443
- 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB,
444
- 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
445
- 0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7,
446
- 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
447
- 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF,
448
- 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
449
- );
450
-
451
- /**
452
- * Pre-permuted S-box1
453
- *
454
- * Each box ($sbox1-$sbox8) has been vectorized, then each value pre-permuted using the
455
- * P table: concatenation can then be replaced by exclusive ORs.
456
- *
457
- * @var array
458
- * @access private
459
- */
460
- var $sbox1 = array(
461
- 0x00808200, 0x00000000, 0x00008000, 0x00808202,
462
- 0x00808002, 0x00008202, 0x00000002, 0x00008000,
463
- 0x00000200, 0x00808200, 0x00808202, 0x00000200,
464
- 0x00800202, 0x00808002, 0x00800000, 0x00000002,
465
- 0x00000202, 0x00800200, 0x00800200, 0x00008200,
466
- 0x00008200, 0x00808000, 0x00808000, 0x00800202,
467
- 0x00008002, 0x00800002, 0x00800002, 0x00008002,
468
- 0x00000000, 0x00000202, 0x00008202, 0x00800000,
469
- 0x00008000, 0x00808202, 0x00000002, 0x00808000,
470
- 0x00808200, 0x00800000, 0x00800000, 0x00000200,
471
- 0x00808002, 0x00008000, 0x00008200, 0x00800002,
472
- 0x00000200, 0x00000002, 0x00800202, 0x00008202,
473
- 0x00808202, 0x00008002, 0x00808000, 0x00800202,
474
- 0x00800002, 0x00000202, 0x00008202, 0x00808200,
475
- 0x00000202, 0x00800200, 0x00800200, 0x00000000,
476
- 0x00008002, 0x00008200, 0x00000000, 0x00808002
477
- );
478
-
479
- /**
480
- * Pre-permuted S-box2
481
- *
482
- * @var array
483
- * @access private
484
- */
485
- var $sbox2 = array(
486
- 0x40084010, 0x40004000, 0x00004000, 0x00084010,
487
- 0x00080000, 0x00000010, 0x40080010, 0x40004010,
488
- 0x40000010, 0x40084010, 0x40084000, 0x40000000,
489
- 0x40004000, 0x00080000, 0x00000010, 0x40080010,
490
- 0x00084000, 0x00080010, 0x40004010, 0x00000000,
491
- 0x40000000, 0x00004000, 0x00084010, 0x40080000,
492
- 0x00080010, 0x40000010, 0x00000000, 0x00084000,
493
- 0x00004010, 0x40084000, 0x40080000, 0x00004010,
494
- 0x00000000, 0x00084010, 0x40080010, 0x00080000,
495
- 0x40004010, 0x40080000, 0x40084000, 0x00004000,
496
- 0x40080000, 0x40004000, 0x00000010, 0x40084010,
497
- 0x00084010, 0x00000010, 0x00004000, 0x40000000,
498
- 0x00004010, 0x40084000, 0x00080000, 0x40000010,
499
- 0x00080010, 0x40004010, 0x40000010, 0x00080010,
500
- 0x00084000, 0x00000000, 0x40004000, 0x00004010,
501
- 0x40000000, 0x40080010, 0x40084010, 0x00084000
502
- );
503
-
504
- /**
505
- * Pre-permuted S-box3
506
- *
507
- * @var array
508
- * @access private
509
- */
510
- var $sbox3 = array(
511
- 0x00000104, 0x04010100, 0x00000000, 0x04010004,
512
- 0x04000100, 0x00000000, 0x00010104, 0x04000100,
513
- 0x00010004, 0x04000004, 0x04000004, 0x00010000,
514
- 0x04010104, 0x00010004, 0x04010000, 0x00000104,
515
- 0x04000000, 0x00000004, 0x04010100, 0x00000100,
516
- 0x00010100, 0x04010000, 0x04010004, 0x00010104,
517
- 0x04000104, 0x00010100, 0x00010000, 0x04000104,
518
- 0x00000004, 0x04010104, 0x00000100, 0x04000000,
519
- 0x04010100, 0x04000000, 0x00010004, 0x00000104,
520
- 0x00010000, 0x04010100, 0x04000100, 0x00000000,
521
- 0x00000100, 0x00010004, 0x04010104, 0x04000100,
522
- 0x04000004, 0x00000100, 0x00000000, 0x04010004,
523
- 0x04000104, 0x00010000, 0x04000000, 0x04010104,
524
- 0x00000004, 0x00010104, 0x00010100, 0x04000004,
525
- 0x04010000, 0x04000104, 0x00000104, 0x04010000,
526
- 0x00010104, 0x00000004, 0x04010004, 0x00010100
527
- );
528
-
529
- /**
530
- * Pre-permuted S-box4
531
- *
532
- * @var array
533
- * @access private
534
- */
535
- var $sbox4 = array(
536
- 0x80401000, 0x80001040, 0x80001040, 0x00000040,
537
- 0x00401040, 0x80400040, 0x80400000, 0x80001000,
538
- 0x00000000, 0x00401000, 0x00401000, 0x80401040,
539
- 0x80000040, 0x00000000, 0x00400040, 0x80400000,
540
- 0x80000000, 0x00001000, 0x00400000, 0x80401000,
541
- 0x00000040, 0x00400000, 0x80001000, 0x00001040,
542
- 0x80400040, 0x80000000, 0x00001040, 0x00400040,
543
- 0x00001000, 0x00401040, 0x80401040, 0x80000040,
544
- 0x00400040, 0x80400000, 0x00401000, 0x80401040,
545
- 0x80000040, 0x00000000, 0x00000000, 0x00401000,
546
- 0x00001040, 0x00400040, 0x80400040, 0x80000000,
547
- 0x80401000, 0x80001040, 0x80001040, 0x00000040,
548
- 0x80401040, 0x80000040, 0x80000000, 0x00001000,
549
- 0x80400000, 0x80001000, 0x00401040, 0x80400040,
550
- 0x80001000, 0x00001040, 0x00400000, 0x80401000,
551
- 0x00000040, 0x00400000, 0x00001000, 0x00401040
552
- );
553
-
554
- /**
555
- * Pre-permuted S-box5
556
- *
557
- * @var array
558
- * @access private
559
- */
560
- var $sbox5 = array(
561
- 0x00000080, 0x01040080, 0x01040000, 0x21000080,
562
- 0x00040000, 0x00000080, 0x20000000, 0x01040000,
563
- 0x20040080, 0x00040000, 0x01000080, 0x20040080,
564
- 0x21000080, 0x21040000, 0x00040080, 0x20000000,
565
- 0x01000000, 0x20040000, 0x20040000, 0x00000000,
566
- 0x20000080, 0x21040080, 0x21040080, 0x01000080,
567
- 0x21040000, 0x20000080, 0x00000000, 0x21000000,
568
- 0x01040080, 0x01000000, 0x21000000, 0x00040080,
569
- 0x00040000, 0x21000080, 0x00000080, 0x01000000,
570
- 0x20000000, 0x01040000, 0x21000080, 0x20040080,
571
- 0x01000080, 0x20000000, 0x21040000, 0x01040080,
572
- 0x20040080, 0x00000080, 0x01000000, 0x21040000,
573
- 0x21040080, 0x00040080, 0x21000000, 0x21040080,
574
- 0x01040000, 0x00000000, 0x20040000, 0x21000000,
575
- 0x00040080, 0x01000080, 0x20000080, 0x00040000,
576
- 0x00000000, 0x20040000, 0x01040080, 0x20000080
577
- );
578
-
579
- /**
580
- * Pre-permuted S-box6
581
- *
582
- * @var array
583
- * @access private
584
- */
585
- var $sbox6 = array(
586
- 0x10000008, 0x10200000, 0x00002000, 0x10202008,
587
- 0x10200000, 0x00000008, 0x10202008, 0x00200000,
588
- 0x10002000, 0x00202008, 0x00200000, 0x10000008,
589
- 0x00200008, 0x10002000, 0x10000000, 0x00002008,
590
- 0x00000000, 0x00200008, 0x10002008, 0x00002000,
591
- 0x00202000, 0x10002008, 0x00000008, 0x10200008,
592
- 0x10200008, 0x00000000, 0x00202008, 0x10202000,
593
- 0x00002008, 0x00202000, 0x10202000, 0x10000000,
594
- 0x10002000, 0x00000008, 0x10200008, 0x00202000,
595
- 0x10202008, 0x00200000, 0x00002008, 0x10000008,
596
- 0x00200000, 0x10002000, 0x10000000, 0x00002008,
597
- 0x10000008, 0x10202008, 0x00202000, 0x10200000,
598
- 0x00202008, 0x10202000, 0x00000000, 0x10200008,
599
- 0x00000008, 0x00002000, 0x10200000, 0x00202008,
600
- 0x00002000, 0x00200008, 0x10002008, 0x00000000,
601
- 0x10202000, 0x10000000, 0x00200008, 0x10002008
602
- );
603
-
604
- /**
605
- * Pre-permuted S-box7
606
- *
607
- * @var array
608
- * @access private
609
- */
610
- var $sbox7 = array(
611
- 0x00100000, 0x02100001, 0x02000401, 0x00000000,
612
- 0x00000400, 0x02000401, 0x00100401, 0x02100400,
613
- 0x02100401, 0x00100000, 0x00000000, 0x02000001,
614
- 0x00000001, 0x02000000, 0x02100001, 0x00000401,
615
- 0x02000400, 0x00100401, 0x00100001, 0x02000400,
616
- 0x02000001, 0x02100000, 0x02100400, 0x00100001,
617
- 0x02100000, 0x00000400, 0x00000401, 0x02100401,
618
- 0x00100400, 0x00000001, 0x02000000, 0x00100400,
619
- 0x02000000, 0x00100400, 0x00100000, 0x02000401,
620
- 0x02000401, 0x02100001, 0x02100001, 0x00000001,
621
- 0x00100001, 0x02000000, 0x02000400, 0x00100000,
622
- 0x02100400, 0x00000401, 0x00100401, 0x02100400,
623
- 0x00000401, 0x02000001, 0x02100401, 0x02100000,
624
- 0x00100400, 0x00000000, 0x00000001, 0x02100401,
625
- 0x00000000, 0x00100401, 0x02100000, 0x00000400,
626
- 0x02000001, 0x02000400, 0x00000400, 0x00100001
627
- );
628
-
629
- /**
630
- * Pre-permuted S-box8
631
- *
632
- * @var array
633
- * @access private
634
- */
635
- var $sbox8 = array(
636
- 0x08000820, 0x00000800, 0x00020000, 0x08020820,
637
- 0x08000000, 0x08000820, 0x00000020, 0x08000000,
638
- 0x00020020, 0x08020000, 0x08020820, 0x00020800,
639
- 0x08020800, 0x00020820, 0x00000800, 0x00000020,
640
- 0x08020000, 0x08000020, 0x08000800, 0x00000820,
641
- 0x00020800, 0x00020020, 0x08020020, 0x08020800,
642
- 0x00000820, 0x00000000, 0x00000000, 0x08020020,
643
- 0x08000020, 0x08000800, 0x00020820, 0x00020000,
644
- 0x00020820, 0x00020000, 0x08020800, 0x00000800,
645
- 0x00000020, 0x08020020, 0x00000800, 0x00020820,
646
- 0x08000800, 0x00000020, 0x08000020, 0x08020000,
647
- 0x08020020, 0x08000000, 0x00020000, 0x08000820,
648
- 0x00000000, 0x08020820, 0x00020020, 0x08000020,
649
- 0x08020000, 0x08000800, 0x08000820, 0x00000000,
650
- 0x08020820, 0x00020800, 0x00020800, 0x00000820,
651
- 0x00000820, 0x00020020, 0x08000000, 0x08020800
652
- );
653
-
654
- /**
655
- * Test for engine validity
656
- *
657
- * This is mainly just a wrapper to set things up for Crypt_Base::isValidEngine()
658
- *
659
- * @see Crypt_Base::isValidEngine()
660
- * @param int $engine
661
- * @access public
662
- * @return bool
663
- */
664
- function isValidEngine($engine)
665
- {
666
- if ($this->key_length_max == 8) {
667
- if ($engine == CRYPT_ENGINE_OPENSSL) {
668
- $this->cipher_name_openssl_ecb = 'des-ecb';
669
- $this->cipher_name_openssl = 'des-' . $this->_openssl_translate_mode();
670
- }
671
- }
672
-
673
- return parent::isValidEngine($engine);
674
- }
675
-
676
- /**
677
- * Sets the key.
678
- *
679
- * Keys can be of any length. DES, itself, uses 64-bit keys (eg. strlen($key) == 8), however, we
680
- * only use the first eight, if $key has more then eight characters in it, and pad $key with the
681
- * null byte if it is less then eight characters long.
682
- *
683
- * DES also requires that every eighth bit be a parity bit, however, we'll ignore that.
684
- *
685
- * If the key is not explicitly set, it'll be assumed to be all zero's.
686
- *
687
- * @see Crypt_Base::setKey()
688
- * @access public
689
- * @param string $key
690
- */
691
- function setKey($key)
692
- {
693
- // We check/cut here only up to max length of the key.
694
- // Key padding to the proper length will be done in _setupKey()
695
- if (strlen($key) > $this->key_length_max) {
696
- $key = substr($key, 0, $this->key_length_max);
697
- }
698
-
699
- // Sets the key
700
- parent::setKey($key);
701
- }
702
-
703
- /**
704
- * Encrypts a block
705
- *
706
- * @see Crypt_Base::_encryptBlock()
707
- * @see Crypt_Base::encrypt()
708
- * @see self::encrypt()
709
- * @access private
710
- * @param string $in
711
- * @return string
712
- */
713
- function _encryptBlock($in)
714
- {
715
- return $this->_processBlock($in, CRYPT_DES_ENCRYPT);
716
- }
717
-
718
- /**
719
- * Decrypts a block
720
- *
721
- * @see Crypt_Base::_decryptBlock()
722
- * @see Crypt_Base::decrypt()
723
- * @see self::decrypt()
724
- * @access private
725
- * @param string $in
726
- * @return string
727
- */
728
- function _decryptBlock($in)
729
- {
730
- return $this->_processBlock($in, CRYPT_DES_DECRYPT);
731
- }
732
-
733
- /**
734
- * Encrypts or decrypts a 64-bit block
735
- *
736
- * $mode should be either CRYPT_DES_ENCRYPT or CRYPT_DES_DECRYPT. See
737
- * {@link http://en.wikipedia.org/wiki/Image:Feistel.png Feistel.png} to get a general
738
- * idea of what this function does.
739
- *
740
- * @see self::_encryptBlock()
741
- * @see self::_decryptBlock()
742
- * @access private
743
- * @param string $block
744
- * @param int $mode
745
- * @return string
746
- */
747
- function _processBlock($block, $mode)
748
- {
749
- static $sbox1, $sbox2, $sbox3, $sbox4, $sbox5, $sbox6, $sbox7, $sbox8, $shuffleip, $shuffleinvip;
750
- if (!$sbox1) {
751
- $sbox1 = array_map("intval", $this->sbox1);
752
- $sbox2 = array_map("intval", $this->sbox2);
753
- $sbox3 = array_map("intval", $this->sbox3);
754
- $sbox4 = array_map("intval", $this->sbox4);
755
- $sbox5 = array_map("intval", $this->sbox5);
756
- $sbox6 = array_map("intval", $this->sbox6);
757
- $sbox7 = array_map("intval", $this->sbox7);
758
- $sbox8 = array_map("intval", $this->sbox8);
759
- /* Merge $shuffle with $[inv]ipmap */
760
- for ($i = 0; $i < 256; ++$i) {
761
- $shuffleip[] = $this->shuffle[$this->ipmap[$i]];
762
- $shuffleinvip[] = $this->shuffle[$this->invipmap[$i]];
763
- }
764
- }
765
-
766
- $keys = $this->keys[$mode];
767
- $ki = -1;
768
-
769
- // Do the initial IP permutation.
770
- $t = unpack('Nl/Nr', $block);
771
- list($l, $r) = array($t['l'], $t['r']);
772
- $block = ($shuffleip[ $r & 0xFF] & "\x80\x80\x80\x80\x80\x80\x80\x80") |
773
- ($shuffleip[($r >> 8) & 0xFF] & "\x40\x40\x40\x40\x40\x40\x40\x40") |
774
- ($shuffleip[($r >> 16) & 0xFF] & "\x20\x20\x20\x20\x20\x20\x20\x20") |
775
- ($shuffleip[($r >> 24) & 0xFF] & "\x10\x10\x10\x10\x10\x10\x10\x10") |
776
- ($shuffleip[ $l & 0xFF] & "\x08\x08\x08\x08\x08\x08\x08\x08") |
777
- ($shuffleip[($l >> 8) & 0xFF] & "\x04\x04\x04\x04\x04\x04\x04\x04") |
778
- ($shuffleip[($l >> 16) & 0xFF] & "\x02\x02\x02\x02\x02\x02\x02\x02") |
779
- ($shuffleip[($l >> 24) & 0xFF] & "\x01\x01\x01\x01\x01\x01\x01\x01");
780
-
781
- // Extract L0 and R0.
782
- $t = unpack('Nl/Nr', $block);
783
- list($l, $r) = array($t['l'], $t['r']);
784
-
785
- for ($des_round = 0; $des_round < $this->des_rounds; ++$des_round) {
786
- // Perform the 16 steps.
787
- for ($i = 0; $i < 16; $i++) {
788
- // start of "the Feistel (F) function" - see the following URL:
789
- // http://en.wikipedia.org/wiki/Image:Data_Encryption_Standard_InfoBox_Diagram.png
790
- // Merge key schedule.
791
- $b1 = (($r >> 3) & 0x1FFFFFFF) ^ ($r << 29) ^ $keys[++$ki];
792
- $b2 = (($r >> 31) & 0x00000001) ^ ($r << 1) ^ $keys[++$ki];
793
-
794
- // S-box indexing.
795
- $t = $sbox1[($b1 >> 24) & 0x3F] ^ $sbox2[($b2 >> 24) & 0x3F] ^
796
- $sbox3[($b1 >> 16) & 0x3F] ^ $sbox4[($b2 >> 16) & 0x3F] ^
797
- $sbox5[($b1 >> 8) & 0x3F] ^ $sbox6[($b2 >> 8) & 0x3F] ^
798
- $sbox7[ $b1 & 0x3F] ^ $sbox8[ $b2 & 0x3F] ^ $l;
799
- // end of "the Feistel (F) function"
800
-
801
- $l = $r;
802
- $r = $t;
803
- }
804
-
805
- // Last step should not permute L & R.
806
- $t = $l;
807
- $l = $r;
808
- $r = $t;
809
- }
810
-
811
- // Perform the inverse IP permutation.
812
- return ($shuffleinvip[($r >> 24) & 0xFF] & "\x80\x80\x80\x80\x80\x80\x80\x80") |
813
- ($shuffleinvip[($l >> 24) & 0xFF] & "\x40\x40\x40\x40\x40\x40\x40\x40") |
814
- ($shuffleinvip[($r >> 16) & 0xFF] & "\x20\x20\x20\x20\x20\x20\x20\x20") |
815
- ($shuffleinvip[($l >> 16) & 0xFF] & "\x10\x10\x10\x10\x10\x10\x10\x10") |
816
- ($shuffleinvip[($r >> 8) & 0xFF] & "\x08\x08\x08\x08\x08\x08\x08\x08") |
817
- ($shuffleinvip[($l >> 8) & 0xFF] & "\x04\x04\x04\x04\x04\x04\x04\x04") |
818
- ($shuffleinvip[ $r & 0xFF] & "\x02\x02\x02\x02\x02\x02\x02\x02") |
819
- ($shuffleinvip[ $l & 0xFF] & "\x01\x01\x01\x01\x01\x01\x01\x01");
820
- }
821
-
822
- /**
823
- * Creates the key schedule
824
- *
825
- * @see Crypt_Base::_setupKey()
826
- * @access private
827
- */
828
- function _setupKey()
829
- {
830
- if (isset($this->kl['key']) && $this->key === $this->kl['key'] && $this->des_rounds === $this->kl['des_rounds']) {
831
- // already expanded
832
- return;
833
- }
834
- $this->kl = array('key' => $this->key, 'des_rounds' => $this->des_rounds);
835
-
836
- static $shifts = array( // number of key bits shifted per round
837
- 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
838
- );
839
-
840
- static $pc1map = array(
841
- 0x00, 0x00, 0x08, 0x08, 0x04, 0x04, 0x0C, 0x0C,
842
- 0x02, 0x02, 0x0A, 0x0A, 0x06, 0x06, 0x0E, 0x0E,
843
- 0x10, 0x10, 0x18, 0x18, 0x14, 0x14, 0x1C, 0x1C,
844
- 0x12, 0x12, 0x1A, 0x1A, 0x16, 0x16, 0x1E, 0x1E,
845
- 0x20, 0x20, 0x28, 0x28, 0x24, 0x24, 0x2C, 0x2C,
846
- 0x22, 0x22, 0x2A, 0x2A, 0x26, 0x26, 0x2E, 0x2E,
847
- 0x30, 0x30, 0x38, 0x38, 0x34, 0x34, 0x3C, 0x3C,
848
- 0x32, 0x32, 0x3A, 0x3A, 0x36, 0x36, 0x3E, 0x3E,
849
- 0x40, 0x40, 0x48, 0x48, 0x44, 0x44, 0x4C, 0x4C,
850
- 0x42, 0x42, 0x4A, 0x4A, 0x46, 0x46, 0x4E, 0x4E,
851
- 0x50, 0x50, 0x58, 0x58, 0x54, 0x54, 0x5C, 0x5C,
852
- 0x52, 0x52, 0x5A, 0x5A, 0x56, 0x56, 0x5E, 0x5E,
853
- 0x60, 0x60, 0x68, 0x68, 0x64, 0x64, 0x6C, 0x6C,
854
- 0x62, 0x62, 0x6A, 0x6A, 0x66, 0x66, 0x6E, 0x6E,
855
- 0x70, 0x70, 0x78, 0x78, 0x74, 0x74, 0x7C, 0x7C,
856
- 0x72, 0x72, 0x7A, 0x7A, 0x76, 0x76, 0x7E, 0x7E,
857
- 0x80, 0x80, 0x88, 0x88, 0x84, 0x84, 0x8C, 0x8C,
858
- 0x82, 0x82, 0x8A, 0x8A, 0x86, 0x86, 0x8E, 0x8E,
859
- 0x90, 0x90, 0x98, 0x98, 0x94, 0x94, 0x9C, 0x9C,
860
- 0x92, 0x92, 0x9A, 0x9A, 0x96, 0x96, 0x9E, 0x9E,
861
- 0xA0, 0xA0, 0xA8, 0xA8, 0xA4, 0xA4, 0xAC, 0xAC,
862
- 0xA2, 0xA2, 0xAA, 0xAA, 0xA6, 0xA6, 0xAE, 0xAE,
863
- 0xB0, 0xB0, 0xB8, 0xB8, 0xB4, 0xB4, 0xBC, 0xBC,
864
- 0xB2, 0xB2, 0xBA, 0xBA, 0xB6, 0xB6, 0xBE, 0xBE,
865
- 0xC0, 0xC0, 0xC8, 0xC8, 0xC4, 0xC4, 0xCC, 0xCC,
866
- 0xC2, 0xC2, 0xCA, 0xCA, 0xC6, 0xC6, 0xCE, 0xCE,
867
- 0xD0, 0xD0, 0xD8, 0xD8, 0xD4, 0xD4, 0xDC, 0xDC,
868
- 0xD2, 0xD2, 0xDA, 0xDA, 0xD6, 0xD6, 0xDE, 0xDE,
869
- 0xE0, 0xE0, 0xE8, 0xE8, 0xE4, 0xE4, 0xEC, 0xEC,
870
- 0xE2, 0xE2, 0xEA, 0xEA, 0xE6, 0xE6, 0xEE, 0xEE,
871
- 0xF0, 0xF0, 0xF8, 0xF8, 0xF4, 0xF4, 0xFC, 0xFC,
872
- 0xF2, 0xF2, 0xFA, 0xFA, 0xF6, 0xF6, 0xFE, 0xFE
873
- );
874
-
875
- // Mapping tables for the PC-2 transformation.
876
- static $pc2mapc1 = array(
877
- 0x00000000, 0x00000400, 0x00200000, 0x00200400,
878
- 0x00000001, 0x00000401, 0x00200001, 0x00200401,
879
- 0x02000000, 0x02000400, 0x02200000, 0x02200400,
880
- 0x02000001, 0x02000401, 0x02200001, 0x02200401
881
- );
882
- static $pc2mapc2 = array(
883
- 0x00000000, 0x00000800, 0x08000000, 0x08000800,
884
- 0x00010000, 0x00010800, 0x08010000, 0x08010800,
885
- 0x00000000, 0x00000800, 0x08000000, 0x08000800,
886
- 0x00010000, 0x00010800, 0x08010000, 0x08010800,
887
- 0x00000100, 0x00000900, 0x08000100, 0x08000900,
888
- 0x00010100, 0x00010900, 0x08010100, 0x08010900,
889
- 0x00000100, 0x00000900, 0x08000100, 0x08000900,
890
- 0x00010100, 0x00010900, 0x08010100, 0x08010900,
891
- 0x00000010, 0x00000810, 0x08000010, 0x08000810,
892
- 0x00010010, 0x00010810, 0x08010010, 0x08010810,
893
- 0x00000010, 0x00000810, 0x08000010, 0x08000810,
894
- 0x00010010, 0x00010810, 0x08010010, 0x08010810,
895
- 0x00000110, 0x00000910, 0x08000110, 0x08000910,
896
- 0x00010110, 0x00010910, 0x08010110, 0x08010910,
897
- 0x00000110, 0x00000910, 0x08000110, 0x08000910,
898
- 0x00010110, 0x00010910, 0x08010110, 0x08010910,
899
- 0x00040000, 0x00040800, 0x08040000, 0x08040800,
900
- 0x00050000, 0x00050800, 0x08050000, 0x08050800,
901
- 0x00040000, 0x00040800, 0x08040000, 0x08040800,
902
- 0x00050000, 0x00050800, 0x08050000, 0x08050800,
903
- 0x00040100, 0x00040900, 0x08040100, 0x08040900,
904
- 0x00050100, 0x00050900, 0x08050100, 0x08050900,
905
- 0x00040100, 0x00040900, 0x08040100, 0x08040900,
906
- 0x00050100, 0x00050900, 0x08050100, 0x08050900,
907
- 0x00040010, 0x00040810, 0x08040010, 0x08040810,
908
- 0x00050010, 0x00050810, 0x08050010, 0x08050810,
909
- 0x00040010, 0x00040810, 0x08040010, 0x08040810,
910
- 0x00050010, 0x00050810, 0x08050010, 0x08050810,
911
- 0x00040110, 0x00040910, 0x08040110, 0x08040910,
912
- 0x00050110, 0x00050910, 0x08050110, 0x08050910,
913
- 0x00040110, 0x00040910, 0x08040110, 0x08040910,
914
- 0x00050110, 0x00050910, 0x08050110, 0x08050910,
915
- 0x01000000, 0x01000800, 0x09000000, 0x09000800,
916
- 0x01010000, 0x01010800, 0x09010000, 0x09010800,
917
- 0x01000000, 0x01000800, 0x09000000, 0x09000800,
918
- 0x01010000, 0x01010800, 0x09010000, 0x09010800,
919
- 0x01000100, 0x01000900, 0x09000100, 0x09000900,
920
- 0x01010100, 0x01010900, 0x09010100, 0x09010900,
921
- 0x01000100, 0x01000900, 0x09000100, 0x09000900,
922
- 0x01010100, 0x01010900, 0x09010100, 0x09010900,
923
- 0x01000010, 0x01000810, 0x09000010, 0x09000810,
924
- 0x01010010, 0x01010810, 0x09010010, 0x09010810,
925
- 0x01000010, 0x01000810, 0x09000010, 0x09000810,
926
- 0x01010010, 0x01010810, 0x09010010, 0x09010810,
927
- 0x01000110, 0x01000910, 0x09000110, 0x09000910,
928
- 0x01010110, 0x01010910, 0x09010110, 0x09010910,
929
- 0x01000110, 0x01000910, 0x09000110, 0x09000910,
930
- 0x01010110, 0x01010910, 0x09010110, 0x09010910,
931
- 0x01040000, 0x01040800, 0x09040000, 0x09040800,
932
- 0x01050000, 0x01050800, 0x09050000, 0x09050800,
933
- 0x01040000, 0x01040800, 0x09040000, 0x09040800,
934
- 0x01050000, 0x01050800, 0x09050000, 0x09050800,
935
- 0x01040100, 0x01040900, 0x09040100, 0x09040900,
936
- 0x01050100, 0x01050900, 0x09050100, 0x09050900,
937
- 0x01040100, 0x01040900, 0x09040100, 0x09040900,
938
- 0x01050100, 0x01050900, 0x09050100, 0x09050900,
939
- 0x01040010, 0x01040810, 0x09040010, 0x09040810,
940
- 0x01050010, 0x01050810, 0x09050010, 0x09050810,
941
- 0x01040010, 0x01040810, 0x09040010, 0x09040810,
942
- 0x01050010, 0x01050810, 0x09050010, 0x09050810,
943
- 0x01040110, 0x01040910, 0x09040110, 0x09040910,
944
- 0x01050110, 0x01050910, 0x09050110, 0x09050910,
945
- 0x01040110, 0x01040910, 0x09040110, 0x09040910,
946
- 0x01050110, 0x01050910, 0x09050110, 0x09050910
947
- );
948
- static $pc2mapc3 = array(
949
- 0x00000000, 0x00000004, 0x00001000, 0x00001004,
950
- 0x00000000, 0x00000004, 0x00001000, 0x00001004,
951
- 0x10000000, 0x10000004, 0x10001000, 0x10001004,
952
- 0x10000000, 0x10000004, 0x10001000, 0x10001004,
953
- 0x00000020, 0x00000024, 0x00001020, 0x00001024,
954
- 0x00000020, 0x00000024, 0x00001020, 0x00001024,
955
- 0x10000020, 0x10000024, 0x10001020, 0x10001024,
956
- 0x10000020, 0x10000024, 0x10001020, 0x10001024,
957
- 0x00080000, 0x00080004, 0x00081000, 0x00081004,
958
- 0x00080000, 0x00080004, 0x00081000, 0x00081004,
959
- 0x10080000, 0x10080004, 0x10081000, 0x10081004,
960
- 0x10080000, 0x10080004, 0x10081000, 0x10081004,
961
- 0x00080020, 0x00080024, 0x00081020, 0x00081024,
962
- 0x00080020, 0x00080024, 0x00081020, 0x00081024,
963
- 0x10080020, 0x10080024, 0x10081020, 0x10081024,
964
- 0x10080020, 0x10080024, 0x10081020, 0x10081024,
965
- 0x20000000, 0x20000004, 0x20001000, 0x20001004,
966
- 0x20000000, 0x20000004, 0x20001000, 0x20001004,
967
- 0x30000000, 0x30000004, 0x30001000, 0x30001004,
968
- 0x30000000, 0x30000004, 0x30001000, 0x30001004,
969
- 0x20000020, 0x20000024, 0x20001020, 0x20001024,
970
- 0x20000020, 0x20000024, 0x20001020, 0x20001024,
971
- 0x30000020, 0x30000024, 0x30001020, 0x30001024,
972
- 0x30000020, 0x30000024, 0x30001020, 0x30001024,
973
- 0x20080000, 0x20080004, 0x20081000, 0x20081004,
974
- 0x20080000, 0x20080004, 0x20081000, 0x20081004,
975
- 0x30080000, 0x30080004, 0x30081000, 0x30081004,
976
- 0x30080000, 0x30080004, 0x30081000, 0x30081004,
977
- 0x20080020, 0x20080024, 0x20081020, 0x20081024,
978
- 0x20080020, 0x20080024, 0x20081020, 0x20081024,
979
- 0x30080020, 0x30080024, 0x30081020, 0x30081024,
980
- 0x30080020, 0x30080024, 0x30081020, 0x30081024,
981
- 0x00000002, 0x00000006, 0x00001002, 0x00001006,
982
- 0x00000002, 0x00000006, 0x00001002, 0x00001006,
983
- 0x10000002, 0x10000006, 0x10001002, 0x10001006,
984
- 0x10000002, 0x10000006, 0x10001002, 0x10001006,
985
- 0x00000022, 0x00000026, 0x00001022, 0x00001026,
986
- 0x00000022, 0x00000026, 0x00001022, 0x00001026,
987
- 0x10000022, 0x10000026, 0x10001022, 0x10001026,
988
- 0x10000022, 0x10000026, 0x10001022, 0x10001026,
989
- 0x00080002, 0x00080006, 0x00081002, 0x00081006,
990
- 0x00080002, 0x00080006, 0x00081002, 0x00081006,
991
- 0x10080002, 0x10080006, 0x10081002, 0x10081006,
992
- 0x10080002, 0x10080006, 0x10081002, 0x10081006,
993
- 0x00080022, 0x00080026, 0x00081022, 0x00081026,
994
- 0x00080022, 0x00080026, 0x00081022, 0x00081026,
995
- 0x10080022, 0x10080026, 0x10081022, 0x10081026,
996
- 0x10080022, 0x10080026, 0x10081022, 0x10081026,
997
- 0x20000002, 0x20000006, 0x20001002, 0x20001006,
998
- 0x20000002, 0x20000006, 0x20001002, 0x20001006,
999
- 0x30000002, 0x30000006, 0x30001002, 0x30001006,
1000
- 0x30000002, 0x30000006, 0x30001002, 0x30001006,
1001
- 0x20000022, 0x20000026, 0x20001022, 0x20001026,
1002
- 0x20000022, 0x20000026, 0x20001022, 0x20001026,
1003
- 0x30000022, 0x30000026, 0x30001022, 0x30001026,
1004
- 0x30000022, 0x30000026, 0x30001022, 0x30001026,
1005
- 0x20080002, 0x20080006, 0x20081002, 0x20081006,
1006
- 0x20080002, 0x20080006, 0x20081002, 0x20081006,
1007
- 0x30080002, 0x30080006, 0x30081002, 0x30081006,
1008
- 0x30080002, 0x30080006, 0x30081002, 0x30081006,
1009
- 0x20080022, 0x20080026, 0x20081022, 0x20081026,
1010
- 0x20080022, 0x20080026, 0x20081022, 0x20081026,
1011
- 0x30080022, 0x30080026, 0x30081022, 0x30081026,
1012
- 0x30080022, 0x30080026, 0x30081022, 0x30081026
1013
- );
1014
- static $pc2mapc4 = array(
1015
- 0x00000000, 0x00100000, 0x00000008, 0x00100008,
1016
- 0x00000200, 0x00100200, 0x00000208, 0x00100208,
1017
- 0x00000000, 0x00100000, 0x00000008, 0x00100008,
1018
- 0x00000200, 0x00100200, 0x00000208, 0x00100208,
1019
- 0x04000000, 0x04100000, 0x04000008, 0x04100008,
1020
- 0x04000200, 0x04100200, 0x04000208, 0x04100208,
1021
- 0x04000000, 0x04100000, 0x04000008, 0x04100008,
1022
- 0x04000200, 0x04100200, 0x04000208, 0x04100208,
1023
- 0x00002000, 0x00102000, 0x00002008, 0x00102008,
1024
- 0x00002200, 0x00102200, 0x00002208, 0x00102208,
1025
- 0x00002000, 0x00102000, 0x00002008, 0x00102008,
1026
- 0x00002200, 0x00102200, 0x00002208, 0x00102208,
1027
- 0x04002000, 0x04102000, 0x04002008, 0x04102008,
1028
- 0x04002200, 0x04102200, 0x04002208, 0x04102208,
1029
- 0x04002000, 0x04102000, 0x04002008, 0x04102008,
1030
- 0x04002200, 0x04102200, 0x04002208, 0x04102208,
1031
- 0x00000000, 0x00100000, 0x00000008, 0x00100008,
1032
- 0x00000200, 0x00100200, 0x00000208, 0x00100208,
1033
- 0x00000000, 0x00100000, 0x00000008, 0x00100008,
1034
- 0x00000200, 0x00100200, 0x00000208, 0x00100208,
1035
- 0x04000000, 0x04100000, 0x04000008, 0x04100008,
1036
- 0x04000200, 0x04100200, 0x04000208, 0x04100208,
1037
- 0x04000000, 0x04100000, 0x04000008, 0x04100008,
1038
- 0x04000200, 0x04100200, 0x04000208, 0x04100208,
1039
- 0x00002000, 0x00102000, 0x00002008, 0x00102008,
1040
- 0x00002200, 0x00102200, 0x00002208, 0x00102208,
1041
- 0x00002000, 0x00102000, 0x00002008, 0x00102008,
1042
- 0x00002200, 0x00102200, 0x00002208, 0x00102208,
1043
- 0x04002000, 0x04102000, 0x04002008, 0x04102008,
1044
- 0x04002200, 0x04102200, 0x04002208, 0x04102208,
1045
- 0x04002000, 0x04102000, 0x04002008, 0x04102008,
1046
- 0x04002200, 0x04102200, 0x04002208, 0x04102208,
1047
- 0x00020000, 0x00120000, 0x00020008, 0x00120008,
1048
- 0x00020200, 0x00120200, 0x00020208, 0x00120208,
1049
- 0x00020000, 0x00120000, 0x00020008, 0x00120008,
1050
- 0x00020200, 0x00120200, 0x00020208, 0x00120208,
1051
- 0x04020000, 0x04120000, 0x04020008, 0x04120008,
1052
- 0x04020200, 0x04120200, 0x04020208, 0x04120208,
1053
- 0x04020000, 0x04120000, 0x04020008, 0x04120008,
1054
- 0x04020200, 0x04120200, 0x04020208, 0x04120208,
1055
- 0x00022000, 0x00122000, 0x00022008, 0x00122008,
1056
- 0x00022200, 0x00122200, 0x00022208, 0x00122208,
1057
- 0x00022000, 0x00122000, 0x00022008, 0x00122008,
1058
- 0x00022200, 0x00122200, 0x00022208, 0x00122208,
1059
- 0x04022000, 0x04122000, 0x04022008, 0x04122008,
1060
- 0x04022200, 0x04122200, 0x04022208, 0x04122208,
1061
- 0x04022000, 0x04122000, 0x04022008, 0x04122008,
1062
- 0x04022200, 0x04122200, 0x04022208, 0x04122208,
1063
- 0x00020000, 0x00120000, 0x00020008, 0x00120008,
1064
- 0x00020200, 0x00120200, 0x00020208, 0x00120208,
1065
- 0x00020000, 0x00120000, 0x00020008, 0x00120008,
1066
- 0x00020200, 0x00120200, 0x00020208, 0x00120208,
1067
- 0x04020000, 0x04120000, 0x04020008, 0x04120008,
1068
- 0x04020200, 0x04120200, 0x04020208, 0x04120208,
1069
- 0x04020000, 0x04120000, 0x04020008, 0x04120008,
1070
- 0x04020200, 0x04120200, 0x04020208, 0x04120208,
1071
- 0x00022000, 0x00122000, 0x00022008, 0x00122008,
1072
- 0x00022200, 0x00122200, 0x00022208, 0x00122208,
1073
- 0x00022000, 0x00122000, 0x00022008, 0x00122008,
1074
- 0x00022200, 0x00122200, 0x00022208, 0x00122208,
1075
- 0x04022000, 0x04122000, 0x04022008, 0x04122008,
1076
- 0x04022200, 0x04122200, 0x04022208, 0x04122208,
1077
- 0x04022000, 0x04122000, 0x04022008, 0x04122008,
1078
- 0x04022200, 0x04122200, 0x04022208, 0x04122208
1079
- );
1080
- static $pc2mapd1 = array(
1081
- 0x00000000, 0x00000001, 0x08000000, 0x08000001,
1082
- 0x00200000, 0x00200001, 0x08200000, 0x08200001,
1083
- 0x00000002, 0x00000003, 0x08000002, 0x08000003,
1084
- 0x00200002, 0x00200003, 0x08200002, 0x08200003
1085
- );
1086
- static $pc2mapd2 = array(
1087
- 0x00000000, 0x00100000, 0x00000800, 0x00100800,
1088
- 0x00000000, 0x00100000, 0x00000800, 0x00100800,
1089
- 0x04000000, 0x04100000, 0x04000800, 0x04100800,
1090
- 0x04000000, 0x04100000, 0x04000800, 0x04100800,
1091
- 0x00000004, 0x00100004, 0x00000804, 0x00100804,
1092
- 0x00000004, 0x00100004, 0x00000804, 0x00100804,
1093
- 0x04000004, 0x04100004, 0x04000804, 0x04100804,
1094
- 0x04000004, 0x04100004, 0x04000804, 0x04100804,
1095
- 0x00000000, 0x00100000, 0x00000800, 0x00100800,
1096
- 0x00000000, 0x00100000, 0x00000800, 0x00100800,
1097
- 0x04000000, 0x04100000, 0x04000800, 0x04100800,
1098
- 0x04000000, 0x04100000, 0x04000800, 0x04100800,
1099
- 0x00000004, 0x00100004, 0x00000804, 0x00100804,
1100
- 0x00000004, 0x00100004, 0x00000804, 0x00100804,
1101
- 0x04000004, 0x04100004, 0x04000804, 0x04100804,
1102
- 0x04000004, 0x04100004, 0x04000804, 0x04100804,
1103
- 0x00000200, 0x00100200, 0x00000A00, 0x00100A00,
1104
- 0x00000200, 0x00100200, 0x00000A00, 0x00100A00,
1105
- 0x04000200, 0x04100200, 0x04000A00, 0x04100A00,
1106
- 0x04000200, 0x04100200, 0x04000A00, 0x04100A00,
1107
- 0x00000204, 0x00100204, 0x00000A04, 0x00100A04,
1108
- 0x00000204, 0x00100204, 0x00000A04, 0x00100A04,
1109
- 0x04000204, 0x04100204, 0x04000A04, 0x04100A04,
1110
- 0x04000204, 0x04100204, 0x04000A04, 0x04100A04,
1111
- 0x00000200, 0x00100200, 0x00000A00, 0x00100A00,
1112
- 0x00000200, 0x00100200, 0x00000A00, 0x00100A00,
1113
- 0x04000200, 0x04100200, 0x04000A00, 0x04100A00,
1114
- 0x04000200, 0x04100200, 0x04000A00, 0x04100A00,
1115
- 0x00000204, 0x00100204, 0x00000A04, 0x00100A04,
1116
- 0x00000204, 0x00100204, 0x00000A04, 0x00100A04,
1117
- 0x04000204, 0x04100204, 0x04000A04, 0x04100A04,
1118
- 0x04000204, 0x04100204, 0x04000A04, 0x04100A04,
1119
- 0x00020000, 0x00120000, 0x00020800, 0x00120800,
1120
- 0x00020000, 0x00120000, 0x00020800, 0x00120800,
1121
- 0x04020000, 0x04120000, 0x04020800, 0x04120800,
1122
- 0x04020000, 0x04120000, 0x04020800, 0x04120800,
1123
- 0x00020004, 0x00120004, 0x00020804, 0x00120804,
1124
- 0x00020004, 0x00120004, 0x00020804, 0x00120804,
1125
- 0x04020004, 0x04120004, 0x04020804, 0x04120804,
1126
- 0x04020004, 0x04120004, 0x04020804, 0x04120804,
1127
- 0x00020000, 0x00120000, 0x00020800, 0x00120800,
1128
- 0x00020000, 0x00120000, 0x00020800, 0x00120800,
1129
- 0x04020000, 0x04120000, 0x04020800, 0x04120800,
1130
- 0x04020000, 0x04120000, 0x04020800, 0x04120800,
1131
- 0x00020004, 0x00120004, 0x00020804, 0x00120804,
1132
- 0x00020004, 0x00120004, 0x00020804, 0x00120804,
1133
- 0x04020004, 0x04120004, 0x04020804, 0x04120804,
1134
- 0x04020004, 0x04120004, 0x04020804, 0x04120804,
1135
- 0x00020200, 0x00120200, 0x00020A00, 0x00120A00,
1136
- 0x00020200, 0x00120200, 0x00020A00, 0x00120A00,
1137
- 0x04020200, 0x04120200, 0x04020A00, 0x04120A00,
1138
- 0x04020200, 0x04120200, 0x04020A00, 0x04120A00,
1139
- 0x00020204, 0x00120204, 0x00020A04, 0x00120A04,
1140
- 0x00020204, 0x00120204, 0x00020A04, 0x00120A04,
1141
- 0x04020204, 0x04120204, 0x04020A04, 0x04120A04,
1142
- 0x04020204, 0x04120204, 0x04020A04, 0x04120A04,
1143
- 0x00020200, 0x00120200, 0x00020A00, 0x00120A00,
1144
- 0x00020200, 0x00120200, 0x00020A00, 0x00120A00,
1145
- 0x04020200, 0x04120200, 0x04020A00, 0x04120A00,
1146
- 0x04020200, 0x04120200, 0x04020A00, 0x04120A00,
1147
- 0x00020204, 0x00120204, 0x00020A04, 0x00120A04,
1148
- 0x00020204, 0x00120204, 0x00020A04, 0x00120A04,
1149
- 0x04020204, 0x04120204, 0x04020A04, 0x04120A04,
1150
- 0x04020204, 0x04120204, 0x04020A04, 0x04120A04
1151
- );
1152
- static $pc2mapd3 = array(
1153
- 0x00000000, 0x00010000, 0x02000000, 0x02010000,
1154
- 0x00000020, 0x00010020, 0x02000020, 0x02010020,
1155
- 0x00040000, 0x00050000, 0x02040000, 0x02050000,
1156
- 0x00040020, 0x00050020, 0x02040020, 0x02050020,
1157
- 0x00002000, 0x00012000, 0x02002000, 0x02012000,
1158
- 0x00002020, 0x00012020, 0x02002020, 0x02012020,
1159
- 0x00042000, 0x00052000, 0x02042000, 0x02052000,
1160
- 0x00042020, 0x00052020, 0x02042020, 0x02052020,
1161
- 0x00000000, 0x00010000, 0x02000000, 0x02010000,
1162
- 0x00000020, 0x00010020, 0x02000020, 0x02010020,
1163
- 0x00040000, 0x00050000, 0x02040000, 0x02050000,
1164
- 0x00040020, 0x00050020, 0x02040020, 0x02050020,
1165
- 0x00002000, 0x00012000, 0x02002000, 0x02012000,
1166
- 0x00002020, 0x00012020, 0x02002020, 0x02012020,
1167
- 0x00042000, 0x00052000, 0x02042000, 0x02052000,
1168
- 0x00042020, 0x00052020, 0x02042020, 0x02052020,
1169
- 0x00000010, 0x00010010, 0x02000010, 0x02010010,
1170
- 0x00000030, 0x00010030, 0x02000030, 0x02010030,
1171
- 0x00040010, 0x00050010, 0x02040010, 0x02050010,
1172
- 0x00040030, 0x00050030, 0x02040030, 0x02050030,
1173
- 0x00002010, 0x00012010, 0x02002010, 0x02012010,
1174
- 0x00002030, 0x00012030, 0x02002030, 0x02012030,
1175
- 0x00042010, 0x00052010, 0x02042010, 0x02052010,
1176
- 0x00042030, 0x00052030, 0x02042030, 0x02052030,
1177
- 0x00000010, 0x00010010, 0x02000010, 0x02010010,
1178
- 0x00000030, 0x00010030, 0x02000030, 0x02010030,
1179
- 0x00040010, 0x00050010, 0x02040010, 0x02050010,
1180
- 0x00040030, 0x00050030, 0x02040030, 0x02050030,
1181
- 0x00002010, 0x00012010, 0x02002010, 0x02012010,
1182
- 0x00002030, 0x00012030, 0x02002030, 0x02012030,
1183
- 0x00042010, 0x00052010, 0x02042010, 0x02052010,
1184
- 0x00042030, 0x00052030, 0x02042030, 0x02052030,
1185
- 0x20000000, 0x20010000, 0x22000000, 0x22010000,
1186
- 0x20000020, 0x20010020, 0x22000020, 0x22010020,
1187
- 0x20040000, 0x20050000, 0x22040000, 0x22050000,
1188
- 0x20040020, 0x20050020, 0x22040020, 0x22050020,
1189
- 0x20002000, 0x20012000, 0x22002000, 0x22012000,
1190
- 0x20002020, 0x20012020, 0x22002020, 0x22012020,
1191
- 0x20042000, 0x20052000, 0x22042000, 0x22052000,
1192
- 0x20042020, 0x20052020, 0x22042020, 0x22052020,
1193
- 0x20000000, 0x20010000, 0x22000000, 0x22010000,
1194
- 0x20000020, 0x20010020, 0x22000020, 0x22010020,
1195
- 0x20040000, 0x20050000, 0x22040000, 0x22050000,
1196
- 0x20040020, 0x20050020, 0x22040020, 0x22050020,
1197
- 0x20002000, 0x20012000, 0x22002000, 0x22012000,
1198
- 0x20002020, 0x20012020, 0x22002020, 0x22012020,
1199
- 0x20042000, 0x20052000, 0x22042000, 0x22052000,
1200
- 0x20042020, 0x20052020, 0x22042020, 0x22052020,
1201
- 0x20000010, 0x20010010, 0x22000010, 0x22010010,
1202
- 0x20000030, 0x20010030, 0x22000030, 0x22010030,
1203
- 0x20040010, 0x20050010, 0x22040010, 0x22050010,
1204
- 0x20040030, 0x20050030, 0x22040030, 0x22050030,
1205
- 0x20002010, 0x20012010, 0x22002010, 0x22012010,
1206
- 0x20002030, 0x20012030, 0x22002030, 0x22012030,
1207
- 0x20042010, 0x20052010, 0x22042010, 0x22052010,
1208
- 0x20042030, 0x20052030, 0x22042030, 0x22052030,
1209
- 0x20000010, 0x20010010, 0x22000010, 0x22010010,
1210
- 0x20000030, 0x20010030, 0x22000030, 0x22010030,
1211
- 0x20040010, 0x20050010, 0x22040010, 0x22050010,
1212
- 0x20040030, 0x20050030, 0x22040030, 0x22050030,
1213
- 0x20002010, 0x20012010, 0x22002010, 0x22012010,
1214
- 0x20002030, 0x20012030, 0x22002030, 0x22012030,
1215
- 0x20042010, 0x20052010, 0x22042010, 0x22052010,
1216
- 0x20042030, 0x20052030, 0x22042030, 0x22052030
1217
- );
1218
- static $pc2mapd4 = array(
1219
- 0x00000000, 0x00000400, 0x01000000, 0x01000400,
1220
- 0x00000000, 0x00000400, 0x01000000, 0x01000400,
1221
- 0x00000100, 0x00000500, 0x01000100, 0x01000500,
1222
- 0x00000100, 0x00000500, 0x01000100, 0x01000500,
1223
- 0x10000000, 0x10000400, 0x11000000, 0x11000400,
1224
- 0x10000000, 0x10000400, 0x11000000, 0x11000400,
1225
- 0x10000100, 0x10000500, 0x11000100, 0x11000500,
1226
- 0x10000100, 0x10000500, 0x11000100, 0x11000500,
1227
- 0x00080000, 0x00080400, 0x01080000, 0x01080400,
1228
- 0x00080000, 0x00080400, 0x01080000, 0x01080400,
1229
- 0x00080100, 0x00080500, 0x01080100, 0x01080500,
1230
- 0x00080100, 0x00080500, 0x01080100, 0x01080500,
1231
- 0x10080000, 0x10080400, 0x11080000, 0x11080400,
1232
- 0x10080000, 0x10080400, 0x11080000, 0x11080400,
1233
- 0x10080100, 0x10080500, 0x11080100, 0x11080500,
1234
- 0x10080100, 0x10080500, 0x11080100, 0x11080500,
1235
- 0x00000008, 0x00000408, 0x01000008, 0x01000408,
1236
- 0x00000008, 0x00000408, 0x01000008, 0x01000408,
1237
- 0x00000108, 0x00000508, 0x01000108, 0x01000508,
1238
- 0x00000108, 0x00000508, 0x01000108, 0x01000508,
1239
- 0x10000008, 0x10000408, 0x11000008, 0x11000408,
1240
- 0x10000008, 0x10000408, 0x11000008, 0x11000408,
1241
- 0x10000108, 0x10000508, 0x11000108, 0x11000508,
1242
- 0x10000108, 0x10000508, 0x11000108, 0x11000508,
1243
- 0x00080008, 0x00080408, 0x01080008, 0x01080408,
1244
- 0x00080008, 0x00080408, 0x01080008, 0x01080408,
1245
- 0x00080108, 0x00080508, 0x01080108, 0x01080508,
1246
- 0x00080108, 0x00080508, 0x01080108, 0x01080508,
1247
- 0x10080008, 0x10080408, 0x11080008, 0x11080408,
1248
- 0x10080008, 0x10080408, 0x11080008, 0x11080408,
1249
- 0x10080108, 0x10080508, 0x11080108, 0x11080508,
1250
- 0x10080108, 0x10080508, 0x11080108, 0x11080508,
1251
- 0x00001000, 0x00001400, 0x01001000, 0x01001400,
1252
- 0x00001000, 0x00001400, 0x01001000, 0x01001400,
1253
- 0x00001100, 0x00001500, 0x01001100, 0x01001500,
1254
- 0x00001100, 0x00001500, 0x01001100, 0x01001500,
1255
- 0x10001000, 0x10001400, 0x11001000, 0x11001400,
1256
- 0x10001000, 0x10001400, 0x11001000, 0x11001400,
1257
- 0x10001100, 0x10001500, 0x11001100, 0x11001500,
1258
- 0x10001100, 0x10001500, 0x11001100, 0x11001500,
1259
- 0x00081000, 0x00081400, 0x01081000, 0x01081400,
1260
- 0x00081000, 0x00081400, 0x01081000, 0x01081400,
1261
- 0x00081100, 0x00081500, 0x01081100, 0x01081500,
1262
- 0x00081100, 0x00081500, 0x01081100, 0x01081500,
1263
- 0x10081000, 0x10081400, 0x11081000, 0x11081400,
1264
- 0x10081000, 0x10081400, 0x11081000, 0x11081400,
1265
- 0x10081100, 0x10081500, 0x11081100, 0x11081500,
1266
- 0x10081100, 0x10081500, 0x11081100, 0x11081500,
1267
- 0x00001008, 0x00001408, 0x01001008, 0x01001408,
1268
- 0x00001008, 0x00001408, 0x01001008, 0x01001408,
1269
- 0x00001108, 0x00001508, 0x01001108, 0x01001508,
1270
- 0x00001108, 0x00001508, 0x01001108, 0x01001508,
1271
- 0x10001008, 0x10001408, 0x11001008, 0x11001408,
1272
- 0x10001008, 0x10001408, 0x11001008, 0x11001408,
1273
- 0x10001108, 0x10001508, 0x11001108, 0x11001508,
1274
- 0x10001108, 0x10001508, 0x11001108, 0x11001508,
1275
- 0x00081008, 0x00081408, 0x01081008, 0x01081408,
1276
- 0x00081008, 0x00081408, 0x01081008, 0x01081408,
1277
- 0x00081108, 0x00081508, 0x01081108, 0x01081508,
1278
- 0x00081108, 0x00081508, 0x01081108, 0x01081508,
1279
- 0x10081008, 0x10081408, 0x11081008, 0x11081408,
1280
- 0x10081008, 0x10081408, 0x11081008, 0x11081408,
1281
- 0x10081108, 0x10081508, 0x11081108, 0x11081508,
1282
- 0x10081108, 0x10081508, 0x11081108, 0x11081508
1283
- );
1284
-
1285
- $keys = array();
1286
- for ($des_round = 0; $des_round < $this->des_rounds; ++$des_round) {
1287
- // pad the key and remove extra characters as appropriate.
1288
- $key = str_pad(substr($this->key, $des_round * 8, 8), 8, "\0");
1289
-
1290
- // Perform the PC/1 transformation and compute C and D.
1291
- $t = unpack('Nl/Nr', $key);
1292
- list($l, $r) = array($t['l'], $t['r']);
1293
- $key = ($this->shuffle[$pc1map[ $r & 0xFF]] & "\x80\x80\x80\x80\x80\x80\x80\x00") |
1294
- ($this->shuffle[$pc1map[($r >> 8) & 0xFF]] & "\x40\x40\x40\x40\x40\x40\x40\x00") |
1295
- ($this->shuffle[$pc1map[($r >> 16) & 0xFF]] & "\x20\x20\x20\x20\x20\x20\x20\x00") |
1296
- ($this->shuffle[$pc1map[($r >> 24) & 0xFF]] & "\x10\x10\x10\x10\x10\x10\x10\x00") |
1297
- ($this->shuffle[$pc1map[ $l & 0xFF]] & "\x08\x08\x08\x08\x08\x08\x08\x00") |
1298
- ($this->shuffle[$pc1map[($l >> 8) & 0xFF]] & "\x04\x04\x04\x04\x04\x04\x04\x00") |
1299
- ($this->shuffle[$pc1map[($l >> 16) & 0xFF]] & "\x02\x02\x02\x02\x02\x02\x02\x00") |
1300
- ($this->shuffle[$pc1map[($l >> 24) & 0xFF]] & "\x01\x01\x01\x01\x01\x01\x01\x00");
1301
- $key = unpack('Nc/Nd', $key);
1302
- $c = ( $key['c'] >> 4) & 0x0FFFFFFF;
1303
- $d = (($key['d'] >> 4) & 0x0FFFFFF0) | ($key['c'] & 0x0F);
1304
-
1305
- $keys[$des_round] = array(
1306
- CRYPT_DES_ENCRYPT => array(),
1307
- CRYPT_DES_DECRYPT => array_fill(0, 32, 0)
1308
- );
1309
- for ($i = 0, $ki = 31; $i < 16; ++$i, $ki-= 2) {
1310
- $c <<= $shifts[$i];
1311
- $c = ($c | ($c >> 28)) & 0x0FFFFFFF;
1312
- $d <<= $shifts[$i];
1313
- $d = ($d | ($d >> 28)) & 0x0FFFFFFF;
1314
-
1315
- // Perform the PC-2 transformation.
1316
- $cp = $pc2mapc1[ $c >> 24 ] | $pc2mapc2[($c >> 16) & 0xFF] |
1317
- $pc2mapc3[($c >> 8) & 0xFF] | $pc2mapc4[ $c & 0xFF];
1318
- $dp = $pc2mapd1[ $d >> 24 ] | $pc2mapd2[($d >> 16) & 0xFF] |
1319
- $pc2mapd3[($d >> 8) & 0xFF] | $pc2mapd4[ $d & 0xFF];
1320
-
1321
- // Reorder: odd bytes/even bytes. Push the result in key schedule.
1322
- $val1 = ( $cp & 0xFF000000) | (($cp << 8) & 0x00FF0000) |
1323
- (($dp >> 16) & 0x0000FF00) | (($dp >> 8) & 0x000000FF);
1324
- $val2 = (($cp << 8) & 0xFF000000) | (($cp << 16) & 0x00FF0000) |
1325
- (($dp >> 8) & 0x0000FF00) | ( $dp & 0x000000FF);
1326
- $keys[$des_round][CRYPT_DES_ENCRYPT][ ] = $val1;
1327
- $keys[$des_round][CRYPT_DES_DECRYPT][$ki - 1] = $val1;
1328
- $keys[$des_round][CRYPT_DES_ENCRYPT][ ] = $val2;
1329
- $keys[$des_round][CRYPT_DES_DECRYPT][$ki ] = $val2;
1330
- }
1331
- }
1332
-
1333
- switch ($this->des_rounds) {
1334
- case 3: // 3DES keys
1335
- $this->keys = array(
1336
- CRYPT_DES_ENCRYPT => array_merge(
1337
- $keys[0][CRYPT_DES_ENCRYPT],
1338
- $keys[1][CRYPT_DES_DECRYPT],
1339
- $keys[2][CRYPT_DES_ENCRYPT]
1340
- ),
1341
- CRYPT_DES_DECRYPT => array_merge(
1342
- $keys[2][CRYPT_DES_DECRYPT],
1343
- $keys[1][CRYPT_DES_ENCRYPT],
1344
- $keys[0][CRYPT_DES_DECRYPT]
1345
- )
1346
- );
1347
- break;
1348
- // case 1: // DES keys
1349
- default:
1350
- $this->keys = array(
1351
- CRYPT_DES_ENCRYPT => $keys[0][CRYPT_DES_ENCRYPT],
1352
- CRYPT_DES_DECRYPT => $keys[0][CRYPT_DES_DECRYPT]
1353
- );
1354
- }
1355
- }
1356
-
1357
- /**
1358
- * Setup the performance-optimized function for de/encrypt()
1359
- *
1360
- * @see Crypt_Base::_setupInlineCrypt()
1361
- * @access private
1362
- */
1363
- function _setupInlineCrypt()
1364
- {
1365
- $lambda_functions =& Crypt_DES::_getLambdaFunctions();
1366
-
1367
- // Engine configuration for:
1368
- // - DES ($des_rounds == 1) or
1369
- // - 3DES ($des_rounds == 3)
1370
- $des_rounds = $this->des_rounds;
1371
-
1372
- // We create max. 10 hi-optimized code for memory reason. Means: For each $key one ultra fast inline-crypt function.
1373
- // (Currently, for Crypt_DES, one generated $lambda_function cost on php5.5@32bit ~135kb unfreeable mem and ~230kb on php5.5@64bit)
1374
- // (Currently, for Crypt_TripleDES, one generated $lambda_function cost on php5.5@32bit ~240kb unfreeable mem and ~340kb on php5.5@64bit)
1375
- // After that, we'll still create very fast optimized code but not the hi-ultimative code, for each $mode one
1376
- $gen_hi_opt_code = (bool)( count($lambda_functions) < 10 );
1377
-
1378
- // Generation of a unique hash for our generated code
1379
- $code_hash = "Crypt_DES, $des_rounds, {$this->mode}";
1380
- if ($gen_hi_opt_code) {
1381
- // For hi-optimized code, we create for each combination of
1382
- // $mode, $des_rounds and $this->key its own encrypt/decrypt function.
1383
- // After max 10 hi-optimized functions, we create generic
1384
- // (still very fast.. but not ultra) functions for each $mode/$des_rounds
1385
- // Currently 2 * 5 generic functions will be then max. possible.
1386
- $code_hash = str_pad($code_hash, 32) . $this->_hashInlineCryptFunction($this->key);
1387
- }
1388
-
1389
- // Is there a re-usable $lambda_functions in there? If not, we have to create it.
1390
- if (!isset($lambda_functions[$code_hash])) {
1391
- // Init code for both, encrypt and decrypt.
1392
- $init_crypt = 'static $sbox1, $sbox2, $sbox3, $sbox4, $sbox5, $sbox6, $sbox7, $sbox8, $shuffleip, $shuffleinvip;
1393
- if (!$sbox1) {
1394
- $sbox1 = array_map("intval", $self->sbox1);
1395
- $sbox2 = array_map("intval", $self->sbox2);
1396
- $sbox3 = array_map("intval", $self->sbox3);
1397
- $sbox4 = array_map("intval", $self->sbox4);
1398
- $sbox5 = array_map("intval", $self->sbox5);
1399
- $sbox6 = array_map("intval", $self->sbox6);
1400
- $sbox7 = array_map("intval", $self->sbox7);
1401
- $sbox8 = array_map("intval", $self->sbox8);'
1402
- /* Merge $shuffle with $[inv]ipmap */ . '
1403
- for ($i = 0; $i < 256; ++$i) {
1404
- $shuffleip[] = $self->shuffle[$self->ipmap[$i]];
1405
- $shuffleinvip[] = $self->shuffle[$self->invipmap[$i]];
1406
- }
1407
- }
1408
- ';
1409
-
1410
- switch (true) {
1411
- case $gen_hi_opt_code:
1412
- // In Hi-optimized code mode, we use our [3]DES key schedule as hardcoded integers.
1413
- // No futher initialisation of the $keys schedule is necessary.
1414
- // That is the extra performance boost.
1415
- $k = array(
1416
- CRYPT_DES_ENCRYPT => $this->keys[CRYPT_DES_ENCRYPT],
1417
- CRYPT_DES_DECRYPT => $this->keys[CRYPT_DES_DECRYPT]
1418
- );
1419
- $init_encrypt = '';
1420
- $init_decrypt = '';
1421
- break;
1422
- default:
1423
- // In generic optimized code mode, we have to use, as the best compromise [currently],
1424
- // our key schedule as $ke/$kd arrays. (with hardcoded indexes...)
1425
- $k = array(
1426
- CRYPT_DES_ENCRYPT => array(),
1427
- CRYPT_DES_DECRYPT => array()
1428
- );
1429
- for ($i = 0, $c = count($this->keys[CRYPT_DES_ENCRYPT]); $i < $c; ++$i) {
1430
- $k[CRYPT_DES_ENCRYPT][$i] = '$ke[' . $i . ']';
1431
- $k[CRYPT_DES_DECRYPT][$i] = '$kd[' . $i . ']';
1432
- }
1433
- $init_encrypt = '$ke = $self->keys[CRYPT_DES_ENCRYPT];';
1434
- $init_decrypt = '$kd = $self->keys[CRYPT_DES_DECRYPT];';
1435
- break;
1436
- }
1437
-
1438
- // Creating code for en- and decryption.
1439
- $crypt_block = array();
1440
- foreach (array(CRYPT_DES_ENCRYPT, CRYPT_DES_DECRYPT) as $c) {
1441
- /* Do the initial IP permutation. */
1442
- $crypt_block[$c] = '
1443
- $in = unpack("N*", $in);
1444
- $l = $in[1];
1445
- $r = $in[2];
1446
- $in = unpack("N*",
1447
- ($shuffleip[ $r & 0xFF] & "\x80\x80\x80\x80\x80\x80\x80\x80") |
1448
- ($shuffleip[($r >> 8) & 0xFF] & "\x40\x40\x40\x40\x40\x40\x40\x40") |
1449
- ($shuffleip[($r >> 16) & 0xFF] & "\x20\x20\x20\x20\x20\x20\x20\x20") |
1450
- ($shuffleip[($r >> 24) & 0xFF] & "\x10\x10\x10\x10\x10\x10\x10\x10") |
1451
- ($shuffleip[ $l & 0xFF] & "\x08\x08\x08\x08\x08\x08\x08\x08") |
1452
- ($shuffleip[($l >> 8) & 0xFF] & "\x04\x04\x04\x04\x04\x04\x04\x04") |
1453
- ($shuffleip[($l >> 16) & 0xFF] & "\x02\x02\x02\x02\x02\x02\x02\x02") |
1454
- ($shuffleip[($l >> 24) & 0xFF] & "\x01\x01\x01\x01\x01\x01\x01\x01")
1455
- );
1456
- ' . /* Extract L0 and R0 */ '
1457
- $l = $in[1];
1458
- $r = $in[2];
1459
- ';
1460
-
1461
- $l = '$l';
1462
- $r = '$r';
1463
-
1464
- // Perform DES or 3DES.
1465
- for ($ki = -1, $des_round = 0; $des_round < $des_rounds; ++$des_round) {
1466
- // Perform the 16 steps.
1467
- for ($i = 0; $i < 16; ++$i) {
1468
- // start of "the Feistel (F) function" - see the following URL:
1469
- // http://en.wikipedia.org/wiki/Image:Data_Encryption_Standard_InfoBox_Diagram.png
1470
- // Merge key schedule.
1471
- $crypt_block[$c].= '
1472
- $b1 = ((' . $r . ' >> 3) & 0x1FFFFFFF) ^ (' . $r . ' << 29) ^ ' . $k[$c][++$ki] . ';
1473
- $b2 = ((' . $r . ' >> 31) & 0x00000001) ^ (' . $r . ' << 1) ^ ' . $k[$c][++$ki] . ';' .
1474
- /* S-box indexing. */
1475
- $l . ' = $sbox1[($b1 >> 24) & 0x3F] ^ $sbox2[($b2 >> 24) & 0x3F] ^
1476
- $sbox3[($b1 >> 16) & 0x3F] ^ $sbox4[($b2 >> 16) & 0x3F] ^
1477
- $sbox5[($b1 >> 8) & 0x3F] ^ $sbox6[($b2 >> 8) & 0x3F] ^
1478
- $sbox7[ $b1 & 0x3F] ^ $sbox8[ $b2 & 0x3F] ^ ' . $l . ';
1479
- ';
1480
- // end of "the Feistel (F) function"
1481
-
1482
- // swap L & R
1483
- list($l, $r) = array($r, $l);
1484
- }
1485
- list($l, $r) = array($r, $l);
1486
- }
1487
-
1488
- // Perform the inverse IP permutation.
1489
- $crypt_block[$c].= '$in =
1490
- ($shuffleinvip[($l >> 24) & 0xFF] & "\x80\x80\x80\x80\x80\x80\x80\x80") |
1491
- ($shuffleinvip[($r >> 24) & 0xFF] & "\x40\x40\x40\x40\x40\x40\x40\x40") |
1492
- ($shuffleinvip[($l >> 16) & 0xFF] & "\x20\x20\x20\x20\x20\x20\x20\x20") |
1493
- ($shuffleinvip[($r >> 16) & 0xFF] & "\x10\x10\x10\x10\x10\x10\x10\x10") |
1494
- ($shuffleinvip[($l >> 8) & 0xFF] & "\x08\x08\x08\x08\x08\x08\x08\x08") |
1495
- ($shuffleinvip[($r >> 8) & 0xFF] & "\x04\x04\x04\x04\x04\x04\x04\x04") |
1496
- ($shuffleinvip[ $l & 0xFF] & "\x02\x02\x02\x02\x02\x02\x02\x02") |
1497
- ($shuffleinvip[ $r & 0xFF] & "\x01\x01\x01\x01\x01\x01\x01\x01");
1498
- ';
1499
- }
1500
-
1501
- // Creates the inline-crypt function
1502
- $lambda_functions[$code_hash] = $this->_createInlineCryptFunction(
1503
- array(
1504
- 'init_crypt' => $init_crypt,
1505
- 'init_encrypt' => $init_encrypt,
1506
- 'init_decrypt' => $init_decrypt,
1507
- 'encrypt_block' => $crypt_block[CRYPT_DES_ENCRYPT],
1508
- 'decrypt_block' => $crypt_block[CRYPT_DES_DECRYPT]
1509
- )
1510
- );
1511
- }
1512
-
1513
- // Set the inline-crypt function as callback in: $this->inline_crypt
1514
- $this->inline_crypt = $lambda_functions[$code_hash];
1515
- }
1516
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/phpseclib/Crypt/Hash.php DELETED
@@ -1,861 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Pure-PHP implementations of keyed-hash message authentication codes (HMACs) and various cryptographic hashing functions.
5
- *
6
- * Uses hash() or mhash() if available and an internal implementation, otherwise. Currently supports the following:
7
- *
8
- * md2, md5, md5-96, sha1, sha1-96, sha256, sha256-96, sha384, and sha512, sha512-96
9
- *
10
- * If {@link self::setKey() setKey()} is called, {@link self::hash() hash()} will return the HMAC as opposed to
11
- * the hash. If no valid algorithm is provided, sha1 will be used.
12
- *
13
- * PHP versions 4 and 5
14
- *
15
- * {@internal The variable names are the same as those in
16
- * {@link http://tools.ietf.org/html/rfc2104#section-2 RFC2104}.}}
17
- *
18
- * Here's a short example of how to use this library:
19
- * <code>
20
- * <?php
21
- * include 'Crypt/Hash.php';
22
- *
23
- * $hash = new Crypt_Hash('sha1');
24
- *
25
- * $hash->setKey('abcdefg');
26
- *
27
- * echo base64_encode($hash->hash('abcdefg'));
28
- * ?>
29
- * </code>
30
- *
31
- * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
32
- * of this software and associated documentation files (the "Software"), to deal
33
- * in the Software without restriction, including without limitation the rights
34
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
35
- * copies of the Software, and to permit persons to whom the Software is
36
- * furnished to do so, subject to the following conditions:
37
- *
38
- * The above copyright notice and this permission notice shall be included in
39
- * all copies or substantial portions of the Software.
40
- *
41
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
42
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
43
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
44
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
45
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
46
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
47
- * THE SOFTWARE.
48
- *
49
- * @category Crypt
50
- * @package Crypt_Hash
51
- * @author Jim Wigginton <terrafrost@php.net>
52
- * @copyright 2007 Jim Wigginton
53
- * @license http://www.opensource.org/licenses/mit-license.html MIT License
54
- * @link http://phpseclib.sourceforge.net
55
- */
56
-
57
- /**#@+
58
- * @access private
59
- * @see self::Crypt_Hash()
60
- */
61
- /**
62
- * Toggles the internal implementation
63
- */
64
- define('CRYPT_HASH_MODE_INTERNAL', 1);
65
- /**
66
- * Toggles the mhash() implementation, which has been deprecated on PHP 5.3.0+.
67
- */
68
- define('CRYPT_HASH_MODE_MHASH', 2);
69
- /**
70
- * Toggles the hash() implementation, which works on PHP 5.1.2+.
71
- */
72
- define('CRYPT_HASH_MODE_HASH', 3);
73
- /**#@-*/
74
-
75
- /**
76
- * Pure-PHP implementations of keyed-hash message authentication codes (HMACs) and various cryptographic hashing functions.
77
- *
78
- * @package Crypt_Hash
79
- * @author Jim Wigginton <terrafrost@php.net>
80
- * @access public
81
- */
82
- class Crypt_Hash
83
- {
84
- /**
85
- * Hash Parameter
86
- *
87
- * @see self::setHash()
88
- * @var int
89
- * @access private
90
- */
91
- var $hashParam;
92
-
93
- /**
94
- * Byte-length of compression blocks / key (Internal HMAC)
95
- *
96
- * @see self::setAlgorithm()
97
- * @var int
98
- * @access private
99
- */
100
- var $b;
101
-
102
- /**
103
- * Byte-length of hash output (Internal HMAC)
104
- *
105
- * @see self::setHash()
106
- * @var int
107
- * @access private
108
- */
109
- var $l = false;
110
-
111
- /**
112
- * Hash Algorithm
113
- *
114
- * @see self::setHash()
115
- * @var string
116
- * @access private
117
- */
118
- var $hash;
119
-
120
- /**
121
- * Key
122
- *
123
- * @see self::setKey()
124
- * @var string
125
- * @access private
126
- */
127
- var $key = false;
128
-
129
- /**
130
- * Outer XOR (Internal HMAC)
131
- *
132
- * @see self::setKey()
133
- * @var string
134
- * @access private
135
- */
136
- var $opad;
137
-
138
- /**
139
- * Inner XOR (Internal HMAC)
140
- *
141
- * @see self::setKey()
142
- * @var string
143
- * @access private
144
- */
145
- var $ipad;
146
-
147
- /**
148
- * Default Constructor.
149
- *
150
- * @param string $hash
151
- * @return Crypt_Hash
152
- * @access public
153
- */
154
- function __construct($hash = 'sha1')
155
- {
156
- if (!defined('CRYPT_HASH_MODE')) {
157
- switch (true) {
158
- case extension_loaded('hash'):
159
- define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_HASH);
160
- break;
161
- case extension_loaded('mhash'):
162
- define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_MHASH);
163
- break;
164
- default:
165
- define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_INTERNAL);
166
- }
167
- }
168
-
169
- $this->setHash($hash);
170
- }
171
-
172
- /**
173
- * PHP4 compatible Default Constructor.
174
- *
175
- * @see self::__construct()
176
- * @param int $mode
177
- * @access public
178
- */
179
- function Crypt_Hash($hash = 'sha1')
180
- {
181
- $this->__construct($mode);
182
- }
183
-
184
- /**
185
- * Sets the key for HMACs
186
- *
187
- * Keys can be of any length.
188
- *
189
- * @access public
190
- * @param string $key
191
- */
192
- function setKey($key = false)
193
- {
194
- $this->key = $key;
195
- }
196
-
197
- /**
198
- * Gets the hash function.
199
- *
200
- * As set by the constructor or by the setHash() method.
201
- *
202
- * @access public
203
- * @return string
204
- */
205
- function getHash()
206
- {
207
- return $this->hashParam;
208
- }
209
-
210
- /**
211
- * Sets the hash function.
212
- *
213
- * @access public
214
- * @param string $hash
215
- */
216
- function setHash($hash)
217
- {
218
- $this->hashParam = $hash = strtolower($hash);
219
- switch ($hash) {
220
- case 'md5-96':
221
- case 'sha1-96':
222
- case 'sha256-96':
223
- case 'sha512-96':
224
- $hash = substr($hash, 0, -3);
225
- $this->l = 12; // 96 / 8 = 12
226
- break;
227
- case 'md2':
228
- case 'md5':
229
- $this->l = 16;
230
- break;
231
- case 'sha1':
232
- $this->l = 20;
233
- break;
234
- case 'sha256':
235
- $this->l = 32;
236
- break;
237
- case 'sha384':
238
- $this->l = 48;
239
- break;
240
- case 'sha512':
241
- $this->l = 64;
242
- }
243
-
244
- switch ($hash) {
245
- case 'md2':
246
- $mode = CRYPT_HASH_MODE == CRYPT_HASH_MODE_HASH && in_array('md2', hash_algos()) ?
247
- CRYPT_HASH_MODE_HASH : CRYPT_HASH_MODE_INTERNAL;
248
- break;
249
- case 'sha384':
250
- case 'sha512':
251
- $mode = CRYPT_HASH_MODE == CRYPT_HASH_MODE_MHASH ? CRYPT_HASH_MODE_INTERNAL : CRYPT_HASH_MODE;
252
- break;
253
- default:
254
- $mode = CRYPT_HASH_MODE;
255
- }
256
-
257
- switch ($mode) {
258
- case CRYPT_HASH_MODE_MHASH:
259
- switch ($hash) {
260
- case 'md5':
261
- $this->hash = MHASH_MD5;
262
- break;
263
- case 'sha256':
264
- $this->hash = MHASH_SHA256;
265
- break;
266
- case 'sha1':
267
- default:
268
- $this->hash = MHASH_SHA1;
269
- }
270
- return;
271
- case CRYPT_HASH_MODE_HASH:
272
- switch ($hash) {
273
- case 'md5':
274
- $this->hash = 'md5';
275
- return;
276
- case 'md2':
277
- case 'sha256':
278
- case 'sha384':
279
- case 'sha512':
280
- $this->hash = $hash;
281
- return;
282
- case 'sha1':
283
- default:
284
- $this->hash = 'sha1';
285
- }
286
- return;
287
- }
288
-
289
- switch ($hash) {
290
- case 'md2':
291
- $this->b = 16;
292
- $this->hash = array($this, '_md2');
293
- break;
294
- case 'md5':
295
- $this->b = 64;
296
- $this->hash = array($this, '_md5');
297
- break;
298
- case 'sha256':
299
- $this->b = 64;
300
- $this->hash = array($this, '_sha256');
301
- break;
302
- case 'sha384':
303
- case 'sha512':
304
- $this->b = 128;
305
- $this->hash = array($this, '_sha512');
306
- break;
307
- case 'sha1':
308
- default:
309
- $this->b = 64;
310
- $this->hash = array($this, '_sha1');
311
- }
312
-
313
- $this->ipad = str_repeat(chr(0x36), $this->b);
314
- $this->opad = str_repeat(chr(0x5C), $this->b);
315
- }
316
-
317
- /**
318
- * Compute the HMAC.
319
- *
320
- * @access public
321
- * @param string $text
322
- * @return string
323
- */
324
- function hash($text)
325
- {
326
- $mode = is_array($this->hash) ? CRYPT_HASH_MODE_INTERNAL : CRYPT_HASH_MODE;
327
-
328
- if (!empty($this->key) || is_string($this->key)) {
329
- switch ($mode) {
330
- case CRYPT_HASH_MODE_MHASH:
331
- $output = mhash($this->hash, $text, $this->key);
332
- break;
333
- case CRYPT_HASH_MODE_HASH:
334
- $output = hash_hmac($this->hash, $text, $this->key, true);
335
- break;
336
- case CRYPT_HASH_MODE_INTERNAL:
337
- /* "Applications that use keys longer than B bytes will first hash the key using H and then use the
338
- resultant L byte string as the actual key to HMAC."
339
-
340
- -- http://tools.ietf.org/html/rfc2104#section-2 */
341
- $key = strlen($this->key) > $this->b ? call_user_func($this->hash, $this->key) : $this->key;
342
-
343
- $key = str_pad($key, $this->b, chr(0)); // step 1
344
- $temp = $this->ipad ^ $key; // step 2
345
- $temp .= $text; // step 3
346
- $temp = call_user_func($this->hash, $temp); // step 4
347
- $output = $this->opad ^ $key; // step 5
348
- $output.= $temp; // step 6
349
- $output = call_user_func($this->hash, $output); // step 7
350
- }
351
- } else {
352
- switch ($mode) {
353
- case CRYPT_HASH_MODE_MHASH:
354
- $output = mhash($this->hash, $text);
355
- break;
356
- case CRYPT_HASH_MODE_HASH:
357
- $output = hash($this->hash, $text, true);
358
- break;
359
- case CRYPT_HASH_MODE_INTERNAL:
360
- $output = call_user_func($this->hash, $text);
361
- }
362
- }
363
-
364
- return substr($output, 0, $this->l);
365
- }
366
-
367
- /**
368
- * Returns the hash length (in bytes)
369
- *
370
- * @access public
371
- * @return int
372
- */
373
- function getLength()
374
- {
375
- return $this->l;
376
- }
377
-
378
- /**
379
- * Wrapper for MD5
380
- *
381
- * @access private
382
- * @param string $m
383
- */
384
- function _md5($m)
385
- {
386
- return pack('H*', md5($m));
387
- }
388
-
389
- /**
390
- * Wrapper for SHA1
391
- *
392
- * @access private
393
- * @param string $m
394
- */
395
- function _sha1($m)
396
- {
397
- return pack('H*', sha1($m));
398
- }
399
-
400
- /**
401
- * Pure-PHP implementation of MD2
402
- *
403
- * See {@link http://tools.ietf.org/html/rfc1319 RFC1319}.
404
- *
405
- * @access private
406
- * @param string $m
407
- */
408
- function _md2($m)
409
- {
410
- static $s = array(
411
- 41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6,
412
- 19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188,
413
- 76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24,
414
- 138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251,
415
- 245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63,
416
- 148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50,
417
- 39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165,
418
- 181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210,
419
- 150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157,
420
- 112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27,
421
- 96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15,
422
- 85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197,
423
- 234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65,
424
- 129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123,
425
- 8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233,
426
- 203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228,
427
- 166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237,
428
- 31, 26, 219, 153, 141, 51, 159, 17, 131, 20
429
- );
430
-
431
- // Step 1. Append Padding Bytes
432
- $pad = 16 - (strlen($m) & 0xF);
433
- $m.= str_repeat(chr($pad), $pad);
434
-
435
- $length = strlen($m);
436
-
437
- // Step 2. Append Checksum
438
- $c = str_repeat(chr(0), 16);
439
- $l = chr(0);
440
- for ($i = 0; $i < $length; $i+= 16) {
441
- for ($j = 0; $j < 16; $j++) {
442
- // RFC1319 incorrectly states that C[j] should be set to S[c xor L]
443
- //$c[$j] = chr($s[ord($m[$i + $j] ^ $l)]);
444
- // 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]
445
- $c[$j] = chr($s[ord($m[$i + $j] ^ $l)] ^ ord($c[$j]));
446
- $l = $c[$j];
447
- }
448
- }
449
- $m.= $c;
450
-
451
- $length+= 16;
452
-
453
- // Step 3. Initialize MD Buffer
454
- $x = str_repeat(chr(0), 48);
455
-
456
- // Step 4. Process Message in 16-Byte Blocks
457
- for ($i = 0; $i < $length; $i+= 16) {
458
- for ($j = 0; $j < 16; $j++) {
459
- $x[$j + 16] = $m[$i + $j];
460
- $x[$j + 32] = $x[$j + 16] ^ $x[$j];
461
- }
462
- $t = chr(0);
463
- for ($j = 0; $j < 18; $j++) {
464
- for ($k = 0; $k < 48; $k++) {
465
- $x[$k] = $t = $x[$k] ^ chr($s[ord($t)]);
466
- //$t = $x[$k] = $x[$k] ^ chr($s[ord($t)]);
467
- }
468
- $t = chr(ord($t) + $j);
469
- }
470
- }
471
-
472
- // Step 5. Output
473
- return substr($x, 0, 16);
474
- }
475
-
476
- /**
477
- * Pure-PHP implementation of SHA256
478
- *
479
- * 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}.
480
- *
481
- * @access private
482
- * @param string $m
483
- */
484
- function _sha256($m)
485
- {
486
- if (extension_loaded('suhosin')) {
487
- return pack('H*', sha256($m));
488
- }
489
-
490
- // Initialize variables
491
- $hash = array(
492
- 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
493
- );
494
- // Initialize table of round constants
495
- // (first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311)
496
- static $k = array(
497
- 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
498
- 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
499
- 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
500
- 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
501
- 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
502
- 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
503
- 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
504
- 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
505
- );
506
-
507
- // Pre-processing
508
- $length = strlen($m);
509
- // to round to nearest 56 mod 64, we'll add 64 - (length + (64 - 56)) % 64
510
- $m.= str_repeat(chr(0), 64 - (($length + 8) & 0x3F));
511
- $m[$length] = chr(0x80);
512
- // we don't support hashing strings 512MB long
513
- $m.= pack('N2', 0, $length << 3);
514
-
515
- // Process the message in successive 512-bit chunks
516
- $chunks = str_split($m, 64);
517
- foreach ($chunks as $chunk) {
518
- $w = array();
519
- for ($i = 0; $i < 16; $i++) {
520
- extract(unpack('Ntemp', $this->_string_shift($chunk, 4)));
521
- $w[] = $temp;
522
- }
523
-
524
- // Extend the sixteen 32-bit words into sixty-four 32-bit words
525
- for ($i = 16; $i < 64; $i++) {
526
- // @codingStandardsIgnoreStart
527
- $s0 = $this->_rightRotate($w[$i - 15], 7) ^
528
- $this->_rightRotate($w[$i - 15], 18) ^
529
- $this->_rightShift( $w[$i - 15], 3);
530
- $s1 = $this->_rightRotate($w[$i - 2], 17) ^
531
- $this->_rightRotate($w[$i - 2], 19) ^
532
- $this->_rightShift( $w[$i - 2], 10);
533
- // @codingStandardsIgnoreEnd
534
- $w[$i] = $this->_add($w[$i - 16], $s0, $w[$i - 7], $s1);
535
- }
536
-
537
- // Initialize hash value for this chunk
538
- list($a, $b, $c, $d, $e, $f, $g, $h) = $hash;
539
-
540
- // Main loop
541
- for ($i = 0; $i < 64; $i++) {
542
- $s0 = $this->_rightRotate($a, 2) ^
543
- $this->_rightRotate($a, 13) ^
544
- $this->_rightRotate($a, 22);
545
- $maj = ($a & $b) ^
546
- ($a & $c) ^
547
- ($b & $c);
548
- $t2 = $this->_add($s0, $maj);
549
-
550
- $s1 = $this->_rightRotate($e, 6) ^
551
- $this->_rightRotate($e, 11) ^
552
- $this->_rightRotate($e, 25);
553
- $ch = ($e & $f) ^
554
- ($this->_not($e) & $g);
555
- $t1 = $this->_add($h, $s1, $ch, $k[$i], $w[$i]);
556
-
557
- $h = $g;
558
- $g = $f;
559
- $f = $e;
560
- $e = $this->_add($d, $t1);
561
- $d = $c;
562
- $c = $b;
563
- $b = $a;
564
- $a = $this->_add($t1, $t2);
565
- }
566
-
567
- // Add this chunk's hash to result so far
568
- $hash = array(
569
- $this->_add($hash[0], $a),
570
- $this->_add($hash[1], $b),
571
- $this->_add($hash[2], $c),
572
- $this->_add($hash[3], $d),
573
- $this->_add($hash[4], $e),
574
- $this->_add($hash[5], $f),
575
- $this->_add($hash[6], $g),
576
- $this->_add($hash[7], $h)
577
- );
578
- }
579
-
580
- // Produce the final hash value (big-endian)
581
- return pack('N8', $hash[0], $hash[1], $hash[2], $hash[3], $hash[4], $hash[5], $hash[6], $hash[7]);
582
- }
583
-
584
- /**
585
- * Pure-PHP implementation of SHA384 and SHA512
586
- *
587
- * @access private
588
- * @param string $m
589
- */
590
- function _sha512($m)
591
- {
592
- if (!class_exists('Math_BigInteger')) {
593
- include_once 'Math/BigInteger.php';
594
- }
595
-
596
- static $init384, $init512, $k;
597
-
598
- if (!isset($k)) {
599
- // Initialize variables
600
- $init384 = array( // initial values for SHA384
601
- 'cbbb9d5dc1059ed8', '629a292a367cd507', '9159015a3070dd17', '152fecd8f70e5939',
602
- '67332667ffc00b31', '8eb44a8768581511', 'db0c2e0d64f98fa7', '47b5481dbefa4fa4'
603
- );
604
- $init512 = array( // initial values for SHA512
605
- '6a09e667f3bcc908', 'bb67ae8584caa73b', '3c6ef372fe94f82b', 'a54ff53a5f1d36f1',
606
- '510e527fade682d1', '9b05688c2b3e6c1f', '1f83d9abfb41bd6b', '5be0cd19137e2179'
607
- );
608
-
609
- for ($i = 0; $i < 8; $i++) {
610
- $init384[$i] = new Math_BigInteger($init384[$i], 16);
611
- $init384[$i]->setPrecision(64);
612
- $init512[$i] = new Math_BigInteger($init512[$i], 16);
613
- $init512[$i]->setPrecision(64);
614
- }
615
-
616
- // Initialize table of round constants
617
- // (first 64 bits of the fractional parts of the cube roots of the first 80 primes 2..409)
618
- $k = array(
619
- '428a2f98d728ae22', '7137449123ef65cd', 'b5c0fbcfec4d3b2f', 'e9b5dba58189dbbc',
620
- '3956c25bf348b538', '59f111f1b605d019', '923f82a4af194f9b', 'ab1c5ed5da6d8118',
621
- 'd807aa98a3030242', '12835b0145706fbe', '243185be4ee4b28c', '550c7dc3d5ffb4e2',
622
- '72be5d74f27b896f', '80deb1fe3b1696b1', '9bdc06a725c71235', 'c19bf174cf692694',
623
- 'e49b69c19ef14ad2', 'efbe4786384f25e3', '0fc19dc68b8cd5b5', '240ca1cc77ac9c65',
624
- '2de92c6f592b0275', '4a7484aa6ea6e483', '5cb0a9dcbd41fbd4', '76f988da831153b5',
625
- '983e5152ee66dfab', 'a831c66d2db43210', 'b00327c898fb213f', 'bf597fc7beef0ee4',
626
- 'c6e00bf33da88fc2', 'd5a79147930aa725', '06ca6351e003826f', '142929670a0e6e70',
627
- '27b70a8546d22ffc', '2e1b21385c26c926', '4d2c6dfc5ac42aed', '53380d139d95b3df',
628
- '650a73548baf63de', '766a0abb3c77b2a8', '81c2c92e47edaee6', '92722c851482353b',
629
- 'a2bfe8a14cf10364', 'a81a664bbc423001', 'c24b8b70d0f89791', 'c76c51a30654be30',
630
- 'd192e819d6ef5218', 'd69906245565a910', 'f40e35855771202a', '106aa07032bbd1b8',
631
- '19a4c116b8d2d0c8', '1e376c085141ab53', '2748774cdf8eeb99', '34b0bcb5e19b48a8',
632
- '391c0cb3c5c95a63', '4ed8aa4ae3418acb', '5b9cca4f7763e373', '682e6ff3d6b2b8a3',
633
- '748f82ee5defb2fc', '78a5636f43172f60', '84c87814a1f0ab72', '8cc702081a6439ec',
634
- '90befffa23631e28', 'a4506cebde82bde9', 'bef9a3f7b2c67915', 'c67178f2e372532b',
635
- 'ca273eceea26619c', 'd186b8c721c0c207', 'eada7dd6cde0eb1e', 'f57d4f7fee6ed178',
636
- '06f067aa72176fba', '0a637dc5a2c898a6', '113f9804bef90dae', '1b710b35131c471b',
637
- '28db77f523047d84', '32caab7b40c72493', '3c9ebe0a15c9bebc', '431d67c49c100d4c',
638
- '4cc5d4becb3e42b6', '597f299cfc657e2a', '5fcb6fab3ad6faec', '6c44198c4a475817'
639
- );
640
-
641
- for ($i = 0; $i < 80; $i++) {
642
- $k[$i] = new Math_BigInteger($k[$i], 16);
643
- }
644
- }
645
-
646
- $hash = $this->l == 48 ? $init384 : $init512;
647
-
648
- // Pre-processing
649
- $length = strlen($m);
650
- // to round to nearest 112 mod 128, we'll add 128 - (length + (128 - 112)) % 128
651
- $m.= str_repeat(chr(0), 128 - (($length + 16) & 0x7F));
652
- $m[$length] = chr(0x80);
653
- // we don't support hashing strings 512MB long
654
- $m.= pack('N4', 0, 0, 0, $length << 3);
655
-
656
- // Process the message in successive 1024-bit chunks
657
- $chunks = str_split($m, 128);
658
- foreach ($chunks as $chunk) {
659
- $w = array();
660
- for ($i = 0; $i < 16; $i++) {
661
- $temp = new Math_BigInteger($this->_string_shift($chunk, 8), 256);
662
- $temp->setPrecision(64);
663
- $w[] = $temp;
664
- }
665
-
666
- // Extend the sixteen 32-bit words into eighty 32-bit words
667
- for ($i = 16; $i < 80; $i++) {
668
- $temp = array(
669
- $w[$i - 15]->bitwise_rightRotate(1),
670
- $w[$i - 15]->bitwise_rightRotate(8),
671
- $w[$i - 15]->bitwise_rightShift(7)
672
- );
673
- $s0 = $temp[0]->bitwise_xor($temp[1]);
674
- $s0 = $s0->bitwise_xor($temp[2]);
675
- $temp = array(
676
- $w[$i - 2]->bitwise_rightRotate(19),
677
- $w[$i - 2]->bitwise_rightRotate(61),
678
- $w[$i - 2]->bitwise_rightShift(6)
679
- );
680
- $s1 = $temp[0]->bitwise_xor($temp[1]);
681
- $s1 = $s1->bitwise_xor($temp[2]);
682
- $w[$i] = $w[$i - 16]->copy();
683
- $w[$i] = $w[$i]->add($s0);
684
- $w[$i] = $w[$i]->add($w[$i - 7]);
685
- $w[$i] = $w[$i]->add($s1);
686
- }
687
-
688
- // Initialize hash value for this chunk
689
- $a = $hash[0]->copy();
690
- $b = $hash[1]->copy();
691
- $c = $hash[2]->copy();
692
- $d = $hash[3]->copy();
693
- $e = $hash[4]->copy();
694
- $f = $hash[5]->copy();
695
- $g = $hash[6]->copy();
696
- $h = $hash[7]->copy();
697
-
698
- // Main loop
699
- for ($i = 0; $i < 80; $i++) {
700
- $temp = array(
701
- $a->bitwise_rightRotate(28),
702
- $a->bitwise_rightRotate(34),
703
- $a->bitwise_rightRotate(39)
704
- );
705
- $s0 = $temp[0]->bitwise_xor($temp[1]);
706
- $s0 = $s0->bitwise_xor($temp[2]);
707
- $temp = array(
708
- $a->bitwise_and($b),
709
- $a->bitwise_and($c),
710
- $b->bitwise_and($c)
711
- );
712
- $maj = $temp[0]->bitwise_xor($temp[1]);
713
- $maj = $maj->bitwise_xor($temp[2]);
714
- $t2 = $s0->add($maj);
715
-
716
- $temp = array(
717
- $e->bitwise_rightRotate(14),
718
- $e->bitwise_rightRotate(18),
719
- $e->bitwise_rightRotate(41)
720
- );
721
- $s1 = $temp[0]->bitwise_xor($temp[1]);
722
- $s1 = $s1->bitwise_xor($temp[2]);
723
- $temp = array(
724
- $e->bitwise_and($f),
725
- $g->bitwise_and($e->bitwise_not())
726
- );
727
- $ch = $temp[0]->bitwise_xor($temp[1]);
728
- $t1 = $h->add($s1);
729
- $t1 = $t1->add($ch);
730
- $t1 = $t1->add($k[$i]);
731
- $t1 = $t1->add($w[$i]);
732
-
733
- $h = $g->copy();
734
- $g = $f->copy();
735
- $f = $e->copy();
736
- $e = $d->add($t1);
737
- $d = $c->copy();
738
- $c = $b->copy();
739
- $b = $a->copy();
740
- $a = $t1->add($t2);
741
- }
742
-
743
- // Add this chunk's hash to result so far
744
- $hash = array(
745
- $hash[0]->add($a),
746
- $hash[1]->add($b),
747
- $hash[2]->add($c),
748
- $hash[3]->add($d),
749
- $hash[4]->add($e),
750
- $hash[5]->add($f),
751
- $hash[6]->add($g),
752
- $hash[7]->add($h)
753
- );
754
- }
755
-
756
- // Produce the final hash value (big-endian)
757
- // (Crypt_Hash::hash() trims the output for hashes but not for HMACs. as such, we trim the output here)
758
- $temp = $hash[0]->toBytes() . $hash[1]->toBytes() . $hash[2]->toBytes() . $hash[3]->toBytes() .
759
- $hash[4]->toBytes() . $hash[5]->toBytes();
760
- if ($this->l != 48) {
761
- $temp.= $hash[6]->toBytes() . $hash[7]->toBytes();
762
- }
763
-
764
- return $temp;
765
- }
766
-
767
- /**
768
- * Right Rotate
769
- *
770
- * @access private
771
- * @param int $int
772
- * @param int $amt
773
- * @see self::_sha256()
774
- * @return int
775
- */
776
- function _rightRotate($int, $amt)
777
- {
778
- $invamt = 32 - $amt;
779
- $mask = (1 << $invamt) - 1;
780
- return (($int << $invamt) & 0xFFFFFFFF) | (($int >> $amt) & $mask);
781
- }
782
-
783
- /**
784
- * Right Shift
785
- *
786
- * @access private
787
- * @param int $int
788
- * @param int $amt
789
- * @see self::_sha256()
790
- * @return int
791
- */
792
- function _rightShift($int, $amt)
793
- {
794
- $mask = (1 << (32 - $amt)) - 1;
795
- return ($int >> $amt) & $mask;
796
- }
797
-
798
- /**
799
- * Not
800
- *
801
- * @access private
802
- * @param int $int
803
- * @see self::_sha256()
804
- * @return int
805
- */
806
- function _not($int)
807
- {
808
- return ~$int & 0xFFFFFFFF;
809
- }
810
-
811
- /**
812
- * Add
813
- *
814
- * _sha256() adds multiple unsigned 32-bit integers. Since PHP doesn't support unsigned integers and since the
815
- * possibility of overflow exists, care has to be taken. Math_BigInteger() could be used but this should be faster.
816
- *
817
- * @param int $...
818
- * @return int
819
- * @see self::_sha256()
820
- * @access private
821
- */
822
- function _add()
823
- {
824
- static $mod;
825
- if (!isset($mod)) {
826
- $mod = pow(2, 32);
827
- }
828
-
829
- $result = 0;
830
- $arguments = func_get_args();
831
- foreach ($arguments as $argument) {
832
- $result+= $argument < 0 ? ($argument & 0x7FFFFFFF) + 0x80000000 : $argument;
833
- }
834
-
835
- // PHP 5.3, per http://php.net/releases/5_3_0.php, introduced "more consistent float rounding"
836
- // PHP_OS & "\xDF\xDF\xDF" == strtoupper(substr(PHP_OS, 0, 3)), but a lot faster
837
- if (is_int($result) || version_compare(PHP_VERSION, '5.3.0') >= 0 || (PHP_OS & "\xDF\xDF\xDF") === 'WIN') {
838
- return fmod($result, $mod);
839
- }
840
-
841
- return (fmod($result, 0x80000000) & 0x7FFFFFFF) |
842
- ((fmod(floor($result / 0x80000000), 2) & 1) << 31);
843
- }
844
-
845
- /**
846
- * String Shift
847
- *
848
- * Inspired by array_shift
849
- *
850
- * @param string $string
851
- * @param int $index
852
- * @return string
853
- * @access private
854
- */
855
- function _string_shift(&$string, $index = 1)
856
- {
857
- $substr = substr($string, 0, $index);
858
- $string = substr($string, $index);
859
- return $substr;
860
- }
861
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/phpseclib/Crypt/RC2.php DELETED
@@ -1,761 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Pure-PHP implementation of RC2.
5
- *
6
- * Uses mcrypt, if available, and an internal implementation, otherwise.
7
- *
8
- * PHP versions 4 and 5
9
- *
10
- * Useful resources are as follows:
11
- *
12
- * - {@link http://tools.ietf.org/html/rfc2268}
13
- *
14
- * Here's a short example of how to use this library:
15
- * <code>
16
- * <?php
17
- * include 'Crypt/RC2.php';
18
- *
19
- * $rc2 = new Crypt_RC2();
20
- *
21
- * $rc2->setKey('abcdefgh');
22
- *
23
- * $plaintext = str_repeat('a', 1024);
24
- *
25
- * echo $rc2->decrypt($rc2->encrypt($plaintext));
26
- * ?>
27
- * </code>
28
- *
29
- * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
30
- * of this software and associated documentation files (the "Software"), to deal
31
- * in the Software without restriction, including without limitation the rights
32
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
33
- * copies of the Software, and to permit persons to whom the Software is
34
- * furnished to do so, subject to the following conditions:
35
- *
36
- * The above copyright notice and this permission notice shall be included in
37
- * all copies or substantial portions of the Software.
38
- *
39
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
40
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
41
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
42
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
43
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
44
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
45
- * THE SOFTWARE.
46
- *
47
- * @category Crypt
48
- * @package Crypt_RC2
49
- * @author Patrick Monnerat <pm@datasphere.ch>
50
- * @license http://www.opensource.org/licenses/mit-license.html MIT License
51
- * @link http://phpseclib.sourceforge.net
52
- */
53
-
54
- /**
55
- * Include Crypt_Base
56
- *
57
- * Base cipher class
58
- */
59
- if (!class_exists('Crypt_Base')) {
60
- include_once 'Base.php';
61
- }
62
-
63
- /**#@+
64
- * @access public
65
- * @see self::encrypt()
66
- * @see self::decrypt()
67
- */
68
- /**
69
- * Encrypt / decrypt using the Counter mode.
70
- *
71
- * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
72
- *
73
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
74
- */
75
- define('CRYPT_RC2_MODE_CTR', CRYPT_MODE_CTR);
76
- /**
77
- * Encrypt / decrypt using the Electronic Code Book mode.
78
- *
79
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
80
- */
81
- define('CRYPT_RC2_MODE_ECB', CRYPT_MODE_ECB);
82
- /**
83
- * Encrypt / decrypt using the Code Book Chaining mode.
84
- *
85
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
86
- */
87
- define('CRYPT_RC2_MODE_CBC', CRYPT_MODE_CBC);
88
- /**
89
- * Encrypt / decrypt using the Cipher Feedback mode.
90
- *
91
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
92
- */
93
- define('CRYPT_RC2_MODE_CFB', CRYPT_MODE_CFB);
94
- /**
95
- * Encrypt / decrypt using the Cipher Feedback mode.
96
- *
97
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
98
- */
99
- define('CRYPT_RC2_MODE_OFB', CRYPT_MODE_OFB);
100
- /**#@-*/
101
-
102
- /**
103
- * Pure-PHP implementation of RC2.
104
- *
105
- * @package Crypt_RC2
106
- * @access public
107
- */
108
- class Crypt_RC2 extends Crypt_Base
109
- {
110
- /**
111
- * Block Length of the cipher
112
- *
113
- * @see Crypt_Base::block_size
114
- * @var int
115
- * @access private
116
- */
117
- var $block_size = 8;
118
-
119
- /**
120
- * The Key
121
- *
122
- * @see Crypt_Base::key
123
- * @see self::setKey()
124
- * @var string
125
- * @access private
126
- */
127
- var $key;
128
-
129
- /**
130
- * The Original (unpadded) Key
131
- *
132
- * @see Crypt_Base::key
133
- * @see self::setKey()
134
- * @see self::encrypt()
135
- * @see self::decrypt()
136
- * @var string
137
- * @access private
138
- */
139
- var $orig_key;
140
-
141
- /**
142
- * Don't truncate / null pad key
143
- *
144
- * @see Crypt_Base::_clearBuffers()
145
- * @var bool
146
- * @access private
147
- */
148
- var $skip_key_adjustment = true;
149
-
150
- /**
151
- * Key Length (in bytes)
152
- *
153
- * @see Crypt_RC2::setKeyLength()
154
- * @var int
155
- * @access private
156
- */
157
- var $key_length = 16; // = 128 bits
158
-
159
- /**
160
- * The namespace used by the cipher for its constants.
161
- *
162
- * @see Crypt_Base::const_namespace
163
- * @var string
164
- * @access private
165
- */
166
- var $const_namespace = 'RC2';
167
-
168
- /**
169
- * The mcrypt specific name of the cipher
170
- *
171
- * @see Crypt_Base::cipher_name_mcrypt
172
- * @var string
173
- * @access private
174
- */
175
- var $cipher_name_mcrypt = 'rc2';
176
-
177
- /**
178
- * Optimizing value while CFB-encrypting
179
- *
180
- * @see Crypt_Base::cfb_init_len
181
- * @var int
182
- * @access private
183
- */
184
- var $cfb_init_len = 500;
185
-
186
- /**
187
- * The key length in bits.
188
- *
189
- * @see self::setKeyLength()
190
- * @see self::setKey()
191
- * @var int
192
- * @access private
193
- * @internal Should be in range [1..1024].
194
- * @internal Changing this value after setting the key has no effect.
195
- */
196
- var $default_key_length = 1024;
197
-
198
- /**
199
- * The key length in bits.
200
- *
201
- * @see self::isValidEnine()
202
- * @see self::setKey()
203
- * @var int
204
- * @access private
205
- * @internal Should be in range [1..1024].
206
- */
207
- var $current_key_length;
208
-
209
- /**
210
- * The Key Schedule
211
- *
212
- * @see self::_setupKey()
213
- * @var array
214
- * @access private
215
- */
216
- var $keys;
217
-
218
- /**
219
- * Key expansion randomization table.
220
- * Twice the same 256-value sequence to save a modulus in key expansion.
221
- *
222
- * @see self::setKey()
223
- * @var array
224
- * @access private
225
- */
226
- var $pitable = array(
227
- 0xD9, 0x78, 0xF9, 0xC4, 0x19, 0xDD, 0xB5, 0xED,
228
- 0x28, 0xE9, 0xFD, 0x79, 0x4A, 0xA0, 0xD8, 0x9D,
229
- 0xC6, 0x7E, 0x37, 0x83, 0x2B, 0x76, 0x53, 0x8E,
230
- 0x62, 0x4C, 0x64, 0x88, 0x44, 0x8B, 0xFB, 0xA2,
231
- 0x17, 0x9A, 0x59, 0xF5, 0x87, 0xB3, 0x4F, 0x13,
232
- 0x61, 0x45, 0x6D, 0x8D, 0x09, 0x81, 0x7D, 0x32,
233
- 0xBD, 0x8F, 0x40, 0xEB, 0x86, 0xB7, 0x7B, 0x0B,
234
- 0xF0, 0x95, 0x21, 0x22, 0x5C, 0x6B, 0x4E, 0x82,
235
- 0x54, 0xD6, 0x65, 0x93, 0xCE, 0x60, 0xB2, 0x1C,
236
- 0x73, 0x56, 0xC0, 0x14, 0xA7, 0x8C, 0xF1, 0xDC,
237
- 0x12, 0x75, 0xCA, 0x1F, 0x3B, 0xBE, 0xE4, 0xD1,
238
- 0x42, 0x3D, 0xD4, 0x30, 0xA3, 0x3C, 0xB6, 0x26,
239
- 0x6F, 0xBF, 0x0E, 0xDA, 0x46, 0x69, 0x07, 0x57,
240
- 0x27, 0xF2, 0x1D, 0x9B, 0xBC, 0x94, 0x43, 0x03,
241
- 0xF8, 0x11, 0xC7, 0xF6, 0x90, 0xEF, 0x3E, 0xE7,
242
- 0x06, 0xC3, 0xD5, 0x2F, 0xC8, 0x66, 0x1E, 0xD7,
243
- 0x08, 0xE8, 0xEA, 0xDE, 0x80, 0x52, 0xEE, 0xF7,
244
- 0x84, 0xAA, 0x72, 0xAC, 0x35, 0x4D, 0x6A, 0x2A,
245
- 0x96, 0x1A, 0xD2, 0x71, 0x5A, 0x15, 0x49, 0x74,
246
- 0x4B, 0x9F, 0xD0, 0x5E, 0x04, 0x18, 0xA4, 0xEC,
247
- 0xC2, 0xE0, 0x41, 0x6E, 0x0F, 0x51, 0xCB, 0xCC,
248
- 0x24, 0x91, 0xAF, 0x50, 0xA1, 0xF4, 0x70, 0x39,
249
- 0x99, 0x7C, 0x3A, 0x85, 0x23, 0xB8, 0xB4, 0x7A,
250
- 0xFC, 0x02, 0x36, 0x5B, 0x25, 0x55, 0x97, 0x31,
251
- 0x2D, 0x5D, 0xFA, 0x98, 0xE3, 0x8A, 0x92, 0xAE,
252
- 0x05, 0xDF, 0x29, 0x10, 0x67, 0x6C, 0xBA, 0xC9,
253
- 0xD3, 0x00, 0xE6, 0xCF, 0xE1, 0x9E, 0xA8, 0x2C,
254
- 0x63, 0x16, 0x01, 0x3F, 0x58, 0xE2, 0x89, 0xA9,
255
- 0x0D, 0x38, 0x34, 0x1B, 0xAB, 0x33, 0xFF, 0xB0,
256
- 0xBB, 0x48, 0x0C, 0x5F, 0xB9, 0xB1, 0xCD, 0x2E,
257
- 0xC5, 0xF3, 0xDB, 0x47, 0xE5, 0xA5, 0x9C, 0x77,
258
- 0x0A, 0xA6, 0x20, 0x68, 0xFE, 0x7F, 0xC1, 0xAD,
259
- 0xD9, 0x78, 0xF9, 0xC4, 0x19, 0xDD, 0xB5, 0xED,
260
- 0x28, 0xE9, 0xFD, 0x79, 0x4A, 0xA0, 0xD8, 0x9D,
261
- 0xC6, 0x7E, 0x37, 0x83, 0x2B, 0x76, 0x53, 0x8E,
262
- 0x62, 0x4C, 0x64, 0x88, 0x44, 0x8B, 0xFB, 0xA2,
263
- 0x17, 0x9A, 0x59, 0xF5, 0x87, 0xB3, 0x4F, 0x13,
264
- 0x61, 0x45, 0x6D, 0x8D, 0x09, 0x81, 0x7D, 0x32,
265
- 0xBD, 0x8F, 0x40, 0xEB, 0x86, 0xB7, 0x7B, 0x0B,
266
- 0xF0, 0x95, 0x21, 0x22, 0x5C, 0x6B, 0x4E, 0x82,
267
- 0x54, 0xD6, 0x65, 0x93, 0xCE, 0x60, 0xB2, 0x1C,
268
- 0x73, 0x56, 0xC0, 0x14, 0xA7, 0x8C, 0xF1, 0xDC,
269
- 0x12, 0x75, 0xCA, 0x1F, 0x3B, 0xBE, 0xE4, 0xD1,
270
- 0x42, 0x3D, 0xD4, 0x30, 0xA3, 0x3C, 0xB6, 0x26,
271
- 0x6F, 0xBF, 0x0E, 0xDA, 0x46, 0x69, 0x07, 0x57,
272
- 0x27, 0xF2, 0x1D, 0x9B, 0xBC, 0x94, 0x43, 0x03,
273
- 0xF8, 0x11, 0xC7, 0xF6, 0x90, 0xEF, 0x3E, 0xE7,
274
- 0x06, 0xC3, 0xD5, 0x2F, 0xC8, 0x66, 0x1E, 0xD7,
275
- 0x08, 0xE8, 0xEA, 0xDE, 0x80, 0x52, 0xEE, 0xF7,
276
- 0x84, 0xAA, 0x72, 0xAC, 0x35, 0x4D, 0x6A, 0x2A,
277
- 0x96, 0x1A, 0xD2, 0x71, 0x5A, 0x15, 0x49, 0x74,
278
- 0x4B, 0x9F, 0xD0, 0x5E, 0x04, 0x18, 0xA4, 0xEC,
279
- 0xC2, 0xE0, 0x41, 0x6E, 0x0F, 0x51, 0xCB, 0xCC,
280
- 0x24, 0x91, 0xAF, 0x50, 0xA1, 0xF4, 0x70, 0x39,
281
- 0x99, 0x7C, 0x3A, 0x85, 0x23, 0xB8, 0xB4, 0x7A,
282
- 0xFC, 0x02, 0x36, 0x5B, 0x25, 0x55, 0x97, 0x31,
283
- 0x2D, 0x5D, 0xFA, 0x98, 0xE3, 0x8A, 0x92, 0xAE,
284
- 0x05, 0xDF, 0x29, 0x10, 0x67, 0x6C, 0xBA, 0xC9,
285
- 0xD3, 0x00, 0xE6, 0xCF, 0xE1, 0x9E, 0xA8, 0x2C,
286
- 0x63, 0x16, 0x01, 0x3F, 0x58, 0xE2, 0x89, 0xA9,
287
- 0x0D, 0x38, 0x34, 0x1B, 0xAB, 0x33, 0xFF, 0xB0,
288
- 0xBB, 0x48, 0x0C, 0x5F, 0xB9, 0xB1, 0xCD, 0x2E,
289
- 0xC5, 0xF3, 0xDB, 0x47, 0xE5, 0xA5, 0x9C, 0x77,
290
- 0x0A, 0xA6, 0x20, 0x68, 0xFE, 0x7F, 0xC1, 0xAD
291
- );
292
-
293
- /**
294
- * Inverse key expansion randomization table.
295
- *
296
- * @see self::setKey()
297
- * @var array
298
- * @access private
299
- */
300
- var $invpitable = array(
301
- 0xD1, 0xDA, 0xB9, 0x6F, 0x9C, 0xC8, 0x78, 0x66,
302
- 0x80, 0x2C, 0xF8, 0x37, 0xEA, 0xE0, 0x62, 0xA4,
303
- 0xCB, 0x71, 0x50, 0x27, 0x4B, 0x95, 0xD9, 0x20,
304
- 0x9D, 0x04, 0x91, 0xE3, 0x47, 0x6A, 0x7E, 0x53,
305
- 0xFA, 0x3A, 0x3B, 0xB4, 0xA8, 0xBC, 0x5F, 0x68,
306
- 0x08, 0xCA, 0x8F, 0x14, 0xD7, 0xC0, 0xEF, 0x7B,
307
- 0x5B, 0xBF, 0x2F, 0xE5, 0xE2, 0x8C, 0xBA, 0x12,
308
- 0xE1, 0xAF, 0xB2, 0x54, 0x5D, 0x59, 0x76, 0xDB,
309
- 0x32, 0xA2, 0x58, 0x6E, 0x1C, 0x29, 0x64, 0xF3,
310
- 0xE9, 0x96, 0x0C, 0x98, 0x19, 0x8D, 0x3E, 0x26,
311
- 0xAB, 0xA5, 0x85, 0x16, 0x40, 0xBD, 0x49, 0x67,
312
- 0xDC, 0x22, 0x94, 0xBB, 0x3C, 0xC1, 0x9B, 0xEB,
313
- 0x45, 0x28, 0x18, 0xD8, 0x1A, 0x42, 0x7D, 0xCC,
314
- 0xFB, 0x65, 0x8E, 0x3D, 0xCD, 0x2A, 0xA3, 0x60,
315
- 0xAE, 0x93, 0x8A, 0x48, 0x97, 0x51, 0x15, 0xF7,
316
- 0x01, 0x0B, 0xB7, 0x36, 0xB1, 0x2E, 0x11, 0xFD,
317
- 0x84, 0x2D, 0x3F, 0x13, 0x88, 0xB3, 0x34, 0x24,
318
- 0x1B, 0xDE, 0xC5, 0x1D, 0x4D, 0x2B, 0x17, 0x31,
319
- 0x74, 0xA9, 0xC6, 0x43, 0x6D, 0x39, 0x90, 0xBE,
320
- 0xC3, 0xB0, 0x21, 0x6B, 0xF6, 0x0F, 0xD5, 0x99,
321
- 0x0D, 0xAC, 0x1F, 0x5C, 0x9E, 0xF5, 0xF9, 0x4C,
322
- 0xD6, 0xDF, 0x89, 0xE4, 0x8B, 0xFF, 0xC7, 0xAA,
323
- 0xE7, 0xED, 0x46, 0x25, 0xB6, 0x06, 0x5E, 0x35,
324
- 0xB5, 0xEC, 0xCE, 0xE8, 0x6C, 0x30, 0x55, 0x61,
325
- 0x4A, 0xFE, 0xA0, 0x79, 0x03, 0xF0, 0x10, 0x72,
326
- 0x7C, 0xCF, 0x52, 0xA6, 0xA7, 0xEE, 0x44, 0xD3,
327
- 0x9A, 0x57, 0x92, 0xD0, 0x5A, 0x7A, 0x41, 0x7F,
328
- 0x0E, 0x00, 0x63, 0xF2, 0x4F, 0x05, 0x83, 0xC9,
329
- 0xA1, 0xD4, 0xDD, 0xC4, 0x56, 0xF4, 0xD2, 0x77,
330
- 0x81, 0x09, 0x82, 0x33, 0x9F, 0x07, 0x86, 0x75,
331
- 0x38, 0x4E, 0x69, 0xF1, 0xAD, 0x23, 0x73, 0x87,
332
- 0x70, 0x02, 0xC2, 0x1E, 0xB8, 0x0A, 0xFC, 0xE6
333
- );
334
-
335
- /**
336
- * Test for engine validity
337
- *
338
- * This is mainly just a wrapper to set things up for Crypt_Base::isValidEngine()
339
- *
340
- * @see Crypt_Base::Crypt_Base()
341
- * @param int $engine
342
- * @access public
343
- * @return bool
344
- */
345
- function isValidEngine($engine)
346
- {
347
- switch ($engine) {
348
- case CRYPT_ENGINE_OPENSSL:
349
- if ($this->current_key_length != 128 || strlen($this->orig_key) < 16) {
350
- return false;
351
- }
352
- $this->cipher_name_openssl_ecb = 'rc2-ecb';
353
- $this->cipher_name_openssl = 'rc2-' . $this->_openssl_translate_mode();
354
- }
355
-
356
- return parent::isValidEngine($engine);
357
- }
358
-
359
- /**
360
- * Sets the key length.
361
- *
362
- * Valid key lengths are 8 to 1024.
363
- * Calling this function after setting the key has no effect until the next
364
- * Crypt_RC2::setKey() call.
365
- *
366
- * @access public
367
- * @param int $length in bits
368
- */
369
- function setKeyLength($length)
370
- {
371
- if ($length < 8) {
372
- $this->default_key_length = 8;
373
- } elseif ($length > 1024) {
374
- $this->default_key_length = 128;
375
- } else {
376
- $this->default_key_length = $length;
377
- }
378
- $this->current_key_length = $this->default_key_length;
379
-
380
- parent::setKeyLength($length);
381
- }
382
-
383
- /**
384
- * Returns the current key length
385
- *
386
- * @access public
387
- * @return int
388
- */
389
- function getKeyLength()
390
- {
391
- return $this->current_key_length;
392
- }
393
-
394
- /**
395
- * Sets the key.
396
- *
397
- * Keys can be of any length. RC2, itself, uses 8 to 1024 bit keys (eg.
398
- * strlen($key) <= 128), however, we only use the first 128 bytes if $key
399
- * has more then 128 bytes in it, and set $key to a single null byte if
400
- * it is empty.
401
- *
402
- * If the key is not explicitly set, it'll be assumed to be a single
403
- * null byte.
404
- *
405
- * @see Crypt_Base::setKey()
406
- * @access public
407
- * @param string $key
408
- * @param int $t1 optional Effective key length in bits.
409
- */
410
- function setKey($key, $t1 = 0)
411
- {
412
- $this->orig_key = $key;
413
-
414
- if ($t1 <= 0) {
415
- $t1 = $this->default_key_length;
416
- } elseif ($t1 > 1024) {
417
- $t1 = 1024;
418
- }
419
- $this->current_key_length = $t1;
420
- // Key byte count should be 1..128.
421
- $key = strlen($key) ? substr($key, 0, 128) : "\x00";
422
- $t = strlen($key);
423
-
424
- // The mcrypt RC2 implementation only supports effective key length
425
- // of 1024 bits. It is however possible to handle effective key
426
- // lengths in range 1..1024 by expanding the key and applying
427
- // inverse pitable mapping to the first byte before submitting it
428
- // to mcrypt.
429
-
430
- // Key expansion.
431
- $l = array_values(unpack('C*', $key));
432
- $t8 = ($t1 + 7) >> 3;
433
- $tm = 0xFF >> (8 * $t8 - $t1);
434
-
435
- // Expand key.
436
- $pitable = $this->pitable;
437
- for ($i = $t; $i < 128; $i++) {
438
- $l[$i] = $pitable[$l[$i - 1] + $l[$i - $t]];
439
- }
440
- $i = 128 - $t8;
441
- $l[$i] = $pitable[$l[$i] & $tm];
442
- while ($i--) {
443
- $l[$i] = $pitable[$l[$i + 1] ^ $l[$i + $t8]];
444
- }
445
-
446
- // Prepare the key for mcrypt.
447
- $l[0] = $this->invpitable[$l[0]];
448
- array_unshift($l, 'C*');
449
-
450
- parent::setKey(call_user_func_array('pack', $l));
451
- }
452
-
453
- /**
454
- * Encrypts a message.
455
- *
456
- * Mostly a wrapper for Crypt_Base::encrypt, with some additional OpenSSL handling code
457
- *
458
- * @see self::decrypt()
459
- * @access public
460
- * @param string $plaintext
461
- * @return string $ciphertext
462
- */
463
- function encrypt($plaintext)
464
- {
465
- if ($this->engine == CRYPT_ENGINE_OPENSSL) {
466
- $temp = $this->key;
467
- $this->key = $this->orig_key;
468
- $result = parent::encrypt($plaintext);
469
- $this->key = $temp;
470
- return $result;
471
- }
472
-
473
- return parent::encrypt($plaintext);
474
- }
475
-
476
- /**
477
- * Decrypts a message.
478
- *
479
- * Mostly a wrapper for Crypt_Base::decrypt, with some additional OpenSSL handling code
480
- *
481
- * @see self::encrypt()
482
- * @access public
483
- * @param string $ciphertext
484
- * @return string $plaintext
485
- */
486
- function decrypt($ciphertext)
487
- {
488
- if ($this->engine == CRYPT_ENGINE_OPENSSL) {
489
- $temp = $this->key;
490
- $this->key = $this->orig_key;
491
- $result = parent::decrypt($ciphertext);
492
- $this->key = $temp;
493
- return $result;
494
- }
495
-
496
- return parent::decrypt($ciphertext);
497
- }
498
-
499
- /**
500
- * Encrypts a block
501
- *
502
- * @see Crypt_Base::_encryptBlock()
503
- * @see Crypt_Base::encrypt()
504
- * @access private
505
- * @param string $in
506
- * @return string
507
- */
508
- function _encryptBlock($in)
509
- {
510
- list($r0, $r1, $r2, $r3) = array_values(unpack('v*', $in));
511
- $keys = $this->keys;
512
- $limit = 20;
513
- $actions = array($limit => 44, 44 => 64);
514
- $j = 0;
515
-
516
- for (;;) {
517
- // Mixing round.
518
- $r0 = (($r0 + $keys[$j++] + ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF) << 1;
519
- $r0 |= $r0 >> 16;
520
- $r1 = (($r1 + $keys[$j++] + ((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF) << 2;
521
- $r1 |= $r1 >> 16;
522
- $r2 = (($r2 + $keys[$j++] + ((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF) << 3;
523
- $r2 |= $r2 >> 16;
524
- $r3 = (($r3 + $keys[$j++] + ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF) << 5;
525
- $r3 |= $r3 >> 16;
526
-
527
- if ($j === $limit) {
528
- if ($limit === 64) {
529
- break;
530
- }
531
-
532
- // Mashing round.
533
- $r0 += $keys[$r3 & 0x3F];
534
- $r1 += $keys[$r0 & 0x3F];
535
- $r2 += $keys[$r1 & 0x3F];
536
- $r3 += $keys[$r2 & 0x3F];
537
- $limit = $actions[$limit];
538
- }
539
- }
540
-
541
- return pack('vvvv', $r0, $r1, $r2, $r3);
542
- }
543
-
544
- /**
545
- * Decrypts a block
546
- *
547
- * @see Crypt_Base::_decryptBlock()
548
- * @see Crypt_Base::decrypt()
549
- * @access private
550
- * @param string $in
551
- * @return string
552
- */
553
- function _decryptBlock($in)
554
- {
555
- list($r0, $r1, $r2, $r3) = array_values(unpack('v*', $in));
556
- $keys = $this->keys;
557
- $limit = 44;
558
- $actions = array($limit => 20, 20 => 0);
559
- $j = 64;
560
-
561
- for (;;) {
562
- // R-mixing round.
563
- $r3 = ($r3 | ($r3 << 16)) >> 5;
564
- $r3 = ($r3 - $keys[--$j] - ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF;
565
- $r2 = ($r2 | ($r2 << 16)) >> 3;
566
- $r2 = ($r2 - $keys[--$j] - ((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF;
567
- $r1 = ($r1 | ($r1 << 16)) >> 2;
568
- $r1 = ($r1 - $keys[--$j] - ((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF;
569
- $r0 = ($r0 | ($r0 << 16)) >> 1;
570
- $r0 = ($r0 - $keys[--$j] - ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF;
571
-
572
- if ($j === $limit) {
573
- if ($limit === 0) {
574
- break;
575
- }
576
-
577
- // R-mashing round.
578
- $r3 = ($r3 - $keys[$r2 & 0x3F]) & 0xFFFF;
579
- $r2 = ($r2 - $keys[$r1 & 0x3F]) & 0xFFFF;
580
- $r1 = ($r1 - $keys[$r0 & 0x3F]) & 0xFFFF;
581
- $r0 = ($r0 - $keys[$r3 & 0x3F]) & 0xFFFF;
582
- $limit = $actions[$limit];
583
- }
584
- }
585
-
586
- return pack('vvvv', $r0, $r1, $r2, $r3);
587
- }
588
-
589
- /**
590
- * Setup the CRYPT_ENGINE_MCRYPT $engine
591
- *
592
- * @see Crypt_Base::_setupMcrypt()
593
- * @access private
594
- */
595
- function _setupMcrypt()
596
- {
597
- if (!isset($this->key)) {
598
- $this->setKey('');
599
- }
600
-
601
- parent::_setupMcrypt();
602
- }
603
-
604
- /**
605
- * Creates the key schedule
606
- *
607
- * @see Crypt_Base::_setupKey()
608
- * @access private
609
- */
610
- function _setupKey()
611
- {
612
- if (!isset($this->key)) {
613
- $this->setKey('');
614
- }
615
-
616
- // Key has already been expanded in Crypt_RC2::setKey():
617
- // Only the first value must be altered.
618
- $l = unpack('Ca/Cb/v*', $this->key);
619
- array_unshift($l, $this->pitable[$l['a']] | ($l['b'] << 8));
620
- unset($l['a']);
621
- unset($l['b']);
622
- $this->keys = $l;
623
- }
624
-
625
- /**
626
- * Setup the performance-optimized function for de/encrypt()
627
- *
628
- * @see Crypt_Base::_setupInlineCrypt()
629
- * @access private
630
- */
631
- function _setupInlineCrypt()
632
- {
633
- $lambda_functions = &Crypt_RC2::_getLambdaFunctions();
634
-
635
- // The first 10 generated $lambda_functions will use the $keys hardcoded as integers
636
- // for the mixing rounds, for better inline crypt performance [~20% faster].
637
- // But for memory reason we have to limit those ultra-optimized $lambda_functions to an amount of 10.
638
- // (Currently, for Crypt_RC2, one generated $lambda_function cost on php5.5@32bit ~60kb unfreeable mem and ~100kb on php5.5@64bit)
639
- $gen_hi_opt_code = (bool)(count($lambda_functions) < 10);
640
-
641
- // Generation of a unique hash for our generated code
642
- $code_hash = "Crypt_RC2, {$this->mode}";
643
- if ($gen_hi_opt_code) {
644
- $code_hash = str_pad($code_hash, 32) . $this->_hashInlineCryptFunction($this->key);
645
- }
646
-
647
- // Is there a re-usable $lambda_functions in there?
648
- // If not, we have to create it.
649
- if (!isset($lambda_functions[$code_hash])) {
650
- // Init code for both, encrypt and decrypt.
651
- $init_crypt = '$keys = $self->keys;';
652
-
653
- switch (true) {
654
- case $gen_hi_opt_code:
655
- $keys = $this->keys;
656
- default:
657
- $keys = array();
658
- foreach ($this->keys as $k => $v) {
659
- $keys[$k] = '$keys[' . $k . ']';
660
- }
661
- }
662
-
663
- // $in is the current 8 bytes block which has to be en/decrypt
664
- $encrypt_block = $decrypt_block = '
665
- $in = unpack("v4", $in);
666
- $r0 = $in[1];
667
- $r1 = $in[2];
668
- $r2 = $in[3];
669
- $r3 = $in[4];
670
- ';
671
-
672
- // Create code for encryption.
673
- $limit = 20;
674
- $actions = array($limit => 44, 44 => 64);
675
- $j = 0;
676
-
677
- for (;;) {
678
- // Mixing round.
679
- $encrypt_block .= '
680
- $r0 = (($r0 + ' . $keys[$j++] . ' +
681
- ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF) << 1;
682
- $r0 |= $r0 >> 16;
683
- $r1 = (($r1 + ' . $keys[$j++] . ' +
684
- ((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF) << 2;
685
- $r1 |= $r1 >> 16;
686
- $r2 = (($r2 + ' . $keys[$j++] . ' +
687
- ((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF) << 3;
688
- $r2 |= $r2 >> 16;
689
- $r3 = (($r3 + ' . $keys[$j++] . ' +
690
- ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF) << 5;
691
- $r3 |= $r3 >> 16;';
692
-
693
- if ($j === $limit) {
694
- if ($limit === 64) {
695
- break;
696
- }
697
-
698
- // Mashing round.
699
- $encrypt_block .= '
700
- $r0 += $keys[$r3 & 0x3F];
701
- $r1 += $keys[$r0 & 0x3F];
702
- $r2 += $keys[$r1 & 0x3F];
703
- $r3 += $keys[$r2 & 0x3F];';
704
- $limit = $actions[$limit];
705
- }
706
- }
707
-
708
- $encrypt_block .= '$in = pack("v4", $r0, $r1, $r2, $r3);';
709
-
710
- // Create code for decryption.
711
- $limit = 44;
712
- $actions = array($limit => 20, 20 => 0);
713
- $j = 64;
714
-
715
- for (;;) {
716
- // R-mixing round.
717
- $decrypt_block .= '
718
- $r3 = ($r3 | ($r3 << 16)) >> 5;
719
- $r3 = ($r3 - ' . $keys[--$j] . ' -
720
- ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF;
721
- $r2 = ($r2 | ($r2 << 16)) >> 3;
722
- $r2 = ($r2 - ' . $keys[--$j] . ' -
723
- ((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF;
724
- $r1 = ($r1 | ($r1 << 16)) >> 2;
725
- $r1 = ($r1 - ' . $keys[--$j] . ' -
726
- ((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF;
727
- $r0 = ($r0 | ($r0 << 16)) >> 1;
728
- $r0 = ($r0 - ' . $keys[--$j] . ' -
729
- ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF;';
730
-
731
- if ($j === $limit) {
732
- if ($limit === 0) {
733
- break;
734
- }
735
-
736
- // R-mashing round.
737
- $decrypt_block .= '
738
- $r3 = ($r3 - $keys[$r2 & 0x3F]) & 0xFFFF;
739
- $r2 = ($r2 - $keys[$r1 & 0x3F]) & 0xFFFF;
740
- $r1 = ($r1 - $keys[$r0 & 0x3F]) & 0xFFFF;
741
- $r0 = ($r0 - $keys[$r3 & 0x3F]) & 0xFFFF;';
742
- $limit = $actions[$limit];
743
- }
744
- }
745
-
746
- $decrypt_block .= '$in = pack("v4", $r0, $r1, $r2, $r3);';
747
-
748
- // Creates the inline-crypt function
749
- $lambda_functions[$code_hash] = $this->_createInlineCryptFunction(
750
- array(
751
- 'init_crypt' => $init_crypt,
752
- 'encrypt_block' => $encrypt_block,
753
- 'decrypt_block' => $decrypt_block
754
- )
755
- );
756
- }
757
-
758
- // Set the inline-crypt function as callback in: $this->inline_crypt
759
- $this->inline_crypt = $lambda_functions[$code_hash];
760
- }
761
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/phpseclib/Crypt/RC4.php DELETED
@@ -1,363 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Pure-PHP implementation of RC4.
5
- *
6
- * Uses mcrypt, if available, and an internal implementation, otherwise.
7
- *
8
- * PHP versions 4 and 5
9
- *
10
- * Useful resources are as follows:
11
- *
12
- * - {@link http://www.mozilla.org/projects/security/pki/nss/draft-kaukonen-cipher-arcfour-03.txt ARCFOUR Algorithm}
13
- * - {@link http://en.wikipedia.org/wiki/RC4 - Wikipedia: RC4}
14
- *
15
- * RC4 is also known as ARCFOUR or ARC4. The reason is elaborated upon at Wikipedia. This class is named RC4 and not
16
- * ARCFOUR or ARC4 because RC4 is how it is referred to in the SSH1 specification.
17
- *
18
- * Here's a short example of how to use this library:
19
- * <code>
20
- * <?php
21
- * include 'Crypt/RC4.php';
22
- *
23
- * $rc4 = new Crypt_RC4();
24
- *
25
- * $rc4->setKey('abcdefgh');
26
- *
27
- * $size = 10 * 1024;
28
- * $plaintext = '';
29
- * for ($i = 0; $i < $size; $i++) {
30
- * $plaintext.= 'a';
31
- * }
32
- *
33
- * echo $rc4->decrypt($rc4->encrypt($plaintext));
34
- * ?>
35
- * </code>
36
- *
37
- * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
38
- * of this software and associated documentation files (the "Software"), to deal
39
- * in the Software without restriction, including without limitation the rights
40
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
41
- * copies of the Software, and to permit persons to whom the Software is
42
- * furnished to do so, subject to the following conditions:
43
- *
44
- * The above copyright notice and this permission notice shall be included in
45
- * all copies or substantial portions of the Software.
46
- *
47
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
48
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
49
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
50
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
51
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
52
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
53
- * THE SOFTWARE.
54
- *
55
- * @category Crypt
56
- * @package Crypt_RC4
57
- * @author Jim Wigginton <terrafrost@php.net>
58
- * @copyright 2007 Jim Wigginton
59
- * @license http://www.opensource.org/licenses/mit-license.html MIT License
60
- * @link http://phpseclib.sourceforge.net
61
- */
62
-
63
- /**
64
- * Include Crypt_Base
65
- *
66
- * Base cipher class
67
- */
68
- if (!class_exists('Crypt_Base')) {
69
- include_once 'Base.php';
70
- }
71
-
72
- /**#@+
73
- * @access private
74
- * @see self::_crypt()
75
- */
76
- define('CRYPT_RC4_ENCRYPT', 0);
77
- define('CRYPT_RC4_DECRYPT', 1);
78
- /**#@-*/
79
-
80
- /**
81
- * Pure-PHP implementation of RC4.
82
- *
83
- * @package Crypt_RC4
84
- * @author Jim Wigginton <terrafrost@php.net>
85
- * @access public
86
- */
87
- class Crypt_RC4 extends Crypt_Base
88
- {
89
- /**
90
- * Block Length of the cipher
91
- *
92
- * RC4 is a stream cipher
93
- * so we the block_size to 0
94
- *
95
- * @see Crypt_Base::block_size
96
- * @var int
97
- * @access private
98
- */
99
- var $block_size = 0;
100
-
101
- /**
102
- * Key Length (in bytes)
103
- *
104
- * @see Crypt_RC4::setKeyLength()
105
- * @var int
106
- * @access private
107
- */
108
- var $key_length = 128; // = 1024 bits
109
-
110
- /**
111
- * The namespace used by the cipher for its constants.
112
- *
113
- * @see Crypt_Base::const_namespace
114
- * @var string
115
- * @access private
116
- */
117
- var $const_namespace = 'RC4';
118
-
119
- /**
120
- * The mcrypt specific name of the cipher
121
- *
122
- * @see Crypt_Base::cipher_name_mcrypt
123
- * @var string
124
- * @access private
125
- */
126
- var $cipher_name_mcrypt = 'arcfour';
127
-
128
- /**
129
- * Holds whether performance-optimized $inline_crypt() can/should be used.
130
- *
131
- * @see Crypt_Base::inline_crypt
132
- * @var mixed
133
- * @access private
134
- */
135
- var $use_inline_crypt = false; // currently not available
136
-
137
- /**
138
- * The Key
139
- *
140
- * @see self::setKey()
141
- * @var string
142
- * @access private
143
- */
144
- var $key = "\0";
145
-
146
- /**
147
- * The Key Stream for decryption and encryption
148
- *
149
- * @see self::setKey()
150
- * @var array
151
- * @access private
152
- */
153
- var $stream;
154
-
155
- /**
156
- * Default Constructor.
157
- *
158
- * Determines whether or not the mcrypt extension should be used.
159
- *
160
- * @see Crypt_Base::Crypt_Base()
161
- * @return Crypt_RC4
162
- * @access public
163
- */
164
- function __construct()
165
- {
166
- parent::__construct(CRYPT_MODE_STREAM);
167
- }
168
-
169
- /**
170
- * PHP4 compatible Default Constructor.
171
- *
172
- * @see self::__construct()
173
- * @access public
174
- */
175
- function Crypt_RC4()
176
- {
177
- $this->__construct();
178
- }
179
-
180
- /**
181
- * Test for engine validity
182
- *
183
- * This is mainly just a wrapper to set things up for Crypt_Base::isValidEngine()
184
- *
185
- * @see Crypt_Base::Crypt_Base()
186
- * @param int $engine
187
- * @access public
188
- * @return bool
189
- */
190
- function isValidEngine($engine)
191
- {
192
- switch ($engine) {
193
- case CRYPT_ENGINE_OPENSSL:
194
- switch (strlen($this->key)) {
195
- case 5:
196
- $this->cipher_name_openssl = 'rc4-40';
197
- break;
198
- case 8:
199
- $this->cipher_name_openssl = 'rc4-64';
200
- break;
201
- case 16:
202
- $this->cipher_name_openssl = 'rc4';
203
- break;
204
- default:
205
- return false;
206
- }
207
- }
208
-
209
- return parent::isValidEngine($engine);
210
- }
211
-
212
- /**
213
- * Dummy function.
214
- *
215
- * Some protocols, such as WEP, prepend an "initialization vector" to the key, effectively creating a new key [1].
216
- * If you need to use an initialization vector in this manner, feel free to prepend it to the key, yourself, before
217
- * calling setKey().
218
- *
219
- * [1] WEP's initialization vectors (IV's) are used in a somewhat insecure way. Since, in that protocol,
220
- * the IV's are relatively easy to predict, an attack described by
221
- * {@link http://www.drizzle.com/~aboba/IEEE/rc4_ksaproc.pdf Scott Fluhrer, Itsik Mantin, and Adi Shamir}
222
- * can be used to quickly guess at the rest of the key. The following links elaborate:
223
- *
224
- * {@link http://www.rsa.com/rsalabs/node.asp?id=2009 http://www.rsa.com/rsalabs/node.asp?id=2009}
225
- * {@link http://en.wikipedia.org/wiki/Related_key_attack http://en.wikipedia.org/wiki/Related_key_attack}
226
- *
227
- * @param string $iv
228
- * @see self::setKey()
229
- * @access public
230
- */
231
- function setIV($iv)
232
- {
233
- }
234
-
235
- /**
236
- * Sets the key length
237
- *
238
- * Keys can be between 1 and 256 bytes long.
239
- *
240
- * @access public
241
- * @param int $length
242
- */
243
- function setKeyLength($length)
244
- {
245
- if ($length < 8) {
246
- $this->key_length = 1;
247
- } elseif ($length > 2048) {
248
- $this->key_length = 256;
249
- } else {
250
- $this->key_length = $length >> 3;
251
- }
252
-
253
- parent::setKeyLength($length);
254
- }
255
-
256
- /**
257
- * Encrypts a message.
258
- *
259
- * @see Crypt_Base::decrypt()
260
- * @see self::_crypt()
261
- * @access public
262
- * @param string $plaintext
263
- * @return string $ciphertext
264
- */
265
- function encrypt($plaintext)
266
- {
267
- if ($this->engine != CRYPT_ENGINE_INTERNAL) {
268
- return parent::encrypt($plaintext);
269
- }
270
- return $this->_crypt($plaintext, CRYPT_RC4_ENCRYPT);
271
- }
272
-
273
- /**
274
- * Decrypts a message.
275
- *
276
- * $this->decrypt($this->encrypt($plaintext)) == $this->encrypt($this->encrypt($plaintext)).
277
- * At least if the continuous buffer is disabled.
278
- *
279
- * @see Crypt_Base::encrypt()
280
- * @see self::_crypt()
281
- * @access public
282
- * @param string $ciphertext
283
- * @return string $plaintext
284
- */
285
- function decrypt($ciphertext)
286
- {
287
- if ($this->engine != CRYPT_ENGINE_INTERNAL) {
288
- return parent::decrypt($ciphertext);
289
- }
290
- return $this->_crypt($ciphertext, CRYPT_RC4_DECRYPT);
291
- }
292
-
293
-
294
- /**
295
- * Setup the key (expansion)
296
- *
297
- * @see Crypt_Base::_setupKey()
298
- * @access private
299
- */
300
- function _setupKey()
301
- {
302
- $key = $this->key;
303
- $keyLength = strlen($key);
304
- $keyStream = range(0, 255);
305
- $j = 0;
306
- for ($i = 0; $i < 256; $i++) {
307
- $j = ($j + $keyStream[$i] + ord($key[$i % $keyLength])) & 255;
308
- $temp = $keyStream[$i];
309
- $keyStream[$i] = $keyStream[$j];
310
- $keyStream[$j] = $temp;
311
- }
312
-
313
- $this->stream = array();
314
- $this->stream[CRYPT_RC4_DECRYPT] = $this->stream[CRYPT_RC4_ENCRYPT] = array(
315
- 0, // index $i
316
- 0, // index $j
317
- $keyStream
318
- );
319
- }
320
-
321
- /**
322
- * Encrypts or decrypts a message.
323
- *
324
- * @see self::encrypt()
325
- * @see self::decrypt()
326
- * @access private
327
- * @param string $text
328
- * @param int $mode
329
- * @return string $text
330
- */
331
- function _crypt($text, $mode)
332
- {
333
- if ($this->changed) {
334
- $this->_setup();
335
- $this->changed = false;
336
- }
337
-
338
- $stream = &$this->stream[$mode];
339
- if ($this->continuousBuffer) {
340
- $i = &$stream[0];
341
- $j = &$stream[1];
342
- $keyStream = &$stream[2];
343
- } else {
344
- $i = $stream[0];
345
- $j = $stream[1];
346
- $keyStream = $stream[2];
347
- }
348
-
349
- $len = strlen($text);
350
- for ($k = 0; $k < $len; ++$k) {
351
- $i = ($i + 1) & 255;
352
- $ksi = $keyStream[$i];
353
- $j = ($j + $ksi) & 255;
354
- $ksj = $keyStream[$j];
355
-
356
- $keyStream[$i] = $ksj;
357
- $keyStream[$j] = $ksi;
358
- $text[$k] = $text[$k] ^ chr($keyStream[($ksj + $ksi) & 255]);
359
- }
360
-
361
- return $text;
362
- }
363
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/phpseclib/Crypt/RSA.php DELETED
@@ -1,3133 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Pure-PHP PKCS#1 (v2.1) compliant implementation of RSA.
5
- *
6
- * PHP versions 4 and 5
7
- *
8
- * Here's an example of how to encrypt and decrypt text with this library:
9
- * <code>
10
- * <?php
11
- * include 'Crypt/RSA.php';
12
- *
13
- * $rsa = new Crypt_RSA();
14
- * extract($rsa->createKey());
15
- *
16
- * $plaintext = 'terrafrost';
17
- *
18
- * $rsa->loadKey($privatekey);
19
- * $ciphertext = $rsa->encrypt($plaintext);
20
- *
21
- * $rsa->loadKey($publickey);
22
- * echo $rsa->decrypt($ciphertext);
23
- * ?>
24
- * </code>
25
- *
26
- * Here's an example of how to create signatures and verify signatures with this library:
27
- * <code>
28
- * <?php
29
- * include 'Crypt/RSA.php';
30
- *
31
- * $rsa = new Crypt_RSA();
32
- * extract($rsa->createKey());
33
- *
34
- * $plaintext = 'terrafrost';
35
- *
36
- * $rsa->loadKey($privatekey);
37
- * $signature = $rsa->sign($plaintext);
38
- *
39
- * $rsa->loadKey($publickey);
40
- * echo $rsa->verify($plaintext, $signature) ? 'verified' : 'unverified';
41
- * ?>
42
- * </code>
43
- *
44
- * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
45
- * of this software and associated documentation files (the "Software"), to deal
46
- * in the Software without restriction, including without limitation the rights
47
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
48
- * copies of the Software, and to permit persons to whom the Software is
49
- * furnished to do so, subject to the following conditions:
50
- *
51
- * The above copyright notice and this permission notice shall be included in
52
- * all copies or substantial portions of the Software.
53
- *
54
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
55
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
56
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
57
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
58
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
59
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
60
- * THE SOFTWARE.
61
- *
62
- * @category Crypt
63
- * @package Crypt_RSA
64
- * @author Jim Wigginton <terrafrost@php.net>
65
- * @copyright 2009 Jim Wigginton
66
- * @license http://www.opensource.org/licenses/mit-license.html MIT License
67
- * @link http://phpseclib.sourceforge.net
68
- */
69
-
70
- /**
71
- * Include Crypt_Random
72
- */
73
- // the class_exists() will only be called if the crypt_random_string function hasn't been defined and
74
- // will trigger a call to __autoload() if you're wanting to auto-load classes
75
- // call function_exists() a second time to stop the include_once from being called outside
76
- // of the auto loader
77
- if (!function_exists('crypt_random_string')) {
78
- include_once 'Random.php';
79
- }
80
-
81
- /**
82
- * Include Crypt_Hash
83
- */
84
- if (!class_exists('Crypt_Hash')) {
85
- include_once 'Hash.php';
86
- }
87
-
88
- /**#@+
89
- * @access public
90
- * @see self::encrypt()
91
- * @see self::decrypt()
92
- */
93
- /**
94
- * Use {@link http://en.wikipedia.org/wiki/Optimal_Asymmetric_Encryption_Padding Optimal Asymmetric Encryption Padding}
95
- * (OAEP) for encryption / decryption.
96
- *
97
- * Uses sha1 by default.
98
- *
99
- * @see self::setHash()
100
- * @see self::setMGFHash()
101
- */
102
- define('CRYPT_RSA_ENCRYPTION_OAEP', 1);
103
- /**
104
- * Use PKCS#1 padding.
105
- *
106
- * Although CRYPT_RSA_ENCRYPTION_OAEP offers more security, including PKCS#1 padding is necessary for purposes of backwards
107
- * compatibility with protocols (like SSH-1) written before OAEP's introduction.
108
- */
109
- define('CRYPT_RSA_ENCRYPTION_PKCS1', 2);
110
- /**
111
- * Do not use any padding
112
- *
113
- * Although this method is not recommended it can none-the-less sometimes be useful if you're trying to decrypt some legacy
114
- * stuff, if you're trying to diagnose why an encrypted message isn't decrypting, etc.
115
- */
116
- define('CRYPT_RSA_ENCRYPTION_NONE', 3);
117
- /**#@-*/
118
-
119
- /**#@+
120
- * @access public
121
- * @see self::sign()
122
- * @see self::verify()
123
- * @see self::setHash()
124
- */
125
- /**
126
- * Use the Probabilistic Signature Scheme for signing
127
- *
128
- * Uses sha1 by default.
129
- *
130
- * @see self::setSaltLength()
131
- * @see self::setMGFHash()
132
- */
133
- define('CRYPT_RSA_SIGNATURE_PSS', 1);
134
- /**
135
- * Use the PKCS#1 scheme by default.
136
- *
137
- * Although CRYPT_RSA_SIGNATURE_PSS offers more security, including PKCS#1 signing is necessary for purposes of backwards
138
- * compatibility with protocols (like SSH-2) written before PSS's introduction.
139
- */
140
- define('CRYPT_RSA_SIGNATURE_PKCS1', 2);
141
- /**#@-*/
142
-
143
- /**#@+
144
- * @access private
145
- * @see self::createKey()
146
- */
147
- /**
148
- * ASN1 Integer
149
- */
150
- define('CRYPT_RSA_ASN1_INTEGER', 2);
151
- /**
152
- * ASN1 Bit String
153
- */
154
- define('CRYPT_RSA_ASN1_BITSTRING', 3);
155
- /**
156
- * ASN1 Octet String
157
- */
158
- define('CRYPT_RSA_ASN1_OCTETSTRING', 4);
159
- /**
160
- * ASN1 Object Identifier
161
- */
162
- define('CRYPT_RSA_ASN1_OBJECT', 6);
163
- /**
164
- * ASN1 Sequence (with the constucted bit set)
165
- */
166
- define('CRYPT_RSA_ASN1_SEQUENCE', 48);
167
- /**#@-*/
168
-
169
- /**#@+
170
- * @access private
171
- * @see self::Crypt_RSA()
172
- */
173
- /**
174
- * To use the pure-PHP implementation
175
- */
176
- define('CRYPT_RSA_MODE_INTERNAL', 1);
177
- /**
178
- * To use the OpenSSL library
179
- *
180
- * (if enabled; otherwise, the internal implementation will be used)
181
- */
182
- define('CRYPT_RSA_MODE_OPENSSL', 2);
183
- /**#@-*/
184
-
185
- /**
186
- * Default openSSL configuration file.
187
- */
188
- define('CRYPT_RSA_OPENSSL_CONFIG', dirname(__FILE__) . '/../openssl.cnf');
189
-
190
- /**#@+
191
- * @access public
192
- * @see self::createKey()
193
- * @see self::setPrivateKeyFormat()
194
- */
195
- /**
196
- * PKCS#1 formatted private key
197
- *
198
- * Used by OpenSSH
199
- */
200
- define('CRYPT_RSA_PRIVATE_FORMAT_PKCS1', 0);
201
- /**
202
- * PuTTY formatted private key
203
- */
204
- define('CRYPT_RSA_PRIVATE_FORMAT_PUTTY', 1);
205
- /**
206
- * XML formatted private key
207
- */
208
- define('CRYPT_RSA_PRIVATE_FORMAT_XML', 2);
209
- /**
210
- * PKCS#8 formatted private key
211
- */
212
- define('CRYPT_RSA_PRIVATE_FORMAT_PKCS8', 8);
213
- /**#@-*/
214
-
215
- /**#@+
216
- * @access public
217
- * @see self::createKey()
218
- * @see self::setPublicKeyFormat()
219
- */
220
- /**
221
- * Raw public key
222
- *
223
- * An array containing two Math_BigInteger objects.
224
- *
225
- * The exponent can be indexed with any of the following:
226
- *
227
- * 0, e, exponent, publicExponent
228
- *
229
- * The modulus can be indexed with any of the following:
230
- *
231
- * 1, n, modulo, modulus
232
- */
233
- define('CRYPT_RSA_PUBLIC_FORMAT_RAW', 3);
234
- /**
235
- * PKCS#1 formatted public key (raw)
236
- *
237
- * Used by File/X509.php
238
- *
239
- * Has the following header:
240
- *
241
- * -----BEGIN RSA PUBLIC KEY-----
242
- *
243
- * Analogous to ssh-keygen's pem format (as specified by -m)
244
- */
245
- define('CRYPT_RSA_PUBLIC_FORMAT_PKCS1', 4);
246
- define('CRYPT_RSA_PUBLIC_FORMAT_PKCS1_RAW', 4);
247
- /**
248
- * XML formatted public key
249
- */
250
- define('CRYPT_RSA_PUBLIC_FORMAT_XML', 5);
251
- /**
252
- * OpenSSH formatted public key
253
- *
254
- * Place in $HOME/.ssh/authorized_keys
255
- */
256
- define('CRYPT_RSA_PUBLIC_FORMAT_OPENSSH', 6);
257
- /**
258
- * PKCS#1 formatted public key (encapsulated)
259
- *
260
- * Used by PHP's openssl_public_encrypt() and openssl's rsautl (when -pubin is set)
261
- *
262
- * Has the following header:
263
- *
264
- * -----BEGIN PUBLIC KEY-----
265
- *
266
- * Analogous to ssh-keygen's pkcs8 format (as specified by -m). Although PKCS8
267
- * is specific to private keys it's basically creating a DER-encoded wrapper
268
- * for keys. This just extends that same concept to public keys (much like ssh-keygen)
269
- */
270
- define('CRYPT_RSA_PUBLIC_FORMAT_PKCS8', 7);
271
- /**#@-*/
272
-
273
- /**
274
- * Pure-PHP PKCS#1 compliant implementation of RSA.
275
- *
276
- * @package Crypt_RSA
277
- * @author Jim Wigginton <terrafrost@php.net>
278
- * @access public
279
- */
280
- class Crypt_RSA
281
- {
282
- /**
283
- * Precomputed Zero
284
- *
285
- * @var Math_BigInteger
286
- * @access private
287
- */
288
- var $zero;
289
-
290
- /**
291
- * Precomputed One
292
- *
293
- * @var Math_BigInteger
294
- * @access private
295
- */
296
- var $one;
297
-
298
- /**
299
- * Private Key Format
300
- *
301
- * @var int
302
- * @access private
303
- */
304
- var $privateKeyFormat = CRYPT_RSA_PRIVATE_FORMAT_PKCS1;
305
-
306
- /**
307
- * Public Key Format
308
- *
309
- * @var int
310
- * @access public
311
- */
312
- var $publicKeyFormat = CRYPT_RSA_PUBLIC_FORMAT_PKCS8;
313
-
314
- /**
315
- * Modulus (ie. n)
316
- *
317
- * @var Math_BigInteger
318
- * @access private
319
- */
320
- var $modulus;
321
-
322
- /**
323
- * Modulus length
324
- *
325
- * @var Math_BigInteger
326
- * @access private
327
- */
328
- var $k;
329
-
330
- /**
331
- * Exponent (ie. e or d)
332
- *
333
- * @var Math_BigInteger
334
- * @access private
335
- */
336
- var $exponent;
337
-
338
- /**
339
- * Primes for Chinese Remainder Theorem (ie. p and q)
340
- *
341
- * @var array
342
- * @access private
343
- */
344
- var $primes;
345
-
346
- /**
347
- * Exponents for Chinese Remainder Theorem (ie. dP and dQ)
348
- *
349
- * @var array
350
- * @access private
351
- */
352
- var $exponents;
353
-
354
- /**
355
- * Coefficients for Chinese Remainder Theorem (ie. qInv)
356
- *
357
- * @var array
358
- * @access private
359
- */
360
- var $coefficients;
361
-
362
- /**
363
- * Hash name
364
- *
365
- * @var string
366
- * @access private
367
- */
368
- var $hashName;
369
-
370
- /**
371
- * Hash function
372
- *
373
- * @var Crypt_Hash
374
- * @access private
375
- */
376
- var $hash;
377
-
378
- /**
379
- * Length of hash function output
380
- *
381
- * @var int
382
- * @access private
383
- */
384
- var $hLen;
385
-
386
- /**
387
- * Length of salt
388
- *
389
- * @var int
390
- * @access private
391
- */
392
- var $sLen;
393
-
394
- /**
395
- * Hash function for the Mask Generation Function
396
- *
397
- * @var Crypt_Hash
398
- * @access private
399
- */
400
- var $mgfHash;
401
-
402
- /**
403
- * Length of MGF hash function output
404
- *
405
- * @var int
406
- * @access private
407
- */
408
- var $mgfHLen;
409
-
410
- /**
411
- * Encryption mode
412
- *
413
- * @var int
414
- * @access private
415
- */
416
- var $encryptionMode = CRYPT_RSA_ENCRYPTION_OAEP;
417
-
418
- /**
419
- * Signature mode
420
- *
421
- * @var int
422
- * @access private
423
- */
424
- var $signatureMode = CRYPT_RSA_SIGNATURE_PSS;
425
-
426
- /**
427
- * Public Exponent
428
- *
429
- * @var mixed
430
- * @access private
431
- */
432
- var $publicExponent = false;
433
-
434
- /**
435
- * Password
436
- *
437
- * @var string
438
- * @access private
439
- */
440
- var $password = false;
441
-
442
- /**
443
- * Components
444
- *
445
- * For use with parsing XML formatted keys. PHP's XML Parser functions use utilized - instead of PHP's DOM functions -
446
- * because PHP's XML Parser functions work on PHP4 whereas PHP's DOM functions - although surperior - don't.
447
- *
448
- * @see self::_start_element_handler()
449
- * @var array
450
- * @access private
451
- */
452
- var $components = array();
453
-
454
- /**
455
- * Current String
456
- *
457
- * For use with parsing XML formatted keys.
458
- *
459
- * @see self::_character_handler()
460
- * @see self::_stop_element_handler()
461
- * @var mixed
462
- * @access private
463
- */
464
- var $current;
465
-
466
- /**
467
- * OpenSSL configuration file name.
468
- *
469
- * Set to null to use system configuration file.
470
- * @see self::createKey()
471
- * @var mixed
472
- * @Access public
473
- */
474
- var $configFile;
475
-
476
- /**
477
- * Public key comment field.
478
- *
479
- * @var string
480
- * @access private
481
- */
482
- var $comment = 'phpseclib-generated-key';
483
-
484
- /**
485
- * The constructor
486
- *
487
- * If you want to make use of the openssl extension, you'll need to set the mode manually, yourself. The reason
488
- * Crypt_RSA doesn't do it is because OpenSSL doesn't fail gracefully. openssl_pkey_new(), in particular, requires
489
- * openssl.cnf be present somewhere and, unfortunately, the only real way to find out is too late.
490
- *
491
- * @return Crypt_RSA
492
- * @access public
493
- */
494
- function __construct()
495
- {
496
- if (!class_exists('Math_BigInteger')) {
497
- include_once 'Math/BigInteger.php';
498
- }
499
-
500
- $this->configFile = CRYPT_RSA_OPENSSL_CONFIG;
501
-
502
- if (!defined('CRYPT_RSA_MODE')) {
503
- switch (true) {
504
- // Math/BigInteger's openssl requirements are a little less stringent than Crypt/RSA's. in particular,
505
- // Math/BigInteger doesn't require an openssl.cfg file whereas Crypt/RSA does. so if Math/BigInteger
506
- // can't use OpenSSL it can be pretty trivially assumed, then, that Crypt/RSA can't either.
507
- case defined('MATH_BIGINTEGER_OPENSSL_DISABLE'):
508
- define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL);
509
- break;
510
- // openssl_pkey_get_details - which is used in the only place Crypt/RSA.php uses OpenSSL - was introduced in PHP 5.2.0
511
- case !function_exists('openssl_pkey_get_details'):
512
- define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL);
513
- break;
514
- case extension_loaded('openssl') && version_compare(PHP_VERSION, '4.2.0', '>=') && file_exists($this->configFile):
515
- // some versions of XAMPP have mismatched versions of OpenSSL which causes it not to work
516
- ob_start();
517
- @phpinfo();
518
- $content = ob_get_contents();
519
- ob_end_clean();
520
-
521
- preg_match_all('#OpenSSL (Header|Library) Version(.*)#im', $content, $matches);
522
-
523
- $versions = array();
524
- if (!empty($matches[1])) {
525
- for ($i = 0; $i < count($matches[1]); $i++) {
526
- $fullVersion = trim(str_replace('=>', '', strip_tags($matches[2][$i])));
527
-
528
- // Remove letter part in OpenSSL version
529
- if (!preg_match('/(\d+\.\d+\.\d+)/i', $fullVersion, $m)) {
530
- $versions[$matches[1][$i]] = $fullVersion;
531
- } else {
532
- $versions[$matches[1][$i]] = $m[0];
533
- }
534
- }
535
- }
536
-
537
- // it doesn't appear that OpenSSL versions were reported upon until PHP 5.3+
538
- switch (true) {
539
- case !isset($versions['Header']):
540
- case !isset($versions['Library']):
541
- case $versions['Header'] == $versions['Library']:
542
- case version_compare($versions['Header'], '1.0.0') >= 0 && version_compare($versions['Library'], '1.0.0') >= 0:
543
- define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_OPENSSL);
544
- break;
545
- default:
546
- define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL);
547
- define('MATH_BIGINTEGER_OPENSSL_DISABLE', true);
548
- }
549
- break;
550
- default:
551
- define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL);
552
- }
553
- }
554
-
555
- $this->zero = new Math_BigInteger();
556
- $this->one = new Math_BigInteger(1);
557
-
558
- $this->hash = new Crypt_Hash('sha1');
559
- $this->hLen = $this->hash->getLength();
560
- $this->hashName = 'sha1';
561
- $this->mgfHash = new Crypt_Hash('sha1');
562
- $this->mgfHLen = $this->mgfHash->getLength();
563
- }
564
-
565
- /**
566
- * PHP4 compatible Default Constructor.
567
- *
568
- * @see self::__construct()
569
- * @access public
570
- */
571
- function Crypt_RSA()
572
- {
573
- $this->__construct();
574
- }
575
-
576
- /**
577
- * Create public / private key pair
578
- *
579
- * Returns an array with the following three elements:
580
- * - 'privatekey': The private key.
581
- * - 'publickey': The public key.
582
- * - 'partialkey': A partially computed key (if the execution time exceeded $timeout).
583
- * Will need to be passed back to Crypt_RSA::createKey() as the third parameter for further processing.
584
- *
585
- * @access public
586
- * @param int $bits
587
- * @param int $timeout
588
- * @param Math_BigInteger $p
589
- */
590
- function createKey($bits = 1024, $timeout = false, $partial = array())
591
- {
592
- if (!defined('CRYPT_RSA_EXPONENT')) {
593
- // http://en.wikipedia.org/wiki/65537_%28number%29
594
- define('CRYPT_RSA_EXPONENT', '65537');
595
- }
596
- // per <http://cseweb.ucsd.edu/~hovav/dist/survey.pdf#page=5>, this number ought not result in primes smaller
597
- // 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
598
- // to 384 bits then you're going to get a 384 bit prime and a 640 bit prime (384 + 1024 % 384). at least if
599
- // CRYPT_RSA_MODE is set to CRYPT_RSA_MODE_INTERNAL. if CRYPT_RSA_MODE is set to CRYPT_RSA_MODE_OPENSSL then
600
- // CRYPT_RSA_SMALLEST_PRIME is ignored (ie. multi-prime RSA support is more intended as a way to speed up RSA key
601
- // generation when there's a chance neither gmp nor OpenSSL are installed)
602
- if (!defined('CRYPT_RSA_SMALLEST_PRIME')) {
603
- define('CRYPT_RSA_SMALLEST_PRIME', 4096);
604
- }
605
-
606
- // OpenSSL uses 65537 as the exponent and requires RSA keys be 384 bits minimum
607
- if (CRYPT_RSA_MODE == CRYPT_RSA_MODE_OPENSSL && $bits >= 384 && CRYPT_RSA_EXPONENT == 65537) {
608
- $config = array();
609
- if (isset($this->configFile)) {
610
- $config['config'] = $this->configFile;
611
- }
612
- $rsa = openssl_pkey_new(array('private_key_bits' => $bits) + $config);
613
- openssl_pkey_export($rsa, $privatekey, null, $config);
614
- $publickey = openssl_pkey_get_details($rsa);
615
- $publickey = $publickey['key'];
616
-
617
- $privatekey = call_user_func_array(array($this, '_convertPrivateKey'), array_values($this->_parseKey($privatekey, CRYPT_RSA_PRIVATE_FORMAT_PKCS1)));
618
- $publickey = call_user_func_array(array($this, '_convertPublicKey'), array_values($this->_parseKey($publickey, CRYPT_RSA_PUBLIC_FORMAT_PKCS1)));
619
-
620
- // clear the buffer of error strings stemming from a minimalistic openssl.cnf
621
- while (openssl_error_string() !== false) {
622
- }
623
-
624
- return array(
625
- 'privatekey' => $privatekey,
626
- 'publickey' => $publickey,
627
- 'partialkey' => false
628
- );
629
- }
630
-
631
- static $e;
632
- if (!isset($e)) {
633
- $e = new Math_BigInteger(CRYPT_RSA_EXPONENT);
634
- }
635
-
636
- extract($this->_generateMinMax($bits));
637
- $absoluteMin = $min;
638
- $temp = $bits >> 1; // divide by two to see how many bits P and Q would be
639
- if ($temp > CRYPT_RSA_SMALLEST_PRIME) {
640
- $num_primes = floor($bits / CRYPT_RSA_SMALLEST_PRIME);
641
- $temp = CRYPT_RSA_SMALLEST_PRIME;
642
- } else {
643
- $num_primes = 2;
644
- }
645
- extract($this->_generateMinMax($temp + $bits % $temp));
646
- $finalMax = $max;
647
- extract($this->_generateMinMax($temp));
648
-
649
- $generator = new Math_BigInteger();
650
-
651
- $n = $this->one->copy();
652
- if (!empty($partial)) {
653
- extract(unserialize($partial));
654
- } else {
655
- $exponents = $coefficients = $primes = array();
656
- $lcm = array(
657
- 'top' => $this->one->copy(),
658
- 'bottom' => false
659
- );
660
- }
661
-
662
- $start = time();
663
- $i0 = count($primes) + 1;
664
-
665
- do {
666
- for ($i = $i0; $i <= $num_primes; $i++) {
667
- if ($timeout !== false) {
668
- $timeout-= time() - $start;
669
- $start = time();
670
- if ($timeout <= 0) {
671
- return array(
672
- 'privatekey' => '',
673
- 'publickey' => '',
674
- 'partialkey' => serialize(array(
675
- 'primes' => $primes,
676
- 'coefficients' => $coefficients,
677
- 'lcm' => $lcm,
678
- 'exponents' => $exponents
679
- ))
680
- );
681
- }
682
- }
683
-
684
- if ($i == $num_primes) {
685
- list($min, $temp) = $absoluteMin->divide($n);
686
- if (!$temp->equals($this->zero)) {
687
- $min = $min->add($this->one); // ie. ceil()
688
- }
689
- $primes[$i] = $generator->randomPrime($min, $finalMax, $timeout);
690
- } else {
691
- $primes[$i] = $generator->randomPrime($min, $max, $timeout);
692
- }
693
-
694
- if ($primes[$i] === false) { // if we've reached the timeout
695
- if (count($primes) > 1) {
696
- $partialkey = '';
697
- } else {
698
- array_pop($primes);
699
- $partialkey = serialize(array(
700
- 'primes' => $primes,
701
- 'coefficients' => $coefficients,
702
- 'lcm' => $lcm,
703
- 'exponents' => $exponents
704
- ));
705
- }
706
-
707
- return array(
708
- 'privatekey' => '',
709
- 'publickey' => '',
710
- 'partialkey' => $partialkey
711
- );
712
- }
713
-
714
- // the first coefficient is calculated differently from the rest
715
- // ie. instead of being $primes[1]->modInverse($primes[2]), it's $primes[2]->modInverse($primes[1])
716
- if ($i > 2) {
717
- $coefficients[$i] = $n->modInverse($primes[$i]);
718
- }
719
-
720
- $n = $n->multiply($primes[$i]);
721
-
722
- $temp = $primes[$i]->subtract($this->one);
723
-
724
- // textbook RSA implementations use Euler's totient function instead of the least common multiple.
725
- // see http://en.wikipedia.org/wiki/Euler%27s_totient_function
726
- $lcm['top'] = $lcm['top']->multiply($temp);
727
- $lcm['bottom'] = $lcm['bottom'] === false ? $temp : $lcm['bottom']->gcd($temp);
728
-
729
- $exponents[$i] = $e->modInverse($temp);
730
- }
731
-
732
- list($temp) = $lcm['top']->divide($lcm['bottom']);
733
- $gcd = $temp->gcd($e);
734
- $i0 = 1;
735
- } while (!$gcd->equals($this->one));
736
-
737
- $d = $e->modInverse($temp);
738
-
739
- $coefficients[2] = $primes[2]->modInverse($primes[1]);
740
-
741
- // from <http://tools.ietf.org/html/rfc3447#appendix-A.1.2>:
742
- // RSAPrivateKey ::= SEQUENCE {
743
- // version Version,
744
- // modulus INTEGER, -- n
745
- // publicExponent INTEGER, -- e
746
- // privateExponent INTEGER, -- d
747
- // prime1 INTEGER, -- p
748
- // prime2 INTEGER, -- q
749
- // exponent1 INTEGER, -- d mod (p-1)
750
- // exponent2 INTEGER, -- d mod (q-1)
751
- // coefficient INTEGER, -- (inverse of q) mod p
752
- // otherPrimeInfos OtherPrimeInfos OPTIONAL
753
- // }
754
-
755
- return array(
756
- 'privatekey' => $this->_convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients),
757
- 'publickey' => $this->_convertPublicKey($n, $e),
758
- 'partialkey' => false
759
- );
760
- }
761
-
762
- /**
763
- * Convert a private key to the appropriate format.
764
- *
765
- * @access private
766
- * @see self::setPrivateKeyFormat()
767
- * @param string $RSAPrivateKey
768
- * @return string
769
- */
770
- function _convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients)
771
- {
772
- $signed = $this->privateKeyFormat != CRYPT_RSA_PRIVATE_FORMAT_XML;
773
- $num_primes = count($primes);
774
- $raw = array(
775
- 'version' => $num_primes == 2 ? chr(0) : chr(1), // two-prime vs. multi
776
- 'modulus' => $n->toBytes($signed),
777
- 'publicExponent' => $e->toBytes($signed),
778
- 'privateExponent' => $d->toBytes($signed),
779
- 'prime1' => $primes[1]->toBytes($signed),
780
- 'prime2' => $primes[2]->toBytes($signed),
781
- 'exponent1' => $exponents[1]->toBytes($signed),
782
- 'exponent2' => $exponents[2]->toBytes($signed),
783
- 'coefficient' => $coefficients[2]->toBytes($signed)
784
- );
785
-
786
- // if the format in question does not support multi-prime rsa and multi-prime rsa was used,
787
- // call _convertPublicKey() instead.
788
- switch ($this->privateKeyFormat) {
789
- case CRYPT_RSA_PRIVATE_FORMAT_XML:
790
- if ($num_primes != 2) {
791
- return false;
792
- }
793
- return "<RSAKeyValue>\r\n" .
794
- ' <Modulus>' . base64_encode($raw['modulus']) . "</Modulus>\r\n" .
795
- ' <Exponent>' . base64_encode($raw['publicExponent']) . "</Exponent>\r\n" .
796
- ' <P>' . base64_encode($raw['prime1']) . "</P>\r\n" .
797
- ' <Q>' . base64_encode($raw['prime2']) . "</Q>\r\n" .
798
- ' <DP>' . base64_encode($raw['exponent1']) . "</DP>\r\n" .
799
- ' <DQ>' . base64_encode($raw['exponent2']) . "</DQ>\r\n" .
800
- ' <InverseQ>' . base64_encode($raw['coefficient']) . "</InverseQ>\r\n" .
801
- ' <D>' . base64_encode($raw['privateExponent']) . "</D>\r\n" .
802
- '</RSAKeyValue>';
803
- break;
804
- case CRYPT_RSA_PRIVATE_FORMAT_PUTTY:
805
- if ($num_primes != 2) {
806
- return false;
807
- }
808
- $key = "PuTTY-User-Key-File-2: ssh-rsa\r\nEncryption: ";
809
- $encryption = (!empty($this->password) || is_string($this->password)) ? 'aes256-cbc' : 'none';
810
- $key.= $encryption;
811
- $key.= "\r\nComment: " . $this->comment . "\r\n";
812
- $public = pack(
813
- 'Na*Na*Na*',
814
- strlen('ssh-rsa'),
815
- 'ssh-rsa',
816
- strlen($raw['publicExponent']),
817
- $raw['publicExponent'],
818
- strlen($raw['modulus']),
819
- $raw['modulus']
820
- );
821
- $source = pack(
822
- 'Na*Na*Na*Na*',
823
- strlen('ssh-rsa'),
824
- 'ssh-rsa',
825
- strlen($encryption),
826
- $encryption,
827
- strlen($this->comment),
828
- $this->comment,
829
- strlen($public),
830
- $public
831
- );
832
- $public = base64_encode($public);
833
- $key.= "Public-Lines: " . ((strlen($public) + 63) >> 6) . "\r\n";
834
- $key.= chunk_split($public, 64);
835
- $private = pack(
836
- 'Na*Na*Na*Na*',
837
- strlen($raw['privateExponent']),
838
- $raw['privateExponent'],
839
- strlen($raw['prime1']),
840
- $raw['prime1'],
841
- strlen($raw['prime2']),
842
- $raw['prime2'],
843
- strlen($raw['coefficient']),
844
- $raw['coefficient']
845
- );
846
- if (empty($this->password) && !is_string($this->password)) {
847
- $source.= pack('Na*', strlen($private), $private);
848
- $hashkey = 'putty-private-key-file-mac-key';
849
- } else {
850
- $private.= crypt_random_string(16 - (strlen($private) & 15));
851
- $source.= pack('Na*', strlen($private), $private);
852
- if (!class_exists('Crypt_AES')) {
853
- include_once 'Crypt/AES.php';
854
- }
855
- $sequence = 0;
856
- $symkey = '';
857
- while (strlen($symkey) < 32) {
858
- $temp = pack('Na*', $sequence++, $this->password);
859
- $symkey.= pack('H*', sha1($temp));
860
- }
861
- $symkey = substr($symkey, 0, 32);
862
- $crypto = new Crypt_AES();
863
-
864
- $crypto->setKey($symkey);
865
- $crypto->disablePadding();
866
- $private = $crypto->encrypt($private);
867
- $hashkey = 'putty-private-key-file-mac-key' . $this->password;
868
- }
869
-
870
- $private = base64_encode($private);
871
- $key.= 'Private-Lines: ' . ((strlen($private) + 63) >> 6) . "\r\n";
872
- $key.= chunk_split($private, 64);
873
- if (!class_exists('Crypt_Hash')) {
874
- include_once 'Crypt/Hash.php';
875
- }
876
- $hash = new Crypt_Hash('sha1');
877
- $hash->setKey(pack('H*', sha1($hashkey)));
878
- $key.= 'Private-MAC: ' . bin2hex($hash->hash($source)) . "\r\n";
879
-
880
- return $key;
881
- default: // eg. CRYPT_RSA_PRIVATE_FORMAT_PKCS1
882
- $components = array();
883
- foreach ($raw as $name => $value) {
884
- $components[$name] = pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($value)), $value);
885
- }
886
-
887
- $RSAPrivateKey = implode('', $components);
888
-
889
- if ($num_primes > 2) {
890
- $OtherPrimeInfos = '';
891
- for ($i = 3; $i <= $num_primes; $i++) {
892
- // OtherPrimeInfos ::= SEQUENCE SIZE(1..MAX) OF OtherPrimeInfo
893
- //
894
- // OtherPrimeInfo ::= SEQUENCE {
895
- // prime INTEGER, -- ri
896
- // exponent INTEGER, -- di
897
- // coefficient INTEGER -- ti
898
- // }
899
- $OtherPrimeInfo = pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($primes[$i]->toBytes(true))), $primes[$i]->toBytes(true));
900
- $OtherPrimeInfo.= pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($exponents[$i]->toBytes(true))), $exponents[$i]->toBytes(true));
901
- $OtherPrimeInfo.= pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($coefficients[$i]->toBytes(true))), $coefficients[$i]->toBytes(true));
902
- $OtherPrimeInfos.= pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($OtherPrimeInfo)), $OtherPrimeInfo);
903
- }
904
- $RSAPrivateKey.= pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($OtherPrimeInfos)), $OtherPrimeInfos);
905
- }
906
-
907
- $RSAPrivateKey = pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);
908
-
909
- if ($this->privateKeyFormat == CRYPT_RSA_PRIVATE_FORMAT_PKCS8) {
910
- $rsaOID = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA
911
- $RSAPrivateKey = pack(
912
- 'Ca*a*Ca*a*',
913
- CRYPT_RSA_ASN1_INTEGER,
914
- "\01\00",
915
- $rsaOID,
916
- 4,
917
- $this->_encodeLength(strlen($RSAPrivateKey)),
918
- $RSAPrivateKey
919
- );
920
- $RSAPrivateKey = pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);
921
- if (!empty($this->password) || is_string($this->password)) {
922
- $salt = crypt_random_string(8);
923
- $iterationCount = 2048;
924
-
925
- if (!class_exists('Crypt_DES')) {
926
- include_once 'Crypt/DES.php';
927
- }
928
- $crypto = new Crypt_DES();
929
- $crypto->setPassword($this->password, 'pbkdf1', 'md5', $salt, $iterationCount);
930
- $RSAPrivateKey = $crypto->encrypt($RSAPrivateKey);
931
-
932
- $parameters = pack(
933
- 'Ca*a*Ca*N',
934
- CRYPT_RSA_ASN1_OCTETSTRING,
935
- $this->_encodeLength(strlen($salt)),
936
- $salt,
937
- CRYPT_RSA_ASN1_INTEGER,
938
- $this->_encodeLength(4),
939
- $iterationCount
940
- );
941
- $pbeWithMD5AndDES_CBC = "\x2a\x86\x48\x86\xf7\x0d\x01\x05\x03";
942
-
943
- $encryptionAlgorithm = pack(
944
- 'Ca*a*Ca*a*',
945
- CRYPT_RSA_ASN1_OBJECT,
946
- $this->_encodeLength(strlen($pbeWithMD5AndDES_CBC)),
947
- $pbeWithMD5AndDES_CBC,
948
- CRYPT_RSA_ASN1_SEQUENCE,
949
- $this->_encodeLength(strlen($parameters)),
950
- $parameters
951
- );
952
-
953
- $RSAPrivateKey = pack(
954
- 'Ca*a*Ca*a*',
955
- CRYPT_RSA_ASN1_SEQUENCE,
956
- $this->_encodeLength(strlen($encryptionAlgorithm)),
957
- $encryptionAlgorithm,
958
- CRYPT_RSA_ASN1_OCTETSTRING,
959
- $this->_encodeLength(strlen($RSAPrivateKey)),
960
- $RSAPrivateKey
961
- );
962
-
963
- $RSAPrivateKey = pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);
964
-
965
- $RSAPrivateKey = "-----BEGIN ENCRYPTED PRIVATE KEY-----\r\n" .
966
- chunk_split(base64_encode($RSAPrivateKey), 64) .
967
- '-----END ENCRYPTED PRIVATE KEY-----';
968
- } else {
969
- $RSAPrivateKey = "-----BEGIN PRIVATE KEY-----\r\n" .
970
- chunk_split(base64_encode($RSAPrivateKey), 64) .
971
- '-----END PRIVATE KEY-----';
972
- }
973
- return $RSAPrivateKey;
974
- }
975
-
976
- if (!empty($this->password) || is_string($this->password)) {
977
- $iv = crypt_random_string(8);
978
- $symkey = pack('H*', md5($this->password . $iv)); // symkey is short for symmetric key
979
- $symkey.= substr(pack('H*', md5($symkey . $this->password . $iv)), 0, 8);
980
- if (!class_exists('Crypt_TripleDES')) {
981
- include_once 'Crypt/TripleDES.php';
982
- }
983
- $des = new Crypt_TripleDES();
984
- $des->setKey($symkey);
985
- $des->setIV($iv);
986
- $iv = strtoupper(bin2hex($iv));
987
- $RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" .
988
- "Proc-Type: 4,ENCRYPTED\r\n" .
989
- "DEK-Info: DES-EDE3-CBC,$iv\r\n" .
990
- "\r\n" .
991
- chunk_split(base64_encode($des->encrypt($RSAPrivateKey)), 64) .
992
- '-----END RSA PRIVATE KEY-----';
993
- } else {
994
- $RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" .
995
- chunk_split(base64_encode($RSAPrivateKey), 64) .
996
- '-----END RSA PRIVATE KEY-----';
997
- }
998
-
999
- return $RSAPrivateKey;
1000
- }
1001
- }
1002
-
1003
- /**
1004
- * Convert a public key to the appropriate format
1005
- *
1006
- * @access private
1007
- * @see self::setPublicKeyFormat()
1008
- * @param string $RSAPrivateKey
1009
- * @return string
1010
- */
1011
- function _convertPublicKey($n, $e)
1012
- {
1013
- $signed = $this->publicKeyFormat != CRYPT_RSA_PUBLIC_FORMAT_XML;
1014
-
1015
- $modulus = $n->toBytes($signed);
1016
- $publicExponent = $e->toBytes($signed);
1017
-
1018
- switch ($this->publicKeyFormat) {
1019
- case CRYPT_RSA_PUBLIC_FORMAT_RAW:
1020
- return array('e' => $e->copy(), 'n' => $n->copy());
1021
- case CRYPT_RSA_PUBLIC_FORMAT_XML:
1022
- return "<RSAKeyValue>\r\n" .
1023
- ' <Modulus>' . base64_encode($modulus) . "</Modulus>\r\n" .
1024
- ' <Exponent>' . base64_encode($publicExponent) . "</Exponent>\r\n" .
1025
- '</RSAKeyValue>';
1026
- break;
1027
- case CRYPT_RSA_PUBLIC_FORMAT_OPENSSH:
1028
- // from <http://tools.ietf.org/html/rfc4253#page-15>:
1029
- // string "ssh-rsa"
1030
- // mpint e
1031
- // mpint n
1032
- $RSAPublicKey = pack('Na*Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($publicExponent), $publicExponent, strlen($modulus), $modulus);
1033
- $RSAPublicKey = 'ssh-rsa ' . base64_encode($RSAPublicKey) . ' ' . $this->comment;
1034
-
1035
- return $RSAPublicKey;
1036
- default: // eg. CRYPT_RSA_PUBLIC_FORMAT_PKCS1_RAW or CRYPT_RSA_PUBLIC_FORMAT_PKCS1
1037
- // from <http://tools.ietf.org/html/rfc3447#appendix-A.1.1>:
1038
- // RSAPublicKey ::= SEQUENCE {
1039
- // modulus INTEGER, -- n
1040
- // publicExponent INTEGER -- e
1041
- // }
1042
- $components = array(
1043
- 'modulus' => pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($modulus)), $modulus),
1044
- 'publicExponent' => pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($publicExponent)), $publicExponent)
1045
- );
1046
-
1047
- $RSAPublicKey = pack(
1048
- 'Ca*a*a*',
1049
- CRYPT_RSA_ASN1_SEQUENCE,
1050
- $this->_encodeLength(strlen($components['modulus']) + strlen($components['publicExponent'])),
1051
- $components['modulus'],
1052
- $components['publicExponent']
1053
- );
1054
-
1055
- if ($this->publicKeyFormat == CRYPT_RSA_PUBLIC_FORMAT_PKCS1_RAW) {
1056
- $RSAPublicKey = "-----BEGIN RSA PUBLIC KEY-----\r\n" .
1057
- chunk_split(base64_encode($RSAPublicKey), 64) .
1058
- '-----END RSA PUBLIC KEY-----';
1059
- } else {
1060
- // sequence(oid(1.2.840.113549.1.1.1), null)) = rsaEncryption.
1061
- $rsaOID = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA
1062
- $RSAPublicKey = chr(0) . $RSAPublicKey;
1063
- $RSAPublicKey = chr(3) . $this->_encodeLength(strlen($RSAPublicKey)) . $RSAPublicKey;
1064
-
1065
- $RSAPublicKey = pack(
1066
- 'Ca*a*',
1067
- CRYPT_RSA_ASN1_SEQUENCE,
1068
- $this->_encodeLength(strlen($rsaOID . $RSAPublicKey)),
1069
- $rsaOID . $RSAPublicKey
1070
- );
1071
-
1072
- $RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" .
1073
- chunk_split(base64_encode($RSAPublicKey), 64) .
1074
- '-----END PUBLIC KEY-----';
1075
- }
1076
-
1077
- return $RSAPublicKey;
1078
- }
1079
- }
1080
-
1081
- /**
1082
- * Break a public or private key down into its constituant components
1083
- *
1084
- * @access private
1085
- * @see self::_convertPublicKey()
1086
- * @see self::_convertPrivateKey()
1087
- * @param string $key
1088
- * @param int $type
1089
- * @return array
1090
- */
1091
- function _parseKey($key, $type)
1092
- {
1093
- if ($type != CRYPT_RSA_PUBLIC_FORMAT_RAW && !is_string($key)) {
1094
- return false;
1095
- }
1096
-
1097
- switch ($type) {
1098
- case CRYPT_RSA_PUBLIC_FORMAT_RAW:
1099
- if (!is_array($key)) {
1100
- return false;
1101
- }
1102
- $components = array();
1103
- switch (true) {
1104
- case isset($key['e']):
1105
- $components['publicExponent'] = $key['e']->copy();
1106
- break;
1107
- case isset($key['exponent']):
1108
- $components['publicExponent'] = $key['exponent']->copy();
1109
- break;
1110
- case isset($key['publicExponent']):
1111
- $components['publicExponent'] = $key['publicExponent']->copy();
1112
- break;
1113
- case isset($key[0]):
1114
- $components['publicExponent'] = $key[0]->copy();
1115
- }
1116
- switch (true) {
1117
- case isset($key['n']):
1118
- $components['modulus'] = $key['n']->copy();
1119
- break;
1120
- case isset($key['modulo']):
1121
- $components['modulus'] = $key['modulo']->copy();
1122
- break;
1123
- case isset($key['modulus']):
1124
- $components['modulus'] = $key['modulus']->copy();
1125
- break;
1126
- case isset($key[1]):
1127
- $components['modulus'] = $key[1]->copy();
1128
- }
1129
- return isset($components['modulus']) && isset($components['publicExponent']) ? $components : false;
1130
- case CRYPT_RSA_PRIVATE_FORMAT_PKCS1:
1131
- case CRYPT_RSA_PRIVATE_FORMAT_PKCS8:
1132
- case CRYPT_RSA_PUBLIC_FORMAT_PKCS1:
1133
- /* Although PKCS#1 proposes a format that public and private keys can use, encrypting them is
1134
- "outside the scope" of PKCS#1. PKCS#1 then refers you to PKCS#12 and PKCS#15 if you're wanting to
1135
- protect private keys, however, that's not what OpenSSL* does. OpenSSL protects private keys by adding
1136
- two new "fields" to the key - DEK-Info and Proc-Type. These fields are discussed here:
1137
-
1138
- http://tools.ietf.org/html/rfc1421#section-4.6.1.1
1139
- http://tools.ietf.org/html/rfc1421#section-4.6.1.3
1140
-
1141
- DES-EDE3-CBC as an algorithm, however, is not discussed anywhere, near as I can tell.
1142
- DES-CBC and DES-EDE are discussed in RFC1423, however, DES-EDE3-CBC isn't, nor is its key derivation
1143
- function. As is, the definitive authority on this encoding scheme isn't the IETF but rather OpenSSL's
1144
- own implementation. ie. the implementation *is* the standard and any bugs that may exist in that
1145
- implementation are part of the standard, as well.
1146
-
1147
- * OpenSSL is the de facto standard. It's utilized by OpenSSH and other projects */
1148
- if (preg_match('#DEK-Info: (.+),(.+)#', $key, $matches)) {
1149
- $iv = pack('H*', trim($matches[2]));
1150
- $symkey = pack('H*', md5($this->password . substr($iv, 0, 8))); // symkey is short for symmetric key
1151
- $symkey.= pack('H*', md5($symkey . $this->password . substr($iv, 0, 8)));
1152
- // remove the Proc-Type / DEK-Info sections as they're no longer needed
1153
- $key = preg_replace('#^(?:Proc-Type|DEK-Info): .*#m', '', $key);
1154
- $ciphertext = $this->_extractBER($key);
1155
- if ($ciphertext === false) {
1156
- $ciphertext = $key;
1157
- }
1158
- switch ($matches[1]) {
1159
- case 'AES-256-CBC':
1160
- if (!class_exists('Crypt_AES')) {
1161
- include_once 'Crypt/AES.php';
1162
- }
1163
- $crypto = new Crypt_AES();
1164
- break;
1165
- case 'AES-128-CBC':
1166
- if (!class_exists('Crypt_AES')) {
1167
- include_once 'Crypt/AES.php';
1168
- }
1169
- $symkey = substr($symkey, 0, 16);
1170
- $crypto = new Crypt_AES();
1171
- break;
1172
- case 'DES-EDE3-CFB':
1173
- if (!class_exists('Crypt_TripleDES')) {
1174
- include_once 'Crypt/TripleDES.php';
1175
- }
1176
- $crypto = new Crypt_TripleDES(CRYPT_DES_MODE_CFB);
1177
- break;
1178
- case 'DES-EDE3-CBC':
1179
- if (!class_exists('Crypt_TripleDES')) {
1180
- include_once 'Crypt/TripleDES.php';
1181
- }
1182
- $symkey = substr($symkey, 0, 24);
1183
- $crypto = new Crypt_TripleDES();
1184
- break;
1185
- case 'DES-CBC':
1186
- if (!class_exists('Crypt_DES')) {
1187
- include_once 'Crypt/DES.php';
1188
- }
1189
- $crypto = new Crypt_DES();
1190
- break;
1191
- default:
1192
- return false;
1193
- }
1194
- $crypto->setKey($symkey);
1195
- $crypto->setIV($iv);
1196
- $decoded = $crypto->decrypt($ciphertext);
1197
- } else {
1198
- $decoded = $this->_extractBER($key);
1199
- }
1200
-
1201
- if ($decoded !== false) {
1202
- $key = $decoded;
1203
- }
1204
-
1205
- $components = array();
1206
-
1207
- if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
1208
- return false;
1209
- }
1210
- if ($this->_decodeLength($key) != strlen($key)) {
1211
- return false;
1212
- }
1213
-
1214
- $tag = ord($this->_string_shift($key));
1215
- /* intended for keys for which OpenSSL's asn1parse returns the following:
1216
-
1217
- 0:d=0 hl=4 l= 631 cons: SEQUENCE
1218
- 4:d=1 hl=2 l= 1 prim: INTEGER :00
1219
- 7:d=1 hl=2 l= 13 cons: SEQUENCE
1220
- 9:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption
1221
- 20:d=2 hl=2 l= 0 prim: NULL
1222
- 22:d=1 hl=4 l= 609 prim: OCTET STRING
1223
-
1224
- ie. PKCS8 keys*/
1225
-
1226
- if ($tag == CRYPT_RSA_ASN1_INTEGER && substr($key, 0, 3) == "\x01\x00\x30") {
1227
- $this->_string_shift($key, 3);
1228
- $tag = CRYPT_RSA_ASN1_SEQUENCE;
1229
- }
1230
-
1231
- if ($tag == CRYPT_RSA_ASN1_SEQUENCE) {
1232
- $temp = $this->_string_shift($key, $this->_decodeLength($key));
1233
- if (ord($this->_string_shift($temp)) != CRYPT_RSA_ASN1_OBJECT) {
1234
- return false;
1235
- }
1236
- $length = $this->_decodeLength($temp);
1237
- switch ($this->_string_shift($temp, $length)) {
1238
- case "\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01": // rsaEncryption
1239
- break;
1240
- case "\x2a\x86\x48\x86\xf7\x0d\x01\x05\x03": // pbeWithMD5AndDES-CBC
1241
- /*
1242
- PBEParameter ::= SEQUENCE {
1243
- salt OCTET STRING (SIZE(8)),
1244
- iterationCount INTEGER }
1245
- */
1246
- if (ord($this->_string_shift($temp)) != CRYPT_RSA_ASN1_SEQUENCE) {
1247
- return false;
1248
- }
1249
- if ($this->_decodeLength($temp) != strlen($temp)) {
1250
- return false;
1251
- }
1252
- $this->_string_shift($temp); // assume it's an octet string
1253
- $salt = $this->_string_shift($temp, $this->_decodeLength($temp));
1254
- if (ord($this->_string_shift($temp)) != CRYPT_RSA_ASN1_INTEGER) {
1255
- return false;
1256
- }
1257
- $this->_decodeLength($temp);
1258
- list(, $iterationCount) = unpack('N', str_pad($temp, 4, chr(0), STR_PAD_LEFT));
1259
- $this->_string_shift($key); // assume it's an octet string
1260
- $length = $this->_decodeLength($key);
1261
- if (strlen($key) != $length) {
1262
- return false;
1263
- }
1264
-
1265
- if (!class_exists('Crypt_DES')) {
1266
- include_once 'Crypt/DES.php';
1267
- }
1268
- $crypto = new Crypt_DES();
1269
- $crypto->setPassword($this->password, 'pbkdf1', 'md5', $salt, $iterationCount);
1270
- $key = $crypto->decrypt($key);
1271
- if ($key === false) {
1272
- return false;
1273
- }
1274
- return $this->_parseKey($key, CRYPT_RSA_PRIVATE_FORMAT_PKCS1);
1275
- default:
1276
- return false;
1277
- }
1278
- /* intended for keys for which OpenSSL's asn1parse returns the following:
1279
-
1280
- 0:d=0 hl=4 l= 290 cons: SEQUENCE
1281
- 4:d=1 hl=2 l= 13 cons: SEQUENCE
1282
- 6:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption
1283
- 17:d=2 hl=2 l= 0 prim: NULL
1284
- 19:d=1 hl=4 l= 271 prim: BIT STRING */
1285
- $tag = ord($this->_string_shift($key)); // skip over the BIT STRING / OCTET STRING tag
1286
- $this->_decodeLength($key); // skip over the BIT STRING / OCTET STRING length
1287
- // "The initial octet shall encode, as an unsigned binary integer wtih bit 1 as the least significant bit, the number of
1288
- // unused bits in the final subsequent octet. The number shall be in the range zero to seven."
1289
- // -- http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf (section 8.6.2.2)
1290
- if ($tag == CRYPT_RSA_ASN1_BITSTRING) {
1291
- $this->_string_shift($key);
1292
- }
1293
- if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
1294
- return false;
1295
- }
1296
- if ($this->_decodeLength($key) != strlen($key)) {
1297
- return false;
1298
- }
1299
- $tag = ord($this->_string_shift($key));
1300
- }
1301
- if ($tag != CRYPT_RSA_ASN1_INTEGER) {
1302
- return false;
1303
- }
1304
-
1305
- $length = $this->_decodeLength($key);
1306
- $temp = $this->_string_shift($key, $length);
1307
- if (strlen($temp) != 1 || ord($temp) > 2) {
1308
- $components['modulus'] = new Math_BigInteger($temp, 256);
1309
- $this->_string_shift($key); // skip over CRYPT_RSA_ASN1_INTEGER
1310
- $length = $this->_decodeLength($key);
1311
- $components[$type == CRYPT_RSA_PUBLIC_FORMAT_PKCS1 ? 'publicExponent' : 'privateExponent'] = new Math_BigInteger($this->_string_shift($key, $length), 256);
1312
-
1313
- return $components;
1314
- }
1315
- if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_INTEGER) {
1316
- return false;
1317
- }
1318
- $length = $this->_decodeLength($key);
1319
- $components['modulus'] = new Math_BigInteger($this->_string_shift($key, $length), 256);
1320
- $this->_string_shift($key);
1321
- $length = $this->_decodeLength($key);
1322
- $components['publicExponent'] = new Math_BigInteger($this->_string_shift($key, $length), 256);
1323
- $this->_string_shift($key);
1324
- $length = $this->_decodeLength($key);
1325
- $components['privateExponent'] = new Math_BigInteger($this->_string_shift($key, $length), 256);
1326
- $this->_string_shift($key);
1327
- $length = $this->_decodeLength($key);
1328
- $components['primes'] = array(1 => new Math_BigInteger($this->_string_shift($key, $length), 256));
1329
- $this->_string_shift($key);
1330
- $length = $this->_decodeLength($key);
1331
- $components['primes'][] = new Math_BigInteger($this->_string_shift($key, $length), 256);
1332
- $this->_string_shift($key);
1333
- $length = $this->_decodeLength($key);
1334
- $components['exponents'] = array(1 => new Math_BigInteger($this->_string_shift($key, $length), 256));
1335
- $this->_string_shift($key);
1336
- $length = $this->_decodeLength($key);
1337
- $components['exponents'][] = new Math_BigInteger($this->_string_shift($key, $length), 256);
1338
- $this->_string_shift($key);
1339
- $length = $this->_decodeLength($key);
1340
- $components['coefficients'] = array(2 => new Math_BigInteger($this->_string_shift($key, $length), 256));
1341
-
1342
- if (!empty($key)) {
1343
- if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
1344
- return false;
1345
- }
1346
- $this->_decodeLength($key);
1347
- while (!empty($key)) {
1348
- if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
1349
- return false;
1350
- }
1351
- $this->_decodeLength($key);
1352
- $key = substr($key, 1);
1353
- $length = $this->_decodeLength($key);
1354
- $components['primes'][] = new Math_BigInteger($this->_string_shift($key, $length), 256);
1355
- $this->_string_shift($key);
1356
- $length = $this->_decodeLength($key);
1357
- $components['exponents'][] = new Math_BigInteger($this->_string_shift($key, $length), 256);
1358
- $this->_string_shift($key);
1359
- $length = $this->_decodeLength($key);
1360
- $components['coefficients'][] = new Math_BigInteger($this->_string_shift($key, $length), 256);
1361
- }
1362
- }
1363
-
1364
- return $components;
1365
- case CRYPT_RSA_PUBLIC_FORMAT_OPENSSH:
1366
- $parts = explode(' ', $key, 3);
1367
-
1368
- $key = isset($parts[1]) ? base64_decode($parts[1]) : false;
1369
- if ($key === false) {
1370
- return false;
1371
- }
1372
-
1373
- $comment = isset($parts[2]) ? $parts[2] : false;
1374
-
1375
- $cleanup = substr($key, 0, 11) == "\0\0\0\7ssh-rsa";
1376
-
1377
- if (strlen($key) <= 4) {
1378
- return false;
1379
- }
1380
- extract(unpack('Nlength', $this->_string_shift($key, 4)));
1381
- $publicExponent = new Math_BigInteger($this->_string_shift($key, $length), -256);
1382
- if (strlen($key) <= 4) {
1383
- return false;
1384
- }
1385
- extract(unpack('Nlength', $this->_string_shift($key, 4)));
1386
- $modulus = new Math_BigInteger($this->_string_shift($key, $length), -256);
1387
-
1388
- if ($cleanup && strlen($key)) {
1389
- if (strlen($key) <= 4) {
1390
- return false;
1391
- }
1392
- extract(unpack('Nlength', $this->_string_shift($key, 4)));
1393
- $realModulus = new Math_BigInteger($this->_string_shift($key, $length), -256);
1394
- return strlen($key) ? false : array(
1395
- 'modulus' => $realModulus,
1396
- 'publicExponent' => $modulus,
1397
- 'comment' => $comment
1398
- );
1399
- } else {
1400
- return strlen($key) ? false : array(
1401
- 'modulus' => $modulus,
1402
- 'publicExponent' => $publicExponent,
1403
- 'comment' => $comment
1404
- );
1405
- }
1406
- // http://www.w3.org/TR/xmldsig-core/#sec-RSAKeyValue
1407
- // http://en.wikipedia.org/wiki/XML_Signature
1408
- case CRYPT_RSA_PRIVATE_FORMAT_XML:
1409
- case CRYPT_RSA_PUBLIC_FORMAT_XML:
1410
- $this->components = array();
1411
-
1412
- $xml = xml_parser_create('UTF-8');
1413
- xml_set_object($xml, $this);
1414
- xml_set_element_handler($xml, '_start_element_handler', '_stop_element_handler');
1415
- xml_set_character_data_handler($xml, '_data_handler');
1416
- // add <xml></xml> to account for "dangling" tags like <BitStrength>...</BitStrength> that are sometimes added
1417
- if (!xml_parse($xml, '<xml>' . $key . '</xml>')) {
1418
- return false;
1419
- }
1420
-
1421
- return isset($this->components['modulus']) && isset($this->components['publicExponent']) ? $this->components : false;
1422
- // from PuTTY's SSHPUBK.C
1423
- case CRYPT_RSA_PRIVATE_FORMAT_PUTTY:
1424
- $components = array();
1425
- $key = preg_split('#\r\n|\r|\n#', $key);
1426
- $type = trim(preg_replace('#PuTTY-User-Key-File-2: (.+)#', '$1', $key[0]));
1427
- if ($type != 'ssh-rsa') {
1428
- return false;
1429
- }
1430
- $encryption = trim(preg_replace('#Encryption: (.+)#', '$1', $key[1]));
1431
- $comment = trim(preg_replace('#Comment: (.+)#', '$1', $key[2]));
1432
-
1433
- $publicLength = trim(preg_replace('#Public-Lines: (\d+)#', '$1', $key[3]));
1434
- $public = base64_decode(implode('', array_map('trim', array_slice($key, 4, $publicLength))));
1435
- $public = substr($public, 11);
1436
- extract(unpack('Nlength', $this->_string_shift($public, 4)));
1437
- $components['publicExponent'] = new Math_BigInteger($this->_string_shift($public, $length), -256);
1438
- extract(unpack('Nlength', $this->_string_shift($public, 4)));
1439
- $components['modulus'] = new Math_BigInteger($this->_string_shift($public, $length), -256);
1440
-
1441
- $privateLength = trim(preg_replace('#Private-Lines: (\d+)#', '$1', $key[$publicLength + 4]));
1442
- $private = base64_decode(implode('', array_map('trim', array_slice($key, $publicLength + 5, $privateLength))));
1443
-
1444
- switch ($encryption) {
1445
- case 'aes256-cbc':
1446
- if (!class_exists('Crypt_AES')) {
1447
- include_once 'Crypt/AES.php';
1448
- }
1449
- $symkey = '';
1450
- $sequence = 0;
1451
- while (strlen($symkey) < 32) {
1452
- $temp = pack('Na*', $sequence++, $this->password);
1453
- $symkey.= pack('H*', sha1($temp));
1454
- }
1455
- $symkey = substr($symkey, 0, 32);
1456
- $crypto = new Crypt_AES();
1457
- }
1458
-
1459
- if ($encryption != 'none') {
1460
- $crypto->setKey($symkey);
1461
- $crypto->disablePadding();
1462
- $private = $crypto->decrypt($private);
1463
- if ($private === false) {
1464
- return false;
1465
- }
1466
- }
1467
-
1468
- extract(unpack('Nlength', $this->_string_shift($private, 4)));
1469
- if (strlen($private) < $length) {
1470
- return false;
1471
- }
1472
- $components['privateExponent'] = new Math_BigInteger($this->_string_shift($private, $length), -256);
1473
- extract(unpack('Nlength', $this->_string_shift($private, 4)));
1474
- if (strlen($private) < $length) {
1475
- return false;
1476
- }
1477
- $components['primes'] = array(1 => new Math_BigInteger($this->_string_shift($private, $length), -256));
1478
- extract(unpack('Nlength', $this->_string_shift($private, 4)));
1479
- if (strlen($private) < $length) {
1480
- return false;
1481
- }
1482
- $components['primes'][] = new Math_BigInteger($this->_string_shift($private, $length), -256);
1483
-
1484
- $temp = $components['primes'][1]->subtract($this->one);
1485
- $components['exponents'] = array(1 => $components['publicExponent']->modInverse($temp));
1486
- $temp = $components['primes'][2]->subtract($this->one);
1487
- $components['exponents'][] = $components['publicExponent']->modInverse($temp);
1488
-
1489
- extract(unpack('Nlength', $this->_string_shift($private, 4)));
1490
- if (strlen($private) < $length) {
1491
- return false;
1492
- }
1493
- $components['coefficients'] = array(2 => new Math_BigInteger($this->_string_shift($private, $length), -256));
1494
-
1495
- return $components;
1496
- }
1497
- }
1498
-
1499
- /**
1500
- * Returns the key size
1501
- *
1502
- * More specifically, this returns the size of the modulo in bits.
1503
- *
1504
- * @access public
1505
- * @return int
1506
- */
1507
- function getSize()
1508
- {
1509
- return !isset($this->modulus) ? 0 : strlen($this->modulus->toBits());
1510
- }
1511
-
1512
- /**
1513
- * Start Element Handler
1514
- *
1515
- * Called by xml_set_element_handler()
1516
- *
1517
- * @access private
1518
- * @param resource $parser
1519
- * @param string $name
1520
- * @param array $attribs
1521
- */
1522
- function _start_element_handler($parser, $name, $attribs)
1523
- {
1524
- //$name = strtoupper($name);
1525
- switch ($name) {
1526
- case 'MODULUS':
1527
- $this->current = &$this->components['modulus'];
1528
- break;
1529
- case 'EXPONENT':
1530
- $this->current = &$this->components['publicExponent'];
1531
- break;
1532
- case 'P':
1533
- $this->current = &$this->components['primes'][1];
1534
- break;
1535
- case 'Q':
1536
- $this->current = &$this->components['primes'][2];
1537
- break;
1538
- case 'DP':
1539
- $this->current = &$this->components['exponents'][1];
1540
- break;
1541
- case 'DQ':
1542
- $this->current = &$this->components['exponents'][2];
1543
- break;
1544
- case 'INVERSEQ':
1545
- $this->current = &$this->components['coefficients'][2];
1546
- break;
1547
- case 'D':
1548
- $this->current = &$this->components['privateExponent'];
1549
- }
1550
- $this->current = '';
1551
- }
1552
-
1553
- /**
1554
- * Stop Element Handler
1555
- *
1556
- * Called by xml_set_element_handler()
1557
- *
1558
- * @access private
1559
- * @param resource $parser
1560
- * @param string $name
1561
- */
1562
- function _stop_element_handler($parser, $name)
1563
- {
1564
- if (isset($this->current)) {
1565
- $this->current = new Math_BigInteger(base64_decode($this->current), 256);
1566
- unset($this->current);
1567
- }
1568
- }
1569
-
1570
- /**
1571
- * Data Handler
1572
- *
1573
- * Called by xml_set_character_data_handler()
1574
- *
1575
- * @access private
1576
- * @param resource $parser
1577
- * @param string $data
1578
- */
1579
- function _data_handler($parser, $data)
1580
- {
1581
- if (!isset($this->current) || is_object($this->current)) {
1582
- return;
1583
- }
1584
- $this->current.= trim($data);
1585
- }
1586
-
1587
- /**
1588
- * Loads a public or private key
1589
- *
1590
- * Returns true on success and false on failure (ie. an incorrect password was provided or the key was malformed)
1591
- *
1592
- * @access public
1593
- * @param string $key
1594
- * @param int $type optional
1595
- */
1596
- function loadKey($key, $type = false)
1597
- {
1598
- if (is_object($key) && strtolower(get_class($key)) == 'crypt_rsa') {
1599
- $this->privateKeyFormat = $key->privateKeyFormat;
1600
- $this->publicKeyFormat = $key->publicKeyFormat;
1601
- $this->k = $key->k;
1602
- $this->hLen = $key->hLen;
1603
- $this->sLen = $key->sLen;
1604
- $this->mgfHLen = $key->mgfHLen;
1605
- $this->encryptionMode = $key->encryptionMode;
1606
- $this->signatureMode = $key->signatureMode;
1607
- $this->password = $key->password;
1608
- $this->configFile = $key->configFile;
1609
- $this->comment = $key->comment;
1610
-
1611
- if (is_object($key->hash)) {
1612
- $this->hash = new Crypt_Hash($key->hash->getHash());
1613
- }
1614
- if (is_object($key->mgfHash)) {
1615
- $this->mgfHash = new Crypt_Hash($key->mgfHash->getHash());
1616
- }
1617
-
1618
- if (is_object($key->modulus)) {
1619
- $this->modulus = $key->modulus->copy();
1620
- }
1621
- if (is_object($key->exponent)) {
1622
- $this->exponent = $key->exponent->copy();
1623
- }
1624
- if (is_object($key->publicExponent)) {
1625
- $this->publicExponent = $key->publicExponent->copy();
1626
- }
1627
-
1628
- $this->primes = array();
1629
- $this->exponents = array();
1630
- $this->coefficients = array();
1631
-
1632
- foreach ($this->primes as $prime) {
1633
- $this->primes[] = $prime->copy();
1634
- }
1635
- foreach ($this->exponents as $exponent) {
1636
- $this->exponents[] = $exponent->copy();
1637
- }
1638
- foreach ($this->coefficients as $coefficient) {
1639
- $this->coefficients[] = $coefficient->copy();
1640
- }
1641
-
1642
- return true;
1643
- }
1644
-
1645
- if ($type === false) {
1646
- $types = array(
1647
- CRYPT_RSA_PUBLIC_FORMAT_RAW,
1648
- CRYPT_RSA_PRIVATE_FORMAT_PKCS1,
1649
- CRYPT_RSA_PRIVATE_FORMAT_XML,
1650
- CRYPT_RSA_PRIVATE_FORMAT_PUTTY,
1651
- CRYPT_RSA_PUBLIC_FORMAT_OPENSSH
1652
- );
1653
- foreach ($types as $type) {
1654
- $components = $this->_parseKey($key, $type);
1655
- if ($components !== false) {
1656
- break;
1657
- }
1658
- }
1659
- } else {
1660
- $components = $this->_parseKey($key, $type);
1661
- }
1662
-
1663
- if ($components === false) {
1664
- return false;
1665
- }
1666
-
1667
- if (isset($components['comment']) && $components['comment'] !== false) {
1668
- $this->comment = $components['comment'];
1669
- }
1670
- $this->modulus = $components['modulus'];
1671
- $this->k = strlen($this->modulus->toBytes());
1672
- $this->exponent = isset($components['privateExponent']) ? $components['privateExponent'] : $components['publicExponent'];
1673
- if (isset($components['primes'])) {
1674
- $this->primes = $components['primes'];
1675
- $this->exponents = $components['exponents'];
1676
- $this->coefficients = $components['coefficients'];
1677
- $this->publicExponent = $components['publicExponent'];
1678
- } else {
1679
- $this->primes = array();
1680
- $this->exponents = array();
1681
- $this->coefficients = array();
1682
- $this->publicExponent = false;
1683
- }
1684
-
1685
- switch ($type) {
1686
- case CRYPT_RSA_PUBLIC_FORMAT_OPENSSH:
1687
- case CRYPT_RSA_PUBLIC_FORMAT_RAW:
1688
- $this->setPublicKey();
1689
- break;
1690
- case CRYPT_RSA_PRIVATE_FORMAT_PKCS1:
1691
- switch (true) {
1692
- case strpos($key, '-BEGIN PUBLIC KEY-') !== false:
1693
- case strpos($key, '-BEGIN RSA PUBLIC KEY-') !== false:
1694
- $this->setPublicKey();
1695
- }
1696
- }
1697
-
1698
- return true;
1699
- }
1700
-
1701
- /**
1702
- * Sets the password
1703
- *
1704
- * Private keys can be encrypted with a password. To unset the password, pass in the empty string or false.
1705
- * Or rather, pass in $password such that empty($password) && !is_string($password) is true.
1706
- *
1707
- * @see self::createKey()
1708
- * @see self::loadKey()
1709
- * @access public
1710
- * @param string $password
1711
- */
1712
- function setPassword($password = false)
1713
- {
1714
- $this->password = $password;
1715
- }
1716
-
1717
- /**
1718
- * Defines the public key
1719
- *
1720
- * Some private key formats define the public exponent and some don't. Those that don't define it are problematic when
1721
- * used in certain contexts. For example, in SSH-2, RSA authentication works by sending the public key along with a
1722
- * message signed by the private key to the server. The SSH-2 server looks the public key up in an index of public keys
1723
- * and if it's present then proceeds to verify the signature. Problem is, if your private key doesn't include the public
1724
- * exponent this won't work unless you manually add the public exponent. phpseclib tries to guess if the key being used
1725
- * is the public key but in the event that it guesses incorrectly you might still want to explicitly set the key as being
1726
- * public.
1727
- *
1728
- * Do note that when a new key is loaded the index will be cleared.
1729
- *
1730
- * Returns true on success, false on failure
1731
- *
1732
- * @see self::getPublicKey()
1733
- * @access public
1734
- * @param string $key optional
1735
- * @param int $type optional
1736
- * @return bool
1737
- */
1738
- function setPublicKey($key = false, $type = false)
1739
- {
1740
- // if a public key has already been loaded return false
1741
- if (!empty($this->publicExponent)) {
1742
- return false;
1743
- }
1744
-
1745
- if ($key === false && !empty($this->modulus)) {
1746
- $this->publicExponent = $this->exponent;
1747
- return true;
1748
- }
1749
-
1750
- if ($type === false) {
1751
- $types = array(
1752
- CRYPT_RSA_PUBLIC_FORMAT_RAW,
1753
- CRYPT_RSA_PUBLIC_FORMAT_PKCS1,
1754
- CRYPT_RSA_PUBLIC_FORMAT_XML,
1755
- CRYPT_RSA_PUBLIC_FORMAT_OPENSSH
1756
- );
1757
- foreach ($types as $type) {
1758
- $components = $this->_parseKey($key, $type);
1759
- if ($components !== false) {
1760
- break;
1761
- }
1762
- }
1763
- } else {
1764
- $components = $this->_parseKey($key, $type);
1765
- }
1766
-
1767
- if ($components === false) {
1768
- return false;
1769
- }
1770
-
1771
- if (empty($this->modulus) || !$this->modulus->equals($components['modulus'])) {
1772
- $this->modulus = $components['modulus'];
1773
- $this->exponent = $this->publicExponent = $components['publicExponent'];
1774
- return true;
1775
- }
1776
-
1777
- $this->publicExponent = $components['publicExponent'];
1778
-
1779
- return true;
1780
- }
1781
-
1782
- /**
1783
- * Defines the private key
1784
- *
1785
- * If phpseclib guessed a private key was a public key and loaded it as such it might be desirable to force
1786
- * phpseclib to treat the key as a private key. This function will do that.
1787
- *
1788
- * Do note that when a new key is loaded the index will be cleared.
1789
- *
1790
- * Returns true on success, false on failure
1791
- *
1792
- * @see self::getPublicKey()
1793
- * @access public
1794
- * @param string $key optional
1795
- * @param int $type optional
1796
- * @return bool
1797
- */
1798
- function setPrivateKey($key = false, $type = false)
1799
- {
1800
- if ($key === false && !empty($this->publicExponent)) {
1801
- $this->publicExponent = false;
1802
- return true;
1803
- }
1804
-
1805
- $rsa = new Crypt_RSA();
1806
- if (!$rsa->loadKey($key, $type)) {
1807
- return false;
1808
- }
1809
- $rsa->publicExponent = false;
1810
-
1811
- // don't overwrite the old key if the new key is invalid
1812
- $this->loadKey($rsa);
1813
- return true;
1814
- }
1815
-
1816
- /**
1817
- * Returns the public key
1818
- *
1819
- * The public key is only returned under two circumstances - if the private key had the public key embedded within it
1820
- * or if the public key was set via setPublicKey(). If the currently loaded key is supposed to be the public key this
1821
- * function won't return it since this library, for the most part, doesn't distinguish between public and private keys.
1822
- *
1823
- * @see self::getPublicKey()
1824
- * @access public
1825
- * @param string $key
1826
- * @param int $type optional
1827
- */
1828
- function getPublicKey($type = CRYPT_RSA_PUBLIC_FORMAT_PKCS8)
1829
- {
1830
- if (empty($this->modulus) || empty($this->publicExponent)) {
1831
- return false;
1832
- }
1833
-
1834
- $oldFormat = $this->publicKeyFormat;
1835
- $this->publicKeyFormat = $type;
1836
- $temp = $this->_convertPublicKey($this->modulus, $this->publicExponent);
1837
- $this->publicKeyFormat = $oldFormat;
1838
- return $temp;
1839
- }
1840
-
1841
- /**
1842
- * Returns the public key's fingerprint
1843
- *
1844
- * The public key's fingerprint is returned, which is equivalent to running `ssh-keygen -lf rsa.pub`. If there is
1845
- * no public key currently loaded, false is returned.
1846
- * Example output (md5): "c1:b1:30:29:d7:b8:de:6c:97:77:10:d7:46:41:63:87" (as specified by RFC 4716)
1847
- *
1848
- * @access public
1849
- * @param string $algorithm The hashing algorithm to be used. Valid options are 'md5' and 'sha256'. False is returned
1850
- * for invalid values.
1851
- * @return mixed
1852
- */
1853
- function getPublicKeyFingerprint($algorithm = 'md5')
1854
- {
1855
- if (empty($this->modulus) || empty($this->publicExponent)) {
1856
- return false;
1857
- }
1858
-
1859
- $modulus = $this->modulus->toBytes(true);
1860
- $publicExponent = $this->publicExponent->toBytes(true);
1861
-
1862
- $RSAPublicKey = pack('Na*Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($publicExponent), $publicExponent, strlen($modulus), $modulus);
1863
-
1864
- switch ($algorithm) {
1865
- case 'sha256':
1866
- $hash = new Crypt_Hash('sha256');
1867
- $base = base64_encode($hash->hash($RSAPublicKey));
1868
- return substr($base, 0, strlen($base) - 1);
1869
- case 'md5':
1870
- return substr(chunk_split(md5($RSAPublicKey), 2, ':'), 0, -1);
1871
- default:
1872
- return false;
1873
- }
1874
- }
1875
-
1876
- /**
1877
- * Returns the private key
1878
- *
1879
- * The private key is only returned if the currently loaded key contains the constituent prime numbers.
1880
- *
1881
- * @see self::getPublicKey()
1882
- * @access public
1883
- * @param string $key
1884
- * @param int $type optional
1885
- * @return mixed
1886
- */
1887
- function getPrivateKey($type = CRYPT_RSA_PUBLIC_FORMAT_PKCS1)
1888
- {
1889
- if (empty($this->primes)) {
1890
- return false;
1891
- }
1892
-
1893
- $oldFormat = $this->privateKeyFormat;
1894
- $this->privateKeyFormat = $type;
1895
- $temp = $this->_convertPrivateKey($this->modulus, $this->publicExponent, $this->exponent, $this->primes, $this->exponents, $this->coefficients);
1896
- $this->privateKeyFormat = $oldFormat;
1897
- return $temp;
1898
- }
1899
-
1900
- /**
1901
- * Returns a minimalistic private key
1902
- *
1903
- * Returns the private key without the prime number constituants. Structurally identical to a public key that
1904
- * hasn't been set as the public key
1905
- *
1906
- * @see self::getPrivateKey()
1907
- * @access private
1908
- * @param string $key
1909
- * @param int $type optional
1910
- */
1911
- function _getPrivatePublicKey($mode = CRYPT_RSA_PUBLIC_FORMAT_PKCS8)
1912
- {
1913
- if (empty($this->modulus) || empty($this->exponent)) {
1914
- return false;
1915
- }
1916
-
1917
- $oldFormat = $this->publicKeyFormat;
1918
- $this->publicKeyFormat = $mode;
1919
- $temp = $this->_convertPublicKey($this->modulus, $this->exponent);
1920
- $this->publicKeyFormat = $oldFormat;
1921
- return $temp;
1922
- }
1923
-
1924
- /**
1925
- * __toString() magic method
1926
- *
1927
- * @access public
1928
- * @return string
1929
- */
1930
- function __toString()
1931
- {
1932
- $key = $this->getPrivateKey($this->privateKeyFormat);
1933
- if ($key !== false) {
1934
- return $key;
1935
- }
1936
- $key = $this->_getPrivatePublicKey($this->publicKeyFormat);
1937
- return $key !== false ? $key : '';
1938
- }
1939
-
1940
- /**
1941
- * __clone() magic method
1942
- *
1943
- * @access public
1944
- * @return Crypt_RSA
1945
- */
1946
- function __clone()
1947
- {
1948
- $key = new Crypt_RSA();
1949
- $key->loadKey($this);
1950
- return $key;
1951
- }
1952
-
1953
- /**
1954
- * Generates the smallest and largest numbers requiring $bits bits
1955
- *
1956
- * @access private
1957
- * @param int $bits
1958
- * @return array
1959
- */
1960
- function _generateMinMax($bits)
1961
- {
1962
- $bytes = $bits >> 3;
1963
- $min = str_repeat(chr(0), $bytes);
1964
- $max = str_repeat(chr(0xFF), $bytes);
1965
- $msb = $bits & 7;
1966
- if ($msb) {
1967
- $min = chr(1 << ($msb - 1)) . $min;
1968
- $max = chr((1 << $msb) - 1) . $max;
1969
- } else {
1970
- $min[0] = chr(0x80);
1971
- }
1972
-
1973
- return array(
1974
- 'min' => new Math_BigInteger($min, 256),
1975
- 'max' => new Math_BigInteger($max, 256)
1976
- );
1977
- }
1978
-
1979
- /**
1980
- * DER-decode the length
1981
- *
1982
- * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See
1983
- * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information.
1984
- *
1985
- * @access private
1986
- * @param string $string
1987
- * @return int
1988
- */
1989
- function _decodeLength(&$string)
1990
- {
1991
- $length = ord($this->_string_shift($string));
1992
- if ($length & 0x80) { // definite length, long form
1993
- $length&= 0x7F;
1994
- $temp = $this->_string_shift($string, $length);
1995
- list(, $length) = unpack('N', substr(str_pad($temp, 4, chr(0), STR_PAD_LEFT), -4));
1996
- }
1997
- return $length;
1998
- }
1999
-
2000
- /**
2001
- * DER-encode the length
2002
- *
2003
- * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See
2004
- * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information.
2005
- *
2006
- * @access private
2007
- * @param int $length
2008
- * @return string
2009
- */
2010
- function _encodeLength($length)
2011
- {
2012
- if ($length <= 0x7F) {
2013
- return chr($length);
2014
- }
2015
-
2016
- $temp = ltrim(pack('N', $length), chr(0));
2017
- return pack('Ca*', 0x80 | strlen($temp), $temp);
2018
- }
2019
-
2020
- /**
2021
- * String Shift
2022
- *
2023
- * Inspired by array_shift
2024
- *
2025
- * @param string $string
2026
- * @param int $index
2027
- * @return string
2028
- * @access private
2029
- */
2030
- function _string_shift(&$string, $index = 1)
2031
- {
2032
- $substr = substr($string, 0, $index);
2033
- $string = substr($string, $index);
2034
- return $substr;
2035
- }
2036
-
2037
- /**
2038
- * Determines the private key format
2039
- *
2040
- * @see self::createKey()
2041
- * @access public
2042
- * @param int $format
2043
- */
2044
- function setPrivateKeyFormat($format)
2045
- {
2046
- $this->privateKeyFormat = $format;
2047
- }
2048
-
2049
- /**
2050
- * Determines the public key format
2051
- *
2052
- * @see self::createKey()
2053
- * @access public
2054
- * @param int $format
2055
- */
2056
- function setPublicKeyFormat($format)
2057
- {
2058
- $this->publicKeyFormat = $format;
2059
- }
2060
-
2061
- /**
2062
- * Determines which hashing function should be used
2063
- *
2064
- * Used with signature production / verification and (if the encryption mode is CRYPT_RSA_ENCRYPTION_OAEP) encryption and
2065
- * decryption. If $hash isn't supported, sha1 is used.
2066
- *
2067
- * @access public
2068
- * @param string $hash
2069
- */
2070
- function setHash($hash)
2071
- {
2072
- // Crypt_Hash supports algorithms that PKCS#1 doesn't support. md5-96 and sha1-96, for example.
2073
- switch ($hash) {
2074
- case 'md2':
2075
- case 'md5':
2076
- case 'sha1':
2077
- case 'sha256':
2078
- case 'sha384':
2079
- case 'sha512':
2080
- $this->hash = new Crypt_Hash($hash);
2081
- $this->hashName = $hash;
2082
- break;
2083
- default:
2084
- $this->hash = new Crypt_Hash('sha1');
2085
- $this->hashName = 'sha1';
2086
- }
2087
- $this->hLen = $this->hash->getLength();
2088
- }
2089
-
2090
- /**
2091
- * Determines which hashing function should be used for the mask generation function
2092
- *
2093
- * The mask generation function is used by CRYPT_RSA_ENCRYPTION_OAEP and CRYPT_RSA_SIGNATURE_PSS and although it's
2094
- * best if Hash and MGFHash are set to the same thing this is not a requirement.
2095
- *
2096
- * @access public
2097
- * @param string $hash
2098
- */
2099
- function setMGFHash($hash)
2100
- {
2101
- // Crypt_Hash supports algorithms that PKCS#1 doesn't support. md5-96 and sha1-96, for example.
2102
- switch ($hash) {
2103
- case 'md2':
2104
- case 'md5':
2105
- case 'sha1':
2106
- case 'sha256':
2107
- case 'sha384':
2108
- case 'sha512':
2109
- $this->mgfHash = new Crypt_Hash($hash);
2110
- break;
2111
- default:
2112
- $this->mgfHash = new Crypt_Hash('sha1');
2113
- }
2114
- $this->mgfHLen = $this->mgfHash->getLength();
2115
- }
2116
-
2117
- /**
2118
- * Determines the salt length
2119
- *
2120
- * To quote from {@link http://tools.ietf.org/html/rfc3447#page-38 RFC3447#page-38}:
2121
- *
2122
- * Typical salt lengths in octets are hLen (the length of the output
2123
- * of the hash function Hash) and 0.
2124
- *
2125
- * @access public
2126
- * @param int $format
2127
- */
2128
- function setSaltLength($sLen)
2129
- {
2130
- $this->sLen = $sLen;
2131
- }
2132
-
2133
- /**
2134
- * Integer-to-Octet-String primitive
2135
- *
2136
- * See {@link http://tools.ietf.org/html/rfc3447#section-4.1 RFC3447#section-4.1}.
2137
- *
2138
- * @access private
2139
- * @param Math_BigInteger $x
2140
- * @param int $xLen
2141
- * @return string
2142
- */
2143
- function _i2osp($x, $xLen)
2144
- {
2145
- $x = $x->toBytes();
2146
- if (strlen($x) > $xLen) {
2147
- user_error('Integer too large');
2148
- return false;
2149
- }
2150
- return str_pad($x, $xLen, chr(0), STR_PAD_LEFT);
2151
- }
2152
-
2153
- /**
2154
- * Octet-String-to-Integer primitive
2155
- *
2156
- * See {@link http://tools.ietf.org/html/rfc3447#section-4.2 RFC3447#section-4.2}.
2157
- *
2158
- * @access private
2159
- * @param string $x
2160
- * @return Math_BigInteger
2161
- */
2162
- function _os2ip($x)
2163
- {
2164
- return new Math_BigInteger($x, 256);
2165
- }
2166
-
2167
- /**
2168
- * Exponentiate with or without Chinese Remainder Theorem
2169
- *
2170
- * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.1 RFC3447#section-5.1.2}.
2171
- *
2172
- * @access private
2173
- * @param Math_BigInteger $x
2174
- * @return Math_BigInteger
2175
- */
2176
- function _exponentiate($x)
2177
- {
2178
- switch (true) {
2179
- case empty($this->primes):
2180
- case $this->primes[1]->equals($this->zero):
2181
- case empty($this->coefficients):
2182
- case $this->coefficients[2]->equals($this->zero):
2183
- case empty($this->exponents):
2184
- case $this->exponents[1]->equals($this->zero):
2185
- return $x->modPow($this->exponent, $this->modulus);
2186
- }
2187
-
2188
- $num_primes = count($this->primes);
2189
-
2190
- if (defined('CRYPT_RSA_DISABLE_BLINDING')) {
2191
- $m_i = array(
2192
- 1 => $x->modPow($this->exponents[1], $this->primes[1]),
2193
- 2 => $x->modPow($this->exponents[2], $this->primes[2])
2194
- );
2195
- $h = $m_i[1]->subtract($m_i[2]);
2196
- $h = $h->multiply($this->coefficients[2]);
2197
- list(, $h) = $h->divide($this->primes[1]);
2198
- $m = $m_i[2]->add($h->multiply($this->primes[2]));
2199
-
2200
- $r = $this->primes[1];
2201
- for ($i = 3; $i <= $num_primes; $i++) {
2202
- $m_i = $x->modPow($this->exponents[$i], $this->primes[$i]);
2203
-
2204
- $r = $r->multiply($this->primes[$i - 1]);
2205
-
2206
- $h = $m_i->subtract($m);
2207
- $h = $h->multiply($this->coefficients[$i]);
2208
- list(, $h) = $h->divide($this->primes[$i]);
2209
-
2210
- $m = $m->add($r->multiply($h));
2211
- }
2212
- } else {
2213
- $smallest = $this->primes[1];
2214
- for ($i = 2; $i <= $num_primes; $i++) {
2215
- if ($smallest->compare($this->primes[$i]) > 0) {
2216
- $smallest = $this->primes[$i];
2217
- }
2218
- }
2219
-
2220
- $one = new Math_BigInteger(1);
2221
-
2222
- $r = $one->random($one, $smallest->subtract($one));
2223
-
2224
- $m_i = array(
2225
- 1 => $this->_blind($x, $r, 1),
2226
- 2 => $this->_blind($x, $r, 2)
2227
- );
2228
- $h = $m_i[1]->subtract($m_i[2]);
2229
- $h = $h->multiply($this->coefficients[2]);
2230
- list(, $h) = $h->divide($this->primes[1]);
2231
- $m = $m_i[2]->add($h->multiply($this->primes[2]));
2232
-
2233
- $r = $this->primes[1];
2234
- for ($i = 3; $i <= $num_primes; $i++) {
2235
- $m_i = $this->_blind($x, $r, $i);
2236
-
2237
- $r = $r->multiply($this->primes[$i - 1]);
2238
-
2239
- $h = $m_i->subtract($m);
2240
- $h = $h->multiply($this->coefficients[$i]);
2241
- list(, $h) = $h->divide($this->primes[$i]);
2242
-
2243
- $m = $m->add($r->multiply($h));
2244
- }
2245
- }
2246
-
2247
- return $m;
2248
- }
2249
-
2250
- /**
2251
- * Performs RSA Blinding
2252
- *
2253
- * Protects against timing attacks by employing RSA Blinding.
2254
- * Returns $x->modPow($this->exponents[$i], $this->primes[$i])
2255
- *
2256
- * @access private
2257
- * @param Math_BigInteger $x
2258
- * @param Math_BigInteger $r
2259
- * @param int $i
2260
- * @return Math_BigInteger
2261
- */
2262
- function _blind($x, $r, $i)
2263
- {
2264
- $x = $x->multiply($r->modPow($this->publicExponent, $this->primes[$i]));
2265
- $x = $x->modPow($this->exponents[$i], $this->primes[$i]);
2266
-
2267
- $r = $r->modInverse($this->primes[$i]);
2268
- $x = $x->multiply($r);
2269
- list(, $x) = $x->divide($this->primes[$i]);
2270
-
2271
- return $x;
2272
- }
2273
-
2274
- /**
2275
- * Performs blinded RSA equality testing
2276
- *
2277
- * Protects against a particular type of timing attack described.
2278
- *
2279
- * See {@link http://codahale.com/a-lesson-in-timing-attacks/ A Lesson In Timing Attacks (or, Don't use MessageDigest.isEquals)}
2280
- *
2281
- * Thanks for the heads up singpolyma!
2282
- *
2283
- * @access private
2284
- * @param string $x
2285
- * @param string $y
2286
- * @return bool
2287
- */
2288
- function _equals($x, $y)
2289
- {
2290
- if (strlen($x) != strlen($y)) {
2291
- return false;
2292
- }
2293
-
2294
- $result = 0;
2295
- for ($i = 0; $i < strlen($x); $i++) {
2296
- $result |= ord($x[$i]) ^ ord($y[$i]);
2297
- }
2298
-
2299
- return $result == 0;
2300
- }
2301
-
2302
- /**
2303
- * RSAEP
2304
- *
2305
- * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.1 RFC3447#section-5.1.1}.
2306
- *
2307
- * @access private
2308
- * @param Math_BigInteger $m
2309
- * @return Math_BigInteger
2310
- */
2311
- function _rsaep($m)
2312
- {
2313
- if ($m->compare($this->zero) < 0 || $m->compare($this->modulus) > 0) {
2314
- user_error('Message representative out of range');
2315
- return false;
2316
- }
2317
- return $this->_exponentiate($m);
2318
- }
2319
-
2320
- /**
2321
- * RSADP
2322
- *
2323
- * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.2 RFC3447#section-5.1.2}.
2324
- *
2325
- * @access private
2326
- * @param Math_BigInteger $c
2327
- * @return Math_BigInteger
2328
- */
2329
- function _rsadp($c)
2330
- {
2331
- if ($c->compare($this->zero) < 0 || $c->compare($this->modulus) > 0) {
2332
- user_error('Ciphertext representative out of range');
2333
- return false;
2334
- }
2335
- return $this->_exponentiate($c);
2336
- }
2337
-
2338
- /**
2339
- * RSASP1
2340
- *
2341
- * See {@link http://tools.ietf.org/html/rfc3447#section-5.2.1 RFC3447#section-5.2.1}.
2342
- *
2343
- * @access private
2344
- * @param Math_BigInteger $m
2345
- * @return Math_BigInteger
2346
- */
2347
- function _rsasp1($m)
2348
- {
2349
- if ($m->compare($this->zero) < 0 || $m->compare($this->modulus) > 0) {
2350
- user_error('Message representative out of range');
2351
- return false;
2352
- }
2353
- return $this->_exponentiate($m);
2354
- }
2355
-
2356
- /**
2357
- * RSAVP1
2358
- *
2359
- * See {@link http://tools.ietf.org/html/rfc3447#section-5.2.2 RFC3447#section-5.2.2}.
2360
- *
2361
- * @access private
2362
- * @param Math_BigInteger $s
2363
- * @return Math_BigInteger
2364
- */
2365
- function _rsavp1($s)
2366
- {
2367
- if ($s->compare($this->zero) < 0 || $s->compare($this->modulus) > 0) {
2368
- user_error('Signature representative out of range');
2369
- return false;
2370
- }
2371
- return $this->_exponentiate($s);
2372
- }
2373
-
2374
- /**
2375
- * MGF1
2376
- *
2377
- * See {@link http://tools.ietf.org/html/rfc3447#appendix-B.2.1 RFC3447#appendix-B.2.1}.
2378
- *
2379
- * @access private
2380
- * @param string $mgfSeed
2381
- * @param int $mgfLen
2382
- * @return string
2383
- */
2384
- function _mgf1($mgfSeed, $maskLen)
2385
- {
2386
- // if $maskLen would yield strings larger than 4GB, PKCS#1 suggests a "Mask too long" error be output.
2387
-
2388
- $t = '';
2389
- $count = ceil($maskLen / $this->mgfHLen);
2390
- for ($i = 0; $i < $count; $i++) {
2391
- $c = pack('N', $i);
2392
- $t.= $this->mgfHash->hash($mgfSeed . $c);
2393
- }
2394
-
2395
- return substr($t, 0, $maskLen);
2396
- }
2397
-
2398
- /**
2399
- * RSAES-OAEP-ENCRYPT
2400
- *
2401
- * See {@link http://tools.ietf.org/html/rfc3447#section-7.1.1 RFC3447#section-7.1.1} and
2402
- * {http://en.wikipedia.org/wiki/Optimal_Asymmetric_Encryption_Padding OAES}.
2403
- *
2404
- * @access private
2405
- * @param string $m
2406
- * @param string $l
2407
- * @return string
2408
- */
2409
- function _rsaes_oaep_encrypt($m, $l = '')
2410
- {
2411
- $mLen = strlen($m);
2412
-
2413
- // Length checking
2414
-
2415
- // if $l is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
2416
- // be output.
2417
-
2418
- if ($mLen > $this->k - 2 * $this->hLen - 2) {
2419
- user_error('Message too long');
2420
- return false;
2421
- }
2422
-
2423
- // EME-OAEP encoding
2424
-
2425
- $lHash = $this->hash->hash($l);
2426
- $ps = str_repeat(chr(0), $this->k - $mLen - 2 * $this->hLen - 2);
2427
- $db = $lHash . $ps . chr(1) . $m;
2428
- $seed = crypt_random_string($this->hLen);
2429
- $dbMask = $this->_mgf1($seed, $this->k - $this->hLen - 1);
2430
- $maskedDB = $db ^ $dbMask;
2431
- $seedMask = $this->_mgf1($maskedDB, $this->hLen);
2432
- $maskedSeed = $seed ^ $seedMask;
2433
- $em = chr(0) . $maskedSeed . $maskedDB;
2434
-
2435
- // RSA encryption
2436
-
2437
- $m = $this->_os2ip($em);
2438
- $c = $this->_rsaep($m);
2439
- $c = $this->_i2osp($c, $this->k);
2440
-
2441
- // Output the ciphertext C
2442
-
2443
- return $c;
2444
- }
2445
-
2446
- /**
2447
- * RSAES-OAEP-DECRYPT
2448
- *
2449
- * See {@link http://tools.ietf.org/html/rfc3447#section-7.1.2 RFC3447#section-7.1.2}. The fact that the error
2450
- * messages aren't distinguishable from one another hinders debugging, but, to quote from RFC3447#section-7.1.2:
2451
- *
2452
- * Note. Care must be taken to ensure that an opponent cannot
2453
- * distinguish the different error conditions in Step 3.g, whether by
2454
- * error message or timing, or, more generally, learn partial
2455
- * information about the encoded message EM. Otherwise an opponent may
2456
- * be able to obtain useful information about the decryption of the
2457
- * ciphertext C, leading to a chosen-ciphertext attack such as the one
2458
- * observed by Manger [36].
2459
- *
2460
- * As for $l... to quote from {@link http://tools.ietf.org/html/rfc3447#page-17 RFC3447#page-17}:
2461
- *
2462
- * Both the encryption and the decryption operations of RSAES-OAEP take
2463
- * the value of a label L as input. In this version of PKCS #1, L is
2464
- * the empty string; other uses of the label are outside the scope of
2465
- * this document.
2466
- *
2467
- * @access private
2468
- * @param string $c
2469
- * @param string $l
2470
- * @return string
2471
- */
2472
- function _rsaes_oaep_decrypt($c, $l = '')
2473
- {
2474
- // Length checking
2475
-
2476
- // if $l is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
2477
- // be output.
2478
-
2479
- if (strlen($c) != $this->k || $this->k < 2 * $this->hLen + 2) {
2480
- user_error('Decryption error');
2481
- return false;
2482
- }
2483
-
2484
- // RSA decryption
2485
-
2486
- $c = $this->_os2ip($c);
2487
- $m = $this->_rsadp($c);
2488
- if ($m === false) {
2489
- user_error('Decryption error');
2490
- return false;
2491
- }
2492
- $em = $this->_i2osp($m, $this->k);
2493
-
2494
- // EME-OAEP decoding
2495
-
2496
- $lHash = $this->hash->hash($l);
2497
- $y = ord($em[0]);
2498
- $maskedSeed = substr($em, 1, $this->hLen);
2499
- $maskedDB = substr($em, $this->hLen + 1);
2500
- $seedMask = $this->_mgf1($maskedDB, $this->hLen);
2501
- $seed = $maskedSeed ^ $seedMask;
2502
- $dbMask = $this->_mgf1($seed, $this->k - $this->hLen - 1);
2503
- $db = $maskedDB ^ $dbMask;
2504
- $lHash2 = substr($db, 0, $this->hLen);
2505
- $m = substr($db, $this->hLen);
2506
- if ($lHash != $lHash2) {
2507
- user_error('Decryption error');
2508
- return false;
2509
- }
2510
- $m = ltrim($m, chr(0));
2511
- if (ord($m[0]) != 1) {
2512
- user_error('Decryption error');
2513
- return false;
2514
- }
2515
-
2516
- // Output the message M
2517
-
2518
- return substr($m, 1);
2519
- }
2520
-
2521
- /**
2522
- * Raw Encryption / Decryption
2523
- *
2524
- * Doesn't use padding and is not recommended.
2525
- *
2526
- * @access private
2527
- * @param string $m
2528
- * @return string
2529
- */
2530
- function _raw_encrypt($m)
2531
- {
2532
- $temp = $this->_os2ip($m);
2533
- $temp = $this->_rsaep($temp);
2534
- return $this->_i2osp($temp, $this->k);
2535
- }
2536
-
2537
- /**
2538
- * RSAES-PKCS1-V1_5-ENCRYPT
2539
- *
2540
- * See {@link http://tools.ietf.org/html/rfc3447#section-7.2.1 RFC3447#section-7.2.1}.
2541
- *
2542
- * @access private
2543
- * @param string $m
2544
- * @return string
2545
- */
2546
- function _rsaes_pkcs1_v1_5_encrypt($m)
2547
- {
2548
- $mLen = strlen($m);
2549
-
2550
- // Length checking
2551
-
2552
- if ($mLen > $this->k - 11) {
2553
- user_error('Message too long');
2554
- return false;
2555
- }
2556
-
2557
- // EME-PKCS1-v1_5 encoding
2558
-
2559
- $psLen = $this->k - $mLen - 3;
2560
- $ps = '';
2561
- while (strlen($ps) != $psLen) {
2562
- $temp = crypt_random_string($psLen - strlen($ps));
2563
- $temp = str_replace("\x00", '', $temp);
2564
- $ps.= $temp;
2565
- }
2566
- $type = 2;
2567
- // see the comments of _rsaes_pkcs1_v1_5_decrypt() to understand why this is being done
2568
- if (defined('CRYPT_RSA_PKCS15_COMPAT') && (!isset($this->publicExponent) || $this->exponent !== $this->publicExponent)) {
2569
- $type = 1;
2570
- // "The padding string PS shall consist of k-3-||D|| octets. ... for block type 01, they shall have value FF"
2571
- $ps = str_repeat("\xFF", $psLen);
2572
- }
2573
- $em = chr(0) . chr($type) . $ps . chr(0) . $m;
2574
-
2575
- // RSA encryption
2576
- $m = $this->_os2ip($em);
2577
- $c = $this->_rsaep($m);
2578
- $c = $this->_i2osp($c, $this->k);
2579
-
2580
- // Output the ciphertext C
2581
-
2582
- return $c;
2583
- }
2584
-
2585
- /**
2586
- * RSAES-PKCS1-V1_5-DECRYPT
2587
- *
2588
- * See {@link http://tools.ietf.org/html/rfc3447#section-7.2.2 RFC3447#section-7.2.2}.
2589
- *
2590
- * For compatibility purposes, this function departs slightly from the description given in RFC3447.
2591
- * The reason being that RFC2313#section-8.1 (PKCS#1 v1.5) states that ciphertext's encrypted by the
2592
- * private key should have the second byte set to either 0 or 1 and that ciphertext's encrypted by the
2593
- * public key should have the second byte set to 2. In RFC3447 (PKCS#1 v2.1), the second byte is supposed
2594
- * to be 2 regardless of which key is used. For compatibility purposes, we'll just check to make sure the
2595
- * second byte is 2 or less. If it is, we'll accept the decrypted string as valid.
2596
- *
2597
- * As a consequence of this, a private key encrypted ciphertext produced with Crypt_RSA may not decrypt
2598
- * with a strictly PKCS#1 v1.5 compliant RSA implementation. Public key encrypted ciphertext's should but
2599
- * not private key encrypted ciphertext's.
2600
- *
2601
- * @access private
2602
- * @param string $c
2603
- * @return string
2604
- */
2605
- function _rsaes_pkcs1_v1_5_decrypt($c)
2606
- {
2607
- // Length checking
2608
-
2609
- if (strlen($c) != $this->k) { // or if k < 11
2610
- user_error('Decryption error');
2611
- return false;
2612
- }
2613
-
2614
- // RSA decryption
2615
-
2616
- $c = $this->_os2ip($c);
2617
- $m = $this->_rsadp($c);
2618
-
2619
- if ($m === false) {
2620
- user_error('Decryption error');
2621
- return false;
2622
- }
2623
- $em = $this->_i2osp($m, $this->k);
2624
-
2625
- // EME-PKCS1-v1_5 decoding
2626
-
2627
- if (ord($em[0]) != 0 || ord($em[1]) > 2) {
2628
- user_error('Decryption error');
2629
- return false;
2630
- }
2631
-
2632
- $ps = substr($em, 2, strpos($em, chr(0), 2) - 2);
2633
- $m = substr($em, strlen($ps) + 3);
2634
-
2635
- if (strlen($ps) < 8) {
2636
- user_error('Decryption error');
2637
- return false;
2638
- }
2639
-
2640
- // Output M
2641
-
2642
- return $m;
2643
- }
2644
-
2645
- /**
2646
- * EMSA-PSS-ENCODE
2647
- *
2648
- * See {@link http://tools.ietf.org/html/rfc3447#section-9.1.1 RFC3447#section-9.1.1}.
2649
- *
2650
- * @access private
2651
- * @param string $m
2652
- * @param int $emBits
2653
- */
2654
- function _emsa_pss_encode($m, $emBits)
2655
- {
2656
- // if $m is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
2657
- // be output.
2658
-
2659
- $emLen = ($emBits + 1) >> 3; // ie. ceil($emBits / 8)
2660
- $sLen = $this->sLen !== null ? $this->sLen : $this->hLen;
2661
-
2662
- $mHash = $this->hash->hash($m);
2663
- if ($emLen < $this->hLen + $sLen + 2) {
2664
- user_error('Encoding error');
2665
- return false;
2666
- }
2667
-
2668
- $salt = crypt_random_string($sLen);
2669
- $m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt;
2670
- $h = $this->hash->hash($m2);
2671
- $ps = str_repeat(chr(0), $emLen - $sLen - $this->hLen - 2);
2672
- $db = $ps . chr(1) . $salt;
2673
- $dbMask = $this->_mgf1($h, $emLen - $this->hLen - 1);
2674
- $maskedDB = $db ^ $dbMask;
2675
- $maskedDB[0] = ~chr(0xFF << ($emBits & 7)) & $maskedDB[0];
2676
- $em = $maskedDB . $h . chr(0xBC);
2677
-
2678
- return $em;
2679
- }
2680
-
2681
- /**
2682
- * EMSA-PSS-VERIFY
2683
- *
2684
- * See {@link http://tools.ietf.org/html/rfc3447#section-9.1.2 RFC3447#section-9.1.2}.
2685
- *
2686
- * @access private
2687
- * @param string $m
2688
- * @param string $em
2689
- * @param int $emBits
2690
- * @return string
2691
- */
2692
- function _emsa_pss_verify($m, $em, $emBits)
2693
- {
2694
- // if $m is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
2695
- // be output.
2696
-
2697
- $emLen = ($emBits + 1) >> 3; // ie. ceil($emBits / 8);
2698
- $sLen = $this->sLen !== null ? $this->sLen : $this->hLen;
2699
-
2700
- $mHash = $this->hash->hash($m);
2701
- if ($emLen < $this->hLen + $sLen + 2) {
2702
- return false;
2703
- }
2704
-
2705
- if ($em[strlen($em) - 1] != chr(0xBC)) {
2706
- return false;
2707
- }
2708
-
2709
- $maskedDB = substr($em, 0, -$this->hLen - 1);
2710
- $h = substr($em, -$this->hLen - 1, $this->hLen);
2711
- $temp = chr(0xFF << ($emBits & 7));
2712
- if ((~$maskedDB[0] & $temp) != $temp) {
2713
- return false;
2714
- }
2715
- $dbMask = $this->_mgf1($h, $emLen - $this->hLen - 1);
2716
- $db = $maskedDB ^ $dbMask;
2717
- $db[0] = ~chr(0xFF << ($emBits & 7)) & $db[0];
2718
- $temp = $emLen - $this->hLen - $sLen - 2;
2719
- if (substr($db, 0, $temp) != str_repeat(chr(0), $temp) || ord($db[$temp]) != 1) {
2720
- return false;
2721
- }
2722
- $salt = substr($db, $temp + 1); // should be $sLen long
2723
- $m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt;
2724
- $h2 = $this->hash->hash($m2);
2725
- return $this->_equals($h, $h2);
2726
- }
2727
-
2728
- /**
2729
- * RSASSA-PSS-SIGN
2730
- *
2731
- * See {@link http://tools.ietf.org/html/rfc3447#section-8.1.1 RFC3447#section-8.1.1}.
2732
- *
2733
- * @access private
2734
- * @param string $m
2735
- * @return string
2736
- */
2737
- function _rsassa_pss_sign($m)
2738
- {
2739
- // EMSA-PSS encoding
2740
-
2741
- $em = $this->_emsa_pss_encode($m, 8 * $this->k - 1);
2742
-
2743
- // RSA signature
2744
-
2745
- $m = $this->_os2ip($em);
2746
- $s = $this->_rsasp1($m);
2747
- $s = $this->_i2osp($s, $this->k);
2748
-
2749
- // Output the signature S
2750
-
2751
- return $s;
2752
- }
2753
-
2754
- /**
2755
- * RSASSA-PSS-VERIFY
2756
- *
2757
- * See {@link http://tools.ietf.org/html/rfc3447#section-8.1.2 RFC3447#section-8.1.2}.
2758
- *
2759
- * @access private
2760
- * @param string $m
2761
- * @param string $s
2762
- * @return string
2763
- */
2764
- function _rsassa_pss_verify($m, $s)
2765
- {
2766
- // Length checking
2767
-
2768
- if (strlen($s) != $this->k) {
2769
- user_error('Invalid signature');
2770
- return false;
2771
- }
2772
-
2773
- // RSA verification
2774
-
2775
- $modBits = 8 * $this->k;
2776
-
2777
- $s2 = $this->_os2ip($s);
2778
- $m2 = $this->_rsavp1($s2);
2779
- if ($m2 === false) {
2780
- user_error('Invalid signature');
2781
- return false;
2782
- }
2783
- $em = $this->_i2osp($m2, $modBits >> 3);
2784
- if ($em === false) {
2785
- user_error('Invalid signature');
2786
- return false;
2787
- }
2788
-
2789
- // EMSA-PSS verification
2790
-
2791
- return $this->_emsa_pss_verify($m, $em, $modBits - 1);
2792
- }
2793
-
2794
- /**
2795
- * EMSA-PKCS1-V1_5-ENCODE
2796
- *
2797
- * See {@link http://tools.ietf.org/html/rfc3447#section-9.2 RFC3447#section-9.2}.
2798
- *
2799
- * @access private
2800
- * @param string $m
2801
- * @param int $emLen
2802
- * @return string
2803
- */
2804
- function _emsa_pkcs1_v1_5_encode($m, $emLen)
2805
- {
2806
- $h = $this->hash->hash($m);
2807
- if ($h === false) {
2808
- return false;
2809
- }
2810
-
2811
- // see http://tools.ietf.org/html/rfc3447#page-43
2812
- switch ($this->hashName) {
2813
- case 'md2':
2814
- $t = pack('H*', '3020300c06082a864886f70d020205000410');
2815
- break;
2816
- case 'md5':
2817
- $t = pack('H*', '3020300c06082a864886f70d020505000410');
2818
- break;
2819
- case 'sha1':
2820
- $t = pack('H*', '3021300906052b0e03021a05000414');
2821
- break;
2822
- case 'sha256':
2823
- $t = pack('H*', '3031300d060960864801650304020105000420');
2824
- break;
2825
- case 'sha384':
2826
- $t = pack('H*', '3041300d060960864801650304020205000430');
2827
- break;
2828
- case 'sha512':
2829
- $t = pack('H*', '3051300d060960864801650304020305000440');
2830
- }
2831
- $t.= $h;
2832
- $tLen = strlen($t);
2833
-
2834
- if ($emLen < $tLen + 11) {
2835
- user_error('Intended encoded message length too short');
2836
- return false;
2837
- }
2838
-
2839
- $ps = str_repeat(chr(0xFF), $emLen - $tLen - 3);
2840
-
2841
- $em = "\0\1$ps\0$t";
2842
-
2843
- return $em;
2844
- }
2845
-
2846
- /**
2847
- * RSASSA-PKCS1-V1_5-SIGN
2848
- *
2849
- * See {@link http://tools.ietf.org/html/rfc3447#section-8.2.1 RFC3447#section-8.2.1}.
2850
- *
2851
- * @access private
2852
- * @param string $m
2853
- * @return string
2854
- */
2855
- function _rsassa_pkcs1_v1_5_sign($m)
2856
- {
2857
- // EMSA-PKCS1-v1_5 encoding
2858
-
2859
- $em = $this->_emsa_pkcs1_v1_5_encode($m, $this->k);
2860
- if ($em === false) {
2861
- user_error('RSA modulus too short');
2862
- return false;
2863
- }
2864
-
2865
- // RSA signature
2866
-
2867
- $m = $this->_os2ip($em);
2868
- $s = $this->_rsasp1($m);
2869
- $s = $this->_i2osp($s, $this->k);
2870
-
2871
- // Output the signature S
2872
-
2873
- return $s;
2874
- }
2875
-
2876
- /**
2877
- * RSASSA-PKCS1-V1_5-VERIFY
2878
- *
2879
- * See {@link http://tools.ietf.org/html/rfc3447#section-8.2.2 RFC3447#section-8.2.2}.
2880
- *
2881
- * @access private
2882
- * @param string $m
2883
- * @return string
2884
- */
2885
- function _rsassa_pkcs1_v1_5_verify($m, $s)
2886
- {
2887
- // Length checking
2888
-
2889
- if (strlen($s) != $this->k) {
2890
- user_error('Invalid signature');
2891
- return false;
2892
- }
2893
-
2894
- // RSA verification
2895
-
2896
- $s = $this->_os2ip($s);
2897
- $m2 = $this->_rsavp1($s);
2898
- if ($m2 === false) {
2899
- user_error('Invalid signature');
2900
- return false;
2901
- }
2902
- $em = $this->_i2osp($m2, $this->k);
2903
- if ($em === false) {
2904
- user_error('Invalid signature');
2905
- return false;
2906
- }
2907
-
2908
- // EMSA-PKCS1-v1_5 encoding
2909
-
2910
- $em2 = $this->_emsa_pkcs1_v1_5_encode($m, $this->k);
2911
- if ($em2 === false) {
2912
- user_error('RSA modulus too short');
2913
- return false;
2914
- }
2915
-
2916
- // Compare
2917
- return $this->_equals($em, $em2);
2918
- }
2919
-
2920
- /**
2921
- * Set Encryption Mode
2922
- *
2923
- * Valid values include CRYPT_RSA_ENCRYPTION_OAEP and CRYPT_RSA_ENCRYPTION_PKCS1.
2924
- *
2925
- * @access public
2926
- * @param int $mode
2927
- */
2928
- function setEncryptionMode($mode)
2929
- {
2930
- $this->encryptionMode = $mode;
2931
- }
2932
-
2933
- /**
2934
- * Set Signature Mode
2935
- *
2936
- * Valid values include CRYPT_RSA_SIGNATURE_PSS and CRYPT_RSA_SIGNATURE_PKCS1
2937
- *
2938
- * @access public
2939
- * @param int $mode
2940
- */
2941
- function setSignatureMode($mode)
2942
- {
2943
- $this->signatureMode = $mode;
2944
- }
2945
-
2946
- /**
2947
- * Set public key comment.
2948
- *
2949
- * @access public
2950
- * @param string $comment
2951
- */
2952
- function setComment($comment)
2953
- {
2954
- $this->comment = $comment;
2955
- }
2956
-
2957
- /**
2958
- * Get public key comment.
2959
- *
2960
- * @access public
2961
- * @return string
2962
- */
2963
- function getComment()
2964
- {
2965
- return $this->comment;
2966
- }
2967
-
2968
- /**
2969
- * Encryption
2970
- *
2971
- * Both CRYPT_RSA_ENCRYPTION_OAEP and CRYPT_RSA_ENCRYPTION_PKCS1 both place limits on how long $plaintext can be.
2972
- * If $plaintext exceeds those limits it will be broken up so that it does and the resultant ciphertext's will
2973
- * be concatenated together.
2974
- *
2975
- * @see self::decrypt()
2976
- * @access public
2977
- * @param string $plaintext
2978
- * @return string
2979
- */
2980
- function encrypt($plaintext)
2981
- {
2982
- switch ($this->encryptionMode) {
2983
- case CRYPT_RSA_ENCRYPTION_NONE:
2984
- $plaintext = str_split($plaintext, $this->k);
2985
- $ciphertext = '';
2986
- foreach ($plaintext as $m) {
2987
- $ciphertext.= $this->_raw_encrypt($m);
2988
- }
2989
- return $ciphertext;
2990
- case CRYPT_RSA_ENCRYPTION_PKCS1:
2991
- $length = $this->k - 11;
2992
- if ($length <= 0) {
2993
- return false;
2994
- }
2995
-
2996
- $plaintext = str_split($plaintext, $length);
2997
- $ciphertext = '';
2998
- foreach ($plaintext as $m) {
2999
- $ciphertext.= $this->_rsaes_pkcs1_v1_5_encrypt($m);
3000
- }
3001
- return $ciphertext;
3002
- //case CRYPT_RSA_ENCRYPTION_OAEP:
3003
- default:
3004
- $length = $this->k - 2 * $this->hLen - 2;
3005
- if ($length <= 0) {
3006
- return false;
3007
- }
3008
-
3009
- $plaintext = str_split($plaintext, $length);
3010
- $ciphertext = '';
3011
- foreach ($plaintext as $m) {
3012
- $ciphertext.= $this->_rsaes_oaep_encrypt($m);
3013
- }
3014
- return $ciphertext;
3015
- }
3016
- }
3017
-
3018
- /**
3019
- * Decryption
3020
- *
3021
- * @see self::encrypt()
3022
- * @access public
3023
- * @param string $plaintext
3024
- * @return string
3025
- */
3026
- function decrypt($ciphertext)
3027
- {
3028
- if ($this->k <= 0) {
3029
- return false;
3030
- }
3031
-
3032
- $ciphertext = str_split($ciphertext, $this->k);
3033
- $ciphertext[count($ciphertext) - 1] = str_pad($ciphertext[count($ciphertext) - 1], $this->k, chr(0), STR_PAD_LEFT);
3034
-
3035
- $plaintext = '';
3036
-
3037
- switch ($this->encryptionMode) {
3038
- case CRYPT_RSA_ENCRYPTION_NONE:
3039
- $decrypt = '_raw_encrypt';
3040
- break;
3041
- case CRYPT_RSA_ENCRYPTION_PKCS1:
3042
- $decrypt = '_rsaes_pkcs1_v1_5_decrypt';
3043
- break;
3044
- //case CRYPT_RSA_ENCRYPTION_OAEP:
3045
- default:
3046
- $decrypt = '_rsaes_oaep_decrypt';
3047
- }
3048
-
3049
- foreach ($ciphertext as $c) {
3050
- $temp = $this->$decrypt($c);
3051
- if ($temp === false) {
3052
- return false;
3053
- }
3054
- $plaintext.= $temp;
3055
- }
3056
-
3057
- return $plaintext;
3058
- }
3059
-
3060
- /**
3061
- * Create a signature
3062
- *
3063
- * @see self::verify()
3064
- * @access public
3065
- * @param string $message
3066
- * @return string
3067
- */
3068
- function sign($message)
3069
- {
3070
- if (empty($this->modulus) || empty($this->exponent)) {
3071
- return false;
3072
- }
3073
-
3074
- switch ($this->signatureMode) {
3075
- case CRYPT_RSA_SIGNATURE_PKCS1:
3076
- return $this->_rsassa_pkcs1_v1_5_sign($message);
3077
- //case CRYPT_RSA_SIGNATURE_PSS:
3078
- default:
3079
- return $this->_rsassa_pss_sign($message);
3080
- }
3081
- }
3082
-
3083
- /**
3084
- * Verifies a signature
3085
- *
3086
- * @see self::sign()
3087
- * @access public
3088
- * @param string $message
3089
- * @param string $signature
3090
- * @return bool
3091
- */
3092
- function verify($message, $signature)
3093
- {
3094
- if (empty($this->modulus) || empty($this->exponent)) {
3095
- return false;
3096
- }
3097
-
3098
- switch ($this->signatureMode) {
3099
- case CRYPT_RSA_SIGNATURE_PKCS1:
3100
- return $this->_rsassa_pkcs1_v1_5_verify($message, $signature);
3101
- //case CRYPT_RSA_SIGNATURE_PSS:
3102
- default:
3103
- return $this->_rsassa_pss_verify($message, $signature);
3104
- }
3105
- }
3106
-
3107
- /**
3108
- * Extract raw BER from Base64 encoding
3109
- *
3110
- * @access private
3111
- * @param string $str
3112
- * @return string
3113
- */
3114
- function _extractBER($str)
3115
- {
3116
- /* X.509 certs are assumed to be base64 encoded but sometimes they'll have additional things in them
3117
- * above and beyond the ceritificate.
3118
- * ie. some may have the following preceding the -----BEGIN CERTIFICATE----- line:
3119
- *
3120
- * Bag Attributes
3121
- * localKeyID: 01 00 00 00
3122
- * subject=/O=organization/OU=org unit/CN=common name
3123
- * issuer=/O=organization/CN=common name
3124
- */
3125
- $temp = preg_replace('#.*?^-+[^-]+-+[\r\n ]*$#ms', '', $str, 1);
3126
- // remove the -----BEGIN CERTIFICATE----- and -----END CERTIFICATE----- stuff
3127
- $temp = preg_replace('#-+[^-]+-+#', '', $temp);
3128
- // remove new lines
3129
- $temp = str_replace(array("\r", "\n", ' '), '', $temp);
3130
- $temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? base64_decode($temp) : false;
3131
- return $temp != false ? $temp : $str;
3132
- }
3133
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/phpseclib/Crypt/Random.php DELETED
@@ -1,334 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Random Number Generator
5
- *
6
- * The idea behind this function is that it can be easily replaced with your own crypt_random_string()
7
- * function. eg. maybe you have a better source of entropy for creating the initial states or whatever.
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/Random.php';
15
- *
16
- * echo bin2hex(crypt_random_string(8));
17
- * ?>
18
- * </code>
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 Crypt
39
- * @package Crypt_Random
40
- * @author Jim Wigginton <terrafrost@php.net>
41
- * @copyright 2007 Jim Wigginton
42
- * @license http://www.opensource.org/licenses/mit-license.html MIT License
43
- * @link http://phpseclib.sourceforge.net
44
- */
45
-
46
- // laravel is a PHP framework that utilizes phpseclib. laravel workbenches may, independently,
47
- // have phpseclib as a requirement as well. if you're developing such a program you may encounter
48
- // a "Cannot redeclare crypt_random_string()" error.
49
- if (!function_exists('crypt_random_string')) {
50
- /**
51
- * "Is Windows" test
52
- *
53
- * @access private
54
- */
55
- define('CRYPT_RANDOM_IS_WINDOWS', strtoupper(substr(PHP_OS, 0, 3)) === 'WIN');
56
-
57
- /**
58
- * Generate a random string.
59
- *
60
- * Although microoptimizations are generally discouraged as they impair readability this function is ripe with
61
- * microoptimizations because this function has the potential of being called a huge number of times.
62
- * eg. for RSA key generation.
63
- *
64
- * @param int $length
65
- * @return string
66
- * @access public
67
- */
68
- function crypt_random_string($length)
69
- {
70
- if (CRYPT_RANDOM_IS_WINDOWS) {
71
- // method 1. prior to PHP 5.3, mcrypt_create_iv() would call rand() on windows
72
- if (extension_loaded('mcrypt') && version_compare(PHP_VERSION, '5.3.0', '>=')) {
73
- return mcrypt_create_iv($length);
74
- }
75
- // method 2. openssl_random_pseudo_bytes was introduced in PHP 5.3.0 but prior to PHP 5.3.4 there was,
76
- // to quote <http://php.net/ChangeLog-5.php#5.3.4>, "possible blocking behavior". as of 5.3.4
77
- // openssl_random_pseudo_bytes and mcrypt_create_iv do the exact same thing on Windows. ie. they both
78
- // call php_win32_get_random_bytes():
79
- //
80
- // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/openssl/openssl.c#L5008
81
- // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/mcrypt/mcrypt.c#L1392
82
- //
83
- // php_win32_get_random_bytes() is defined thusly:
84
- //
85
- // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/win32/winutil.c#L80
86
- //
87
- // we're calling it, all the same, in the off chance that the mcrypt extension is not available
88
- if (extension_loaded('openssl') && version_compare(PHP_VERSION, '5.3.4', '>=')) {
89
- return openssl_random_pseudo_bytes($length);
90
- }
91
- } else {
92
- // method 1. the fastest
93
- if (extension_loaded('openssl') && version_compare(PHP_VERSION, '5.3.0', '>=')) {
94
- return openssl_random_pseudo_bytes($length);
95
- }
96
- // method 2
97
- static $fp = true;
98
- if ($fp === true) {
99
- // warning's will be output unles the error suppression operator is used. errors such as
100
- // "open_basedir restriction in effect", "Permission denied", "No such file or directory", etc.
101
- $fp = @fopen('/dev/urandom', 'rb');
102
- }
103
- if ($fp !== true && $fp !== false) { // surprisingly faster than !is_bool() or is_resource()
104
- return fread($fp, $length);
105
- }
106
- // method 3. pretty much does the same thing as method 2 per the following url:
107
- // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/mcrypt/mcrypt.c#L1391
108
- // surprisingly slower than method 2. maybe that's because mcrypt_create_iv does a bunch of error checking that we're
109
- // not doing. regardless, this'll only be called if this PHP script couldn't open /dev/urandom due to open_basedir
110
- // restrictions or some such
111
- if (extension_loaded('mcrypt')) {
112
- return mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
113
- }
114
- }
115
- // at this point we have no choice but to use a pure-PHP CSPRNG
116
-
117
- // cascade entropy across multiple PHP instances by fixing the session and collecting all
118
- // environmental variables, including the previous session data and the current session
119
- // data.
120
- //
121
- // mt_rand seeds itself by looking at the PID and the time, both of which are (relatively)
122
- // easy to guess at. linux uses mouse clicks, keyboard timings, etc, as entropy sources, but
123
- // PHP isn't low level to be able to use those as sources and on a web server there's not likely
124
- // going to be a ton of keyboard or mouse action. web servers do have one thing that we can use
125
- // however, a ton of people visiting the website. obviously you don't want to base your seeding
126
- // soley on parameters a potential attacker sends but (1) not everything in $_SERVER is controlled
127
- // by the user and (2) this isn't just looking at the data sent by the current user - it's based
128
- // on the data sent by all users. one user requests the page and a hash of their info is saved.
129
- // another user visits the page and the serialization of their data is utilized along with the
130
- // server envirnment stuff and a hash of the previous http request data (which itself utilizes
131
- // a hash of the session data before that). certainly an attacker should be assumed to have
132
- // full control over his own http requests. he, however, is not going to have control over
133
- // everyone's http requests.
134
- static $crypto = false, $v;
135
- if ($crypto === false) {
136
- // save old session data
137
- $old_session_id = session_id();
138
- $old_use_cookies = ini_get('session.use_cookies');
139
- $old_session_cache_limiter = session_cache_limiter();
140
- $_OLD_SESSION = isset($_SESSION) ? $_SESSION : false;
141
- if ($old_session_id != '') {
142
- session_write_close();
143
- }
144
-
145
- session_id(1);
146
- ini_set('session.use_cookies', 0);
147
- session_cache_limiter('');
148
- session_start();
149
-
150
- $v = $seed = $_SESSION['seed'] = pack('H*', sha1(
151
- (isset($_SERVER) ? phpseclib_safe_serialize($_SERVER) : '') .
152
- (isset($_POST) ? phpseclib_safe_serialize($_POST) : '') .
153
- (isset($_GET) ? phpseclib_safe_serialize($_GET) : '') .
154
- (isset($_COOKIE) ? phpseclib_safe_serialize($_COOKIE) : '') .
155
- phpseclib_safe_serialize($GLOBALS) .
156
- phpseclib_safe_serialize($_SESSION) .
157
- phpseclib_safe_serialize($_OLD_SESSION)
158
- ));
159
- if (!isset($_SESSION['count'])) {
160
- $_SESSION['count'] = 0;
161
- }
162
- $_SESSION['count']++;
163
-
164
- session_write_close();
165
-
166
- // restore old session data
167
- if ($old_session_id != '') {
168
- session_id($old_session_id);
169
- session_start();
170
- ini_set('session.use_cookies', $old_use_cookies);
171
- session_cache_limiter($old_session_cache_limiter);
172
- } else {
173
- if ($_OLD_SESSION !== false) {
174
- $_SESSION = $_OLD_SESSION;
175
- unset($_OLD_SESSION);
176
- } else {
177
- unset($_SESSION);
178
- }
179
- }
180
-
181
- // in SSH2 a shared secret and an exchange hash are generated through the key exchange process.
182
- // 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.
183
- // if the hash doesn't produce enough a key or an IV that's long enough concat successive hashes of the
184
- // original hash and the current hash. we'll be emulating that. for more info see the following URL:
185
- //
186
- // http://tools.ietf.org/html/rfc4253#section-7.2
187
- //
188
- // see the is_string($crypto) part for an example of how to expand the keys
189
- $key = pack('H*', sha1($seed . 'A'));
190
- $iv = pack('H*', sha1($seed . 'C'));
191
-
192
- // ciphers are used as per the nist.gov link below. also, see this link:
193
- //
194
- // http://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator#Designs_based_on_cryptographic_primitives
195
- switch (true) {
196
- case phpseclib_resolve_include_path('Crypt/AES.php'):
197
- if (!class_exists('Crypt_AES')) {
198
- include_once 'AES.php';
199
- }
200
- $crypto = new Crypt_AES(CRYPT_AES_MODE_CTR);
201
- break;
202
- case phpseclib_resolve_include_path('Crypt/Twofish.php'):
203
- if (!class_exists('Crypt_Twofish')) {
204
- include_once 'Twofish.php';
205
- }
206
- $crypto = new Crypt_Twofish(CRYPT_TWOFISH_MODE_CTR);
207
- break;
208
- case phpseclib_resolve_include_path('Crypt/Blowfish.php'):
209
- if (!class_exists('Crypt_Blowfish')) {
210
- include_once 'Blowfish.php';
211
- }
212
- $crypto = new Crypt_Blowfish(CRYPT_BLOWFISH_MODE_CTR);
213
- break;
214
- case phpseclib_resolve_include_path('Crypt/TripleDES.php'):
215
- if (!class_exists('Crypt_TripleDES')) {
216
- include_once 'TripleDES.php';
217
- }
218
- $crypto = new Crypt_TripleDES(CRYPT_DES_MODE_CTR);
219
- break;
220
- case phpseclib_resolve_include_path('Crypt/DES.php'):
221
- if (!class_exists('Crypt_DES')) {
222
- include_once 'DES.php';
223
- }
224
- $crypto = new Crypt_DES(CRYPT_DES_MODE_CTR);
225
- break;
226
- case phpseclib_resolve_include_path('Crypt/RC4.php'):
227
- if (!class_exists('Crypt_RC4')) {
228
- include_once 'RC4.php';
229
- }
230
- $crypto = new Crypt_RC4();
231
- break;
232
- default:
233
- user_error('crypt_random_string requires at least one symmetric cipher be loaded');
234
- return false;
235
- }
236
-
237
- $crypto->setKey($key);
238
- $crypto->setIV($iv);
239
- $crypto->enableContinuousBuffer();
240
- }
241
-
242
- //return $crypto->encrypt(str_repeat("\0", $length));
243
-
244
- // the following is based off of ANSI X9.31:
245
- //
246
- // http://csrc.nist.gov/groups/STM/cavp/documents/rng/931rngext.pdf
247
- //
248
- // OpenSSL uses that same standard for it's random numbers:
249
- //
250
- // http://www.opensource.apple.com/source/OpenSSL/OpenSSL-38/openssl/fips-1.0/rand/fips_rand.c
251
- // (do a search for "ANS X9.31 A.2.4")
252
- $result = '';
253
- while (strlen($result) < $length) {
254
- $i = $crypto->encrypt(microtime()); // strlen(microtime()) == 21
255
- $r = $crypto->encrypt($i ^ $v); // strlen($v) == 20
256
- $v = $crypto->encrypt($r ^ $i); // strlen($r) == 20
257
- $result.= $r;
258
- }
259
- return substr($result, 0, $length);
260
- }
261
- }
262
-
263
- if (!function_exists('phpseclib_safe_serialize')) {
264
- /**
265
- * Safely serialize variables
266
- *
267
- * If a class has a private __sleep() method it'll give a fatal error on PHP 5.2 and earlier.
268
- * PHP 5.3 will emit a warning.
269
- *
270
- * @param mixed $arr
271
- * @access public
272
- */
273
- function phpseclib_safe_serialize(&$arr)
274
- {
275
- if (is_object($arr)) {
276
- return '';
277
- }
278
- if (!is_array($arr)) {
279
- return serialize($arr);
280
- }
281
- // prevent circular array recursion
282
- if (isset($arr['__phpseclib_marker'])) {
283
- return '';
284
- }
285
- $safearr = array();
286
- $arr['__phpseclib_marker'] = true;
287
- foreach (array_keys($arr) as $key) {
288
- // do not recurse on the '__phpseclib_marker' key itself, for smaller memory usage
289
- if ($key !== '__phpseclib_marker') {
290
- $safearr[$key] = phpseclib_safe_serialize($arr[$key]);
291
- }
292
- }
293
- unset($arr['__phpseclib_marker']);
294
- return serialize($safearr);
295
- }
296
- }
297
-
298
- if (!function_exists('phpseclib_resolve_include_path')) {
299
- /**
300
- * Resolve filename against the include path.
301
- *
302
- * Wrapper around stream_resolve_include_path() (which was introduced in
303
- * PHP 5.3.2) with fallback implementation for earlier PHP versions.
304
- *
305
- * @param string $filename
306
- * @return string|false
307
- * @access public
308
- */
309
- function phpseclib_resolve_include_path($filename)
310
- {
311
- if (function_exists('stream_resolve_include_path')) {
312
- return stream_resolve_include_path($filename);
313
- }
314
-
315
- // handle non-relative paths
316
- if (file_exists($filename)) {
317
- return realpath($filename);
318
- }
319
-
320
- $paths = PATH_SEPARATOR == ':' ?
321
- preg_split('#(?<!phar):#', get_include_path()) :
322
- explode(PATH_SEPARATOR, get_include_path());
323
- foreach ($paths as $prefix) {
324
- // path's specified in include_path don't always end in /
325
- $ds = substr($prefix, -1) == DIRECTORY_SEPARATOR ? '' : DIRECTORY_SEPARATOR;
326
- $file = $prefix . $ds . $filename;
327
- if (file_exists($file)) {
328
- return realpath($file);
329
- }
330
- }
331
-
332
- return false;
333
- }
334
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/phpseclib/Crypt/Rijndael.php DELETED
@@ -1,1050 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Pure-PHP implementation of Rijndael.
5
- *
6
- * Uses mcrypt, if available/possible, and an internal implementation, otherwise.
7
- *
8
- * PHP versions 4 and 5
9
- *
10
- * If {@link self::setBlockLength() setBlockLength()} isn't called, it'll be assumed to be 128 bits. If
11
- * {@link self::setKeyLength() setKeyLength()} isn't called, it'll be calculated from
12
- * {@link self::setKey() setKey()}. ie. if the key is 128-bits, the key length will be 128-bits. If it's
13
- * 136-bits it'll be null-padded to 192-bits and 192 bits will be the key length until
14
- * {@link self::setKey() setKey()} is called, again, at which point, it'll be recalculated.
15
- *
16
- * Not all Rijndael implementations may support 160-bits or 224-bits as the block length / key length. mcrypt, for example,
17
- * does not. AES, itself, only supports block lengths of 128 and key lengths of 128, 192, and 256.
18
- * {@link http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=10 Rijndael-ammended.pdf#page=10} defines the
19
- * algorithm for block lengths of 192 and 256 but not for block lengths / key lengths of 160 and 224. Indeed, 160 and 224
20
- * are first defined as valid key / block lengths in
21
- * {@link http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=44 Rijndael-ammended.pdf#page=44}:
22
- * Extensions: Other block and Cipher Key lengths.
23
- * Note: Use of 160/224-bit Keys must be explicitly set by setKeyLength(160) respectively setKeyLength(224).
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 2008 Jim Wigginton
69
- * @license http://www.opensource.org/licenses/mit-license.html MIT License
70
- * @link http://phpseclib.sourceforge.net
71
- */
72
-
73
- /**
74
- * Include Crypt_Base
75
- *
76
- * Base cipher class
77
- */
78
- if (!class_exists('Crypt_Base')) {
79
- include_once 'Base.php';
80
- }
81
-
82
- /**#@+
83
- * @access public
84
- * @see self::encrypt()
85
- * @see self::decrypt()
86
- */
87
- /**
88
- * Encrypt / decrypt using the Counter mode.
89
- *
90
- * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
91
- *
92
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
93
- */
94
- define('CRYPT_RIJNDAEL_MODE_CTR', CRYPT_MODE_CTR);
95
- /**
96
- * Encrypt / decrypt using the Electronic Code Book mode.
97
- *
98
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
99
- */
100
- define('CRYPT_RIJNDAEL_MODE_ECB', CRYPT_MODE_ECB);
101
- /**
102
- * Encrypt / decrypt using the Code Book Chaining mode.
103
- *
104
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
105
- */
106
- define('CRYPT_RIJNDAEL_MODE_CBC', CRYPT_MODE_CBC);
107
- /**
108
- * Encrypt / decrypt using the Cipher Feedback mode.
109
- *
110
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
111
- */
112
- define('CRYPT_RIJNDAEL_MODE_CFB', CRYPT_MODE_CFB);
113
- /**
114
- * Encrypt / decrypt using the Cipher Feedback mode.
115
- *
116
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
117
- */
118
- define('CRYPT_RIJNDAEL_MODE_OFB', CRYPT_MODE_OFB);
119
- /**#@-*/
120
-
121
- /**
122
- * Pure-PHP implementation of Rijndael.
123
- *
124
- * @package Crypt_Rijndael
125
- * @author Jim Wigginton <terrafrost@php.net>
126
- * @access public
127
- */
128
- class Crypt_Rijndael extends Crypt_Base
129
- {
130
- /**
131
- * The namespace used by the cipher for its constants.
132
- *
133
- * @see Crypt_Base::const_namespace
134
- * @var string
135
- * @access private
136
- */
137
- var $const_namespace = 'RIJNDAEL';
138
-
139
- /**
140
- * The mcrypt specific name of the cipher
141
- *
142
- * Mcrypt is useable for 128/192/256-bit $block_size/$key_length. For 160/224 not.
143
- * Crypt_Rijndael determines automatically whether mcrypt is useable
144
- * or not for the current $block_size/$key_length.
145
- * In case of, $cipher_name_mcrypt will be set dynamically at run time accordingly.
146
- *
147
- * @see Crypt_Base::cipher_name_mcrypt
148
- * @see Crypt_Base::engine
149
- * @see self::isValidEngine()
150
- * @var string
151
- * @access private
152
- */
153
- var $cipher_name_mcrypt = 'rijndael-128';
154
-
155
- /**
156
- * The default salt used by setPassword()
157
- *
158
- * @see Crypt_Base::password_default_salt
159
- * @see Crypt_Base::setPassword()
160
- * @var string
161
- * @access private
162
- */
163
- var $password_default_salt = 'phpseclib';
164
-
165
- /**
166
- * The Key Schedule
167
- *
168
- * @see self::_setup()
169
- * @var array
170
- * @access private
171
- */
172
- var $w;
173
-
174
- /**
175
- * The Inverse Key Schedule
176
- *
177
- * @see self::_setup()
178
- * @var array
179
- * @access private
180
- */
181
- var $dw;
182
-
183
- /**
184
- * The Block Length divided by 32
185
- *
186
- * @see self::setBlockLength()
187
- * @var int
188
- * @access private
189
- * @internal The max value is 256 / 32 = 8, the min value is 128 / 32 = 4. Exists in conjunction with $block_size
190
- * because the encryption / decryption / key schedule creation requires this number and not $block_size. We could
191
- * derive this from $block_size or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu
192
- * of that, we'll just precompute it once.
193
- */
194
- var $Nb = 4;
195
-
196
- /**
197
- * The Key Length (in bytes)
198
- *
199
- * @see self::setKeyLength()
200
- * @var int
201
- * @access private
202
- * @internal The max value is 256 / 8 = 32, the min value is 128 / 8 = 16. Exists in conjunction with $Nk
203
- * because the encryption / decryption / key schedule creation requires this number and not $key_length. We could
204
- * derive this from $key_length or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu
205
- * of that, we'll just precompute it once.
206
- */
207
- var $key_length = 16;
208
-
209
- /**
210
- * The Key Length divided by 32
211
- *
212
- * @see self::setKeyLength()
213
- * @var int
214
- * @access private
215
- * @internal The max value is 256 / 32 = 8, the min value is 128 / 32 = 4
216
- */
217
- var $Nk = 4;
218
-
219
- /**
220
- * The Number of Rounds
221
- *
222
- * @var int
223
- * @access private
224
- * @internal The max value is 14, the min value is 10.
225
- */
226
- var $Nr;
227
-
228
- /**
229
- * Shift offsets
230
- *
231
- * @var array
232
- * @access private
233
- */
234
- var $c;
235
-
236
- /**
237
- * Holds the last used key- and block_size information
238
- *
239
- * @var array
240
- * @access private
241
- */
242
- var $kl;
243
-
244
- /**
245
- * Sets the key.
246
- *
247
- * Keys can be of any length. Rijndael, itself, requires the use of a key that's between 128-bits and 256-bits long and
248
- * 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
249
- * up to the closest valid key length, padding $key with null bytes. If the key is more than 256-bits, we trim the
250
- * excess bits.
251
- *
252
- * If the key is not explicitly set, it'll be assumed to be all null bytes.
253
- *
254
- * Note: 160/224-bit keys must explicitly set by setKeyLength(), otherwise they will be round/pad up to 192/256 bits.
255
- *
256
- * @see Crypt_Base:setKey()
257
- * @see self::setKeyLength()
258
- * @access public
259
- * @param string $key
260
- */
261
- function setKey($key)
262
- {
263
- if (!$this->explicit_key_length) {
264
- $length = strlen($key);
265
- switch (true) {
266
- case $length <= 16:
267
- $this->key_size = 16;
268
- break;
269
- case $length <= 20:
270
- $this->key_size = 20;
271
- break;
272
- case $length <= 24:
273
- $this->key_size = 24;
274
- break;
275
- case $length <= 28:
276
- $this->key_size = 28;
277
- break;
278
- default:
279
- $this->key_size = 32;
280
- }
281
- }
282
- parent::setKey($key);
283
- }
284
-
285
- /**
286
- * Sets the key length
287
- *
288
- * Valid key lengths are 128, 160, 192, 224, and 256. If the length is less than 128, it will be rounded up to
289
- * 128. If the length is greater than 128 and invalid, it will be rounded down to the closest valid amount.
290
- *
291
- * Note: phpseclib extends Rijndael (and AES) for using 160- and 224-bit keys but they are officially not defined
292
- * and the most (if not all) implementations are not able using 160/224-bit keys but round/pad them up to
293
- * 192/256 bits as, for example, mcrypt will do.
294
- *
295
- * That said, if you want be compatible with other Rijndael and AES implementations,
296
- * you should not setKeyLength(160) or setKeyLength(224).
297
- *
298
- * Additional: In case of 160- and 224-bit keys, phpseclib will/can, for that reason, not use
299
- * the mcrypt php extension, even if available.
300
- * This results then in slower encryption.
301
- *
302
- * @access public
303
- * @param int $length
304
- */
305
- function setKeyLength($length)
306
- {
307
- switch (true) {
308
- case $length <= 128:
309
- $this->key_length = 16;
310
- break;
311
- case $length <= 160:
312
- $this->key_length = 20;
313
- break;
314
- case $length <= 192:
315
- $this->key_length = 24;
316
- break;
317
- case $length <= 224:
318
- $this->key_length = 28;
319
- break;
320
- default:
321
- $this->key_length = 32;
322
- }
323
-
324
- parent::setKeyLength($length);
325
- }
326
-
327
- /**
328
- * Sets the block length
329
- *
330
- * Valid block lengths are 128, 160, 192, 224, and 256. If the length is less than 128, it will be rounded up to
331
- * 128. If the length is greater than 128 and invalid, it will be rounded down to the closest valid amount.
332
- *
333
- * @access public
334
- * @param int $length
335
- */
336
- function setBlockLength($length)
337
- {
338
- $length >>= 5;
339
- if ($length > 8) {
340
- $length = 8;
341
- } elseif ($length < 4) {
342
- $length = 4;
343
- }
344
- $this->Nb = $length;
345
- $this->block_size = $length << 2;
346
- $this->changed = true;
347
- $this->_setEngine();
348
- }
349
-
350
- /**
351
- * Test for engine validity
352
- *
353
- * This is mainly just a wrapper to set things up for Crypt_Base::isValidEngine()
354
- *
355
- * @see Crypt_Base::Crypt_Base()
356
- * @param int $engine
357
- * @access public
358
- * @return bool
359
- */
360
- function isValidEngine($engine)
361
- {
362
- switch ($engine) {
363
- case CRYPT_ENGINE_OPENSSL:
364
- if ($this->block_size != 16) {
365
- return false;
366
- }
367
- $this->cipher_name_openssl_ecb = 'aes-' . ($this->key_length << 3) . '-ecb';
368
- $this->cipher_name_openssl = 'aes-' . ($this->key_length << 3) . '-' . $this->_openssl_translate_mode();
369
- break;
370
- case CRYPT_ENGINE_MCRYPT:
371
- $this->cipher_name_mcrypt = 'rijndael-' . ($this->block_size << 3);
372
- if ($this->key_length % 8) { // is it a 160/224-bit key?
373
- // mcrypt is not usable for them, only for 128/192/256-bit keys
374
- return false;
375
- }
376
- }
377
-
378
- return parent::isValidEngine($engine);
379
- }
380
-
381
- /**
382
- * Encrypts a block
383
- *
384
- * @access private
385
- * @param string $in
386
- * @return string
387
- */
388
- function _encryptBlock($in)
389
- {
390
- static $tables;
391
- if (empty($tables)) {
392
- $tables = &$this->_getTables();
393
- }
394
- $t0 = $tables[0];
395
- $t1 = $tables[1];
396
- $t2 = $tables[2];
397
- $t3 = $tables[3];
398
- $sbox = $tables[4];
399
-
400
- $state = array();
401
- $words = unpack('N*', $in);
402
-
403
- $c = $this->c;
404
- $w = $this->w;
405
- $Nb = $this->Nb;
406
- $Nr = $this->Nr;
407
-
408
- // addRoundKey
409
- $wc = $Nb - 1;
410
- foreach ($words as $word) {
411
- $state[] = $word ^ $w[++$wc];
412
- }
413
-
414
- // fips-197.pdf#page=19, "Figure 5. Pseudo Code for the Cipher", states that this loop has four components -
415
- // subBytes, shiftRows, mixColumns, and addRoundKey. fips-197.pdf#page=30, "Implementation Suggestions Regarding
416
- // Various Platforms" suggests that performs enhanced implementations are described in Rijndael-ammended.pdf.
417
- // Rijndael-ammended.pdf#page=20, "Implementation aspects / 32-bit processor", discusses such an optimization.
418
- // Unfortunately, the description given there is not quite correct. Per aes.spec.v316.pdf#page=19 [1],
419
- // equation (7.4.7) is supposed to use addition instead of subtraction, so we'll do that here, as well.
420
-
421
- // [1] http://fp.gladman.plus.com/cryptography_technology/rijndael/aes.spec.v316.pdf
422
- $temp = array();
423
- for ($round = 1; $round < $Nr; ++$round) {
424
- $i = 0; // $c[0] == 0
425
- $j = $c[1];
426
- $k = $c[2];
427
- $l = $c[3];
428
-
429
- while ($i < $Nb) {
430
- $temp[$i] = $t0[$state[$i] >> 24 & 0x000000FF] ^
431
- $t1[$state[$j] >> 16 & 0x000000FF] ^
432
- $t2[$state[$k] >> 8 & 0x000000FF] ^
433
- $t3[$state[$l] & 0x000000FF] ^
434
- $w[++$wc];
435
- ++$i;
436
- $j = ($j + 1) % $Nb;
437
- $k = ($k + 1) % $Nb;
438
- $l = ($l + 1) % $Nb;
439
- }
440
- $state = $temp;
441
- }
442
-
443
- // subWord
444
- for ($i = 0; $i < $Nb; ++$i) {
445
- $state[$i] = $sbox[$state[$i] & 0x000000FF] |
446
- ($sbox[$state[$i] >> 8 & 0x000000FF] << 8) |
447
- ($sbox[$state[$i] >> 16 & 0x000000FF] << 16) |
448
- ($sbox[$state[$i] >> 24 & 0x000000FF] << 24);
449
- }
450
-
451
- // shiftRows + addRoundKey
452
- $i = 0; // $c[0] == 0
453
- $j = $c[1];
454
- $k = $c[2];
455
- $l = $c[3];
456
- while ($i < $Nb) {
457
- $temp[$i] = ($state[$i] & 0xFF000000) ^
458
- ($state[$j] & 0x00FF0000) ^
459
- ($state[$k] & 0x0000FF00) ^
460
- ($state[$l] & 0x000000FF) ^
461
- $w[$i];
462
- ++$i;
463
- $j = ($j + 1) % $Nb;
464
- $k = ($k + 1) % $Nb;
465
- $l = ($l + 1) % $Nb;
466
- }
467
-
468
- switch ($Nb) {
469
- case 8:
470
- return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6], $temp[7]);
471
- case 7:
472
- return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6]);
473
- case 6:
474
- return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5]);
475
- case 5:
476
- return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4]);
477
- default:
478
- return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3]);
479
- }
480
- }
481
-
482
- /**
483
- * Decrypts a block
484
- *
485
- * @access private
486
- * @param string $in
487
- * @return string
488
- */
489
- function _decryptBlock($in)
490
- {
491
- static $invtables;
492
- if (empty($invtables)) {
493
- $invtables = &$this->_getInvTables();
494
- }
495
- $dt0 = $invtables[0];
496
- $dt1 = $invtables[1];
497
- $dt2 = $invtables[2];
498
- $dt3 = $invtables[3];
499
- $isbox = $invtables[4];
500
-
501
- $state = array();
502
- $words = unpack('N*', $in);
503
-
504
- $c = $this->c;
505
- $dw = $this->dw;
506
- $Nb = $this->Nb;
507
- $Nr = $this->Nr;
508
-
509
- // addRoundKey
510
- $wc = $Nb - 1;
511
- foreach ($words as $word) {
512
- $state[] = $word ^ $dw[++$wc];
513
- }
514
-
515
- $temp = array();
516
- for ($round = $Nr - 1; $round > 0; --$round) {
517
- $i = 0; // $c[0] == 0
518
- $j = $Nb - $c[1];
519
- $k = $Nb - $c[2];
520
- $l = $Nb - $c[3];
521
-
522
- while ($i < $Nb) {
523
- $temp[$i] = $dt0[$state[$i] >> 24 & 0x000000FF] ^
524
- $dt1[$state[$j] >> 16 & 0x000000FF] ^
525
- $dt2[$state[$k] >> 8 & 0x000000FF] ^
526
- $dt3[$state[$l] & 0x000000FF] ^
527
- $dw[++$wc];
528
- ++$i;
529
- $j = ($j + 1) % $Nb;
530
- $k = ($k + 1) % $Nb;
531
- $l = ($l + 1) % $Nb;
532
- }
533
- $state = $temp;
534
- }
535
-
536
- // invShiftRows + invSubWord + addRoundKey
537
- $i = 0; // $c[0] == 0
538
- $j = $Nb - $c[1];
539
- $k = $Nb - $c[2];
540
- $l = $Nb - $c[3];
541
-
542
- while ($i < $Nb) {
543
- $word = ($state[$i] & 0xFF000000) |
544
- ($state[$j] & 0x00FF0000) |
545
- ($state[$k] & 0x0000FF00) |
546
- ($state[$l] & 0x000000FF);
547
-
548
- $temp[$i] = $dw[$i] ^ ($isbox[$word & 0x000000FF] |
549
- ($isbox[$word >> 8 & 0x000000FF] << 8) |
550
- ($isbox[$word >> 16 & 0x000000FF] << 16) |
551
- ($isbox[$word >> 24 & 0x000000FF] << 24));
552
- ++$i;
553
- $j = ($j + 1) % $Nb;
554
- $k = ($k + 1) % $Nb;
555
- $l = ($l + 1) % $Nb;
556
- }
557
-
558
- switch ($Nb) {
559
- case 8:
560
- return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6], $temp[7]);
561
- case 7:
562
- return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6]);
563
- case 6:
564
- return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5]);
565
- case 5:
566
- return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4]);
567
- default:
568
- return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3]);
569
- }
570
- }
571
-
572
- /**
573
- * Setup the key (expansion)
574
- *
575
- * @see Crypt_Base::_setupKey()
576
- * @access private
577
- */
578
- function _setupKey()
579
- {
580
- // Each number in $rcon is equal to the previous number multiplied by two in Rijndael's finite field.
581
- // See http://en.wikipedia.org/wiki/Finite_field_arithmetic#Multiplicative_inverse
582
- static $rcon = array(0,
583
- 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000,
584
- 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000,
585
- 0x6C000000, 0xD8000000, 0xAB000000, 0x4D000000, 0x9A000000,
586
- 0x2F000000, 0x5E000000, 0xBC000000, 0x63000000, 0xC6000000,
587
- 0x97000000, 0x35000000, 0x6A000000, 0xD4000000, 0xB3000000,
588
- 0x7D000000, 0xFA000000, 0xEF000000, 0xC5000000, 0x91000000
589
- );
590
-
591
- if (isset($this->kl['key']) && $this->key === $this->kl['key'] && $this->key_length === $this->kl['key_length'] && $this->block_size === $this->kl['block_size']) {
592
- // already expanded
593
- return;
594
- }
595
- $this->kl = array('key' => $this->key, 'key_length' => $this->key_length, 'block_size' => $this->block_size);
596
-
597
- $this->Nk = $this->key_length >> 2;
598
- // see Rijndael-ammended.pdf#page=44
599
- $this->Nr = max($this->Nk, $this->Nb) + 6;
600
-
601
- // shift offsets for Nb = 5, 7 are defined in Rijndael-ammended.pdf#page=44,
602
- // "Table 8: Shift offsets in Shiftrow for the alternative block lengths"
603
- // shift offsets for Nb = 4, 6, 8 are defined in Rijndael-ammended.pdf#page=14,
604
- // "Table 2: Shift offsets for different block lengths"
605
- switch ($this->Nb) {
606
- case 4:
607
- case 5:
608
- case 6:
609
- $this->c = array(0, 1, 2, 3);
610
- break;
611
- case 7:
612
- $this->c = array(0, 1, 2, 4);
613
- break;
614
- case 8:
615
- $this->c = array(0, 1, 3, 4);
616
- }
617
-
618
- $w = array_values(unpack('N*words', $this->key));
619
-
620
- $length = $this->Nb * ($this->Nr + 1);
621
- for ($i = $this->Nk; $i < $length; $i++) {
622
- $temp = $w[$i - 1];
623
- if ($i % $this->Nk == 0) {
624
- // according to <http://php.net/language.types.integer>, "the size of an integer is platform-dependent".
625
- // on a 32-bit machine, it's 32-bits, and on a 64-bit machine, it's 64-bits. on a 32-bit machine,
626
- // 0xFFFFFFFF << 8 == 0xFFFFFF00, but on a 64-bit machine, it equals 0xFFFFFFFF00. as such, doing 'and'
627
- // with 0xFFFFFFFF (or 0xFFFFFF00) on a 32-bit machine is unnecessary, but on a 64-bit machine, it is.
628
- $temp = (($temp << 8) & 0xFFFFFF00) | (($temp >> 24) & 0x000000FF); // rotWord
629
- $temp = $this->_subWord($temp) ^ $rcon[$i / $this->Nk];
630
- } elseif ($this->Nk > 6 && $i % $this->Nk == 4) {
631
- $temp = $this->_subWord($temp);
632
- }
633
- $w[$i] = $w[$i - $this->Nk] ^ $temp;
634
- }
635
-
636
- // convert the key schedule from a vector of $Nb * ($Nr + 1) length to a matrix with $Nr + 1 rows and $Nb columns
637
- // and generate the inverse key schedule. more specifically,
638
- // according to <http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=23> (section 5.3.3),
639
- // "The key expansion for the Inverse Cipher is defined as follows:
640
- // 1. Apply the Key Expansion.
641
- // 2. Apply InvMixColumn to all Round Keys except the first and the last one."
642
- // also, see fips-197.pdf#page=27, "5.3.5 Equivalent Inverse Cipher"
643
- list($dt0, $dt1, $dt2, $dt3) = $this->_getInvTables();
644
- $temp = $this->w = $this->dw = array();
645
- for ($i = $row = $col = 0; $i < $length; $i++, $col++) {
646
- if ($col == $this->Nb) {
647
- if ($row == 0) {
648
- $this->dw[0] = $this->w[0];
649
- } else {
650
- // subWord + invMixColumn + invSubWord = invMixColumn
651
- $j = 0;
652
- while ($j < $this->Nb) {
653
- $dw = $this->_subWord($this->w[$row][$j]);
654
- $temp[$j] = $dt0[$dw >> 24 & 0x000000FF] ^
655
- $dt1[$dw >> 16 & 0x000000FF] ^
656
- $dt2[$dw >> 8 & 0x000000FF] ^
657
- $dt3[$dw & 0x000000FF];
658
- $j++;
659
- }
660
- $this->dw[$row] = $temp;
661
- }
662
-
663
- $col = 0;
664
- $row++;
665
- }
666
- $this->w[$row][$col] = $w[$i];
667
- }
668
-
669
- $this->dw[$row] = $this->w[$row];
670
-
671
- // Converting to 1-dim key arrays (both ascending)
672
- $this->dw = array_reverse($this->dw);
673
- $w = array_pop($this->w);
674
- $dw = array_pop($this->dw);
675
- foreach ($this->w as $r => $wr) {
676
- foreach ($wr as $c => $wc) {
677
- $w[] = $wc;
678
- $dw[] = $this->dw[$r][$c];
679
- }
680
- }
681
- $this->w = $w;
682
- $this->dw = $dw;
683
- }
684
-
685
- /**
686
- * Performs S-Box substitutions
687
- *
688
- * @access private
689
- * @param int $word
690
- */
691
- function _subWord($word)
692
- {
693
- static $sbox;
694
- if (empty($sbox)) {
695
- list(, , , , $sbox) = $this->_getTables();
696
- }
697
-
698
- return $sbox[$word & 0x000000FF] |
699
- ($sbox[$word >> 8 & 0x000000FF] << 8) |
700
- ($sbox[$word >> 16 & 0x000000FF] << 16) |
701
- ($sbox[$word >> 24 & 0x000000FF] << 24);
702
- }
703
-
704
- /**
705
- * Provides the mixColumns and sboxes tables
706
- *
707
- * @see Crypt_Rijndael:_encryptBlock()
708
- * @see Crypt_Rijndael:_setupInlineCrypt()
709
- * @see Crypt_Rijndael:_subWord()
710
- * @access private
711
- * @return array &$tables
712
- */
713
- function &_getTables()
714
- {
715
- static $tables;
716
- if (empty($tables)) {
717
- // according to <http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=19> (section 5.2.1),
718
- // precomputed tables can be used in the mixColumns phase. in that example, they're assigned t0...t3, so
719
- // those are the names we'll use.
720
- $t3 = array_map('intval', array(
721
- // with array_map('intval', ...) we ensure we have only int's and not
722
- // some slower floats converted by php automatically on high values
723
- 0x6363A5C6, 0x7C7C84F8, 0x777799EE, 0x7B7B8DF6, 0xF2F20DFF, 0x6B6BBDD6, 0x6F6FB1DE, 0xC5C55491,
724
- 0x30305060, 0x01010302, 0x6767A9CE, 0x2B2B7D56, 0xFEFE19E7, 0xD7D762B5, 0xABABE64D, 0x76769AEC,
725
- 0xCACA458F, 0x82829D1F, 0xC9C94089, 0x7D7D87FA, 0xFAFA15EF, 0x5959EBB2, 0x4747C98E, 0xF0F00BFB,
726
- 0xADADEC41, 0xD4D467B3, 0xA2A2FD5F, 0xAFAFEA45, 0x9C9CBF23, 0xA4A4F753, 0x727296E4, 0xC0C05B9B,
727
- 0xB7B7C275, 0xFDFD1CE1, 0x9393AE3D, 0x26266A4C, 0x36365A6C, 0x3F3F417E, 0xF7F702F5, 0xCCCC4F83,
728
- 0x34345C68, 0xA5A5F451, 0xE5E534D1, 0xF1F108F9, 0x717193E2, 0xD8D873AB, 0x31315362, 0x15153F2A,
729
- 0x04040C08, 0xC7C75295, 0x23236546, 0xC3C35E9D, 0x18182830, 0x9696A137, 0x05050F0A, 0x9A9AB52F,
730
- 0x0707090E, 0x12123624, 0x80809B1B, 0xE2E23DDF, 0xEBEB26CD, 0x2727694E, 0xB2B2CD7F, 0x75759FEA,
731
- 0x09091B12, 0x83839E1D, 0x2C2C7458, 0x1A1A2E34, 0x1B1B2D36, 0x6E6EB2DC, 0x5A5AEEB4, 0xA0A0FB5B,
732
- 0x5252F6A4, 0x3B3B4D76, 0xD6D661B7, 0xB3B3CE7D, 0x29297B52, 0xE3E33EDD, 0x2F2F715E, 0x84849713,
733
- 0x5353F5A6, 0xD1D168B9, 0x00000000, 0xEDED2CC1, 0x20206040, 0xFCFC1FE3, 0xB1B1C879, 0x5B5BEDB6,
734
- 0x6A6ABED4, 0xCBCB468D, 0xBEBED967, 0x39394B72, 0x4A4ADE94, 0x4C4CD498, 0x5858E8B0, 0xCFCF4A85,
735
- 0xD0D06BBB, 0xEFEF2AC5, 0xAAAAE54F, 0xFBFB16ED, 0x4343C586, 0x4D4DD79A, 0x33335566, 0x85859411,
736
- 0x4545CF8A, 0xF9F910E9, 0x02020604, 0x7F7F81FE, 0x5050F0A0, 0x3C3C4478, 0x9F9FBA25, 0xA8A8E34B,
737
- 0x5151F3A2, 0xA3A3FE5D, 0x4040C080, 0x8F8F8A05, 0x9292AD3F, 0x9D9DBC21, 0x38384870, 0xF5F504F1,
738
- 0xBCBCDF63, 0xB6B6C177, 0xDADA75AF, 0x21216342, 0x10103020, 0xFFFF1AE5, 0xF3F30EFD, 0xD2D26DBF,
739
- 0xCDCD4C81, 0x0C0C1418, 0x13133526, 0xECEC2FC3, 0x5F5FE1BE, 0x9797A235, 0x4444CC88, 0x1717392E,
740
- 0xC4C45793, 0xA7A7F255, 0x7E7E82FC, 0x3D3D477A, 0x6464ACC8, 0x5D5DE7BA, 0x19192B32, 0x737395E6,
741
- 0x6060A0C0, 0x81819819, 0x4F4FD19E, 0xDCDC7FA3, 0x22226644, 0x2A2A7E54, 0x9090AB3B, 0x8888830B,
742
- 0x4646CA8C, 0xEEEE29C7, 0xB8B8D36B, 0x14143C28, 0xDEDE79A7, 0x5E5EE2BC, 0x0B0B1D16, 0xDBDB76AD,
743
- 0xE0E03BDB, 0x32325664, 0x3A3A4E74, 0x0A0A1E14, 0x4949DB92, 0x06060A0C, 0x24246C48, 0x5C5CE4B8,
744
- 0xC2C25D9F, 0xD3D36EBD, 0xACACEF43, 0x6262A6C4, 0x9191A839, 0x9595A431, 0xE4E437D3, 0x79798BF2,
745
- 0xE7E732D5, 0xC8C8438B, 0x3737596E, 0x6D6DB7DA, 0x8D8D8C01, 0xD5D564B1, 0x4E4ED29C, 0xA9A9E049,
746
- 0x6C6CB4D8, 0x5656FAAC, 0xF4F407F3, 0xEAEA25CF, 0x6565AFCA, 0x7A7A8EF4, 0xAEAEE947, 0x08081810,
747
- 0xBABAD56F, 0x787888F0, 0x25256F4A, 0x2E2E725C, 0x1C1C2438, 0xA6A6F157, 0xB4B4C773, 0xC6C65197,
748
- 0xE8E823CB, 0xDDDD7CA1, 0x74749CE8, 0x1F1F213E, 0x4B4BDD96, 0xBDBDDC61, 0x8B8B860D, 0x8A8A850F,
749
- 0x707090E0, 0x3E3E427C, 0xB5B5C471, 0x6666AACC, 0x4848D890, 0x03030506, 0xF6F601F7, 0x0E0E121C,
750
- 0x6161A3C2, 0x35355F6A, 0x5757F9AE, 0xB9B9D069, 0x86869117, 0xC1C15899, 0x1D1D273A, 0x9E9EB927,
751
- 0xE1E138D9, 0xF8F813EB, 0x9898B32B, 0x11113322, 0x6969BBD2, 0xD9D970A9, 0x8E8E8907, 0x9494A733,
752
- 0x9B9BB62D, 0x1E1E223C, 0x87879215, 0xE9E920C9, 0xCECE4987, 0x5555FFAA, 0x28287850, 0xDFDF7AA5,
753
- 0x8C8C8F03, 0xA1A1F859, 0x89898009, 0x0D0D171A, 0xBFBFDA65, 0xE6E631D7, 0x4242C684, 0x6868B8D0,
754
- 0x4141C382, 0x9999B029, 0x2D2D775A, 0x0F0F111E, 0xB0B0CB7B, 0x5454FCA8, 0xBBBBD66D, 0x16163A2C
755
- ));
756
-
757
- foreach ($t3 as $t3i) {
758
- $t0[] = (($t3i << 24) & 0xFF000000) | (($t3i >> 8) & 0x00FFFFFF);
759
- $t1[] = (($t3i << 16) & 0xFFFF0000) | (($t3i >> 16) & 0x0000FFFF);
760
- $t2[] = (($t3i << 8) & 0xFFFFFF00) | (($t3i >> 24) & 0x000000FF);
761
- }
762
-
763
- $tables = array(
764
- // The Precomputed mixColumns tables t0 - t3
765
- $t0,
766
- $t1,
767
- $t2,
768
- $t3,
769
- // The SubByte S-Box
770
- array(
771
- 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
772
- 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
773
- 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
774
- 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
775
- 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
776
- 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
777
- 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
778
- 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
779
- 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
780
- 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
781
- 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
782
- 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
783
- 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
784
- 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
785
- 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
786
- 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
787
- )
788
- );
789
- }
790
- return $tables;
791
- }
792
-
793
- /**
794
- * Provides the inverse mixColumns and inverse sboxes tables
795
- *
796
- * @see Crypt_Rijndael:_decryptBlock()
797
- * @see Crypt_Rijndael:_setupInlineCrypt()
798
- * @see Crypt_Rijndael:_setupKey()
799
- * @access private
800
- * @return array &$tables
801
- */
802
- function &_getInvTables()
803
- {
804
- static $tables;
805
- if (empty($tables)) {
806
- $dt3 = array_map('intval', array(
807
- 0xF4A75051, 0x4165537E, 0x17A4C31A, 0x275E963A, 0xAB6BCB3B, 0x9D45F11F, 0xFA58ABAC, 0xE303934B,
808
- 0x30FA5520, 0x766DF6AD, 0xCC769188, 0x024C25F5, 0xE5D7FC4F, 0x2ACBD7C5, 0x35448026, 0x62A38FB5,
809
- 0xB15A49DE, 0xBA1B6725, 0xEA0E9845, 0xFEC0E15D, 0x2F7502C3, 0x4CF01281, 0x4697A38D, 0xD3F9C66B,
810
- 0x8F5FE703, 0x929C9515, 0x6D7AEBBF, 0x5259DA95, 0xBE832DD4, 0x7421D358, 0xE0692949, 0xC9C8448E,
811
- 0xC2896A75, 0x8E7978F4, 0x583E6B99, 0xB971DD27, 0xE14FB6BE, 0x88AD17F0, 0x20AC66C9, 0xCE3AB47D,
812
- 0xDF4A1863, 0x1A3182E5, 0x51336097, 0x537F4562, 0x6477E0B1, 0x6BAE84BB, 0x81A01CFE, 0x082B94F9,
813
- 0x48685870, 0x45FD198F, 0xDE6C8794, 0x7BF8B752, 0x73D323AB, 0x4B02E272, 0x1F8F57E3, 0x55AB2A66,
814
- 0xEB2807B2, 0xB5C2032F, 0xC57B9A86, 0x3708A5D3, 0x2887F230, 0xBFA5B223, 0x036ABA02, 0x16825CED,
815
- 0xCF1C2B8A, 0x79B492A7, 0x07F2F0F3, 0x69E2A14E, 0xDAF4CD65, 0x05BED506, 0x34621FD1, 0xA6FE8AC4,
816
- 0x2E539D34, 0xF355A0A2, 0x8AE13205, 0xF6EB75A4, 0x83EC390B, 0x60EFAA40, 0x719F065E, 0x6E1051BD,
817
- 0x218AF93E, 0xDD063D96, 0x3E05AEDD, 0xE6BD464D, 0x548DB591, 0xC45D0571, 0x06D46F04, 0x5015FF60,
818
- 0x98FB2419, 0xBDE997D6, 0x4043CC89, 0xD99E7767, 0xE842BDB0, 0x898B8807, 0x195B38E7, 0xC8EEDB79,
819
- 0x7C0A47A1, 0x420FE97C, 0x841EC9F8, 0x00000000, 0x80868309, 0x2BED4832, 0x1170AC1E, 0x5A724E6C,
820
- 0x0EFFFBFD, 0x8538560F, 0xAED51E3D, 0x2D392736, 0x0FD9640A, 0x5CA62168, 0x5B54D19B, 0x362E3A24,
821
- 0x0A67B10C, 0x57E70F93, 0xEE96D2B4, 0x9B919E1B, 0xC0C54F80, 0xDC20A261, 0x774B695A, 0x121A161C,
822
- 0x93BA0AE2, 0xA02AE5C0, 0x22E0433C, 0x1B171D12, 0x090D0B0E, 0x8BC7ADF2, 0xB6A8B92D, 0x1EA9C814,
823
- 0xF1198557, 0x75074CAF, 0x99DDBBEE, 0x7F60FDA3, 0x01269FF7, 0x72F5BC5C, 0x663BC544, 0xFB7E345B,
824
- 0x4329768B, 0x23C6DCCB, 0xEDFC68B6, 0xE4F163B8, 0x31DCCAD7, 0x63851042, 0x97224013, 0xC6112084,
825
- 0x4A247D85, 0xBB3DF8D2, 0xF93211AE, 0x29A16DC7, 0x9E2F4B1D, 0xB230F3DC, 0x8652EC0D, 0xC1E3D077,
826
- 0xB3166C2B, 0x70B999A9, 0x9448FA11, 0xE9642247, 0xFC8CC4A8, 0xF03F1AA0, 0x7D2CD856, 0x3390EF22,
827
- 0x494EC787, 0x38D1C1D9, 0xCAA2FE8C, 0xD40B3698, 0xF581CFA6, 0x7ADE28A5, 0xB78E26DA, 0xADBFA43F,
828
- 0x3A9DE42C, 0x78920D50, 0x5FCC9B6A, 0x7E466254, 0x8D13C2F6, 0xD8B8E890, 0x39F75E2E, 0xC3AFF582,
829
- 0x5D80BE9F, 0xD0937C69, 0xD52DA96F, 0x2512B3CF, 0xAC993BC8, 0x187DA710, 0x9C636EE8, 0x3BBB7BDB,
830
- 0x267809CD, 0x5918F46E, 0x9AB701EC, 0x4F9AA883, 0x956E65E6, 0xFFE67EAA, 0xBCCF0821, 0x15E8E6EF,
831
- 0xE79BD9BA, 0x6F36CE4A, 0x9F09D4EA, 0xB07CD629, 0xA4B2AF31, 0x3F23312A, 0xA59430C6, 0xA266C035,
832
- 0x4EBC3774, 0x82CAA6FC, 0x90D0B0E0, 0xA7D81533, 0x04984AF1, 0xECDAF741, 0xCD500E7F, 0x91F62F17,
833
- 0x4DD68D76, 0xEFB04D43, 0xAA4D54CC, 0x9604DFE4, 0xD1B5E39E, 0x6A881B4C, 0x2C1FB8C1, 0x65517F46,
834
- 0x5EEA049D, 0x8C355D01, 0x877473FA, 0x0B412EFB, 0x671D5AB3, 0xDBD25292, 0x105633E9, 0xD647136D,
835
- 0xD7618C9A, 0xA10C7A37, 0xF8148E59, 0x133C89EB, 0xA927EECE, 0x61C935B7, 0x1CE5EDE1, 0x47B13C7A,
836
- 0xD2DF599C, 0xF2733F55, 0x14CE7918, 0xC737BF73, 0xF7CDEA53, 0xFDAA5B5F, 0x3D6F14DF, 0x44DB8678,
837
- 0xAFF381CA, 0x68C43EB9, 0x24342C38, 0xA3405FC2, 0x1DC37216, 0xE2250CBC, 0x3C498B28, 0x0D9541FF,
838
- 0xA8017139, 0x0CB3DE08, 0xB4E49CD8, 0x56C19064, 0xCB84617B, 0x32B670D5, 0x6C5C7448, 0xB85742D0
839
- ));
840
-
841
- foreach ($dt3 as $dt3i) {
842
- $dt0[] = (($dt3i << 24) & 0xFF000000) | (($dt3i >> 8) & 0x00FFFFFF);
843
- $dt1[] = (($dt3i << 16) & 0xFFFF0000) | (($dt3i >> 16) & 0x0000FFFF);
844
- $dt2[] = (($dt3i << 8) & 0xFFFFFF00) | (($dt3i >> 24) & 0x000000FF);
845
- };
846
-
847
- $tables = array(
848
- // The Precomputed inverse mixColumns tables dt0 - dt3
849
- $dt0,
850
- $dt1,
851
- $dt2,
852
- $dt3,
853
- // The inverse SubByte S-Box
854
- array(
855
- 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB,
856
- 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB,
857
- 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
858
- 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25,
859
- 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92,
860
- 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
861
- 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06,
862
- 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B,
863
- 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
864
- 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E,
865
- 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B,
866
- 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
867
- 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F,
868
- 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF,
869
- 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
870
- 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D
871
- )
872
- );
873
- }
874
- return $tables;
875
- }
876
-
877
- /**
878
- * Setup the performance-optimized function for de/encrypt()
879
- *
880
- * @see Crypt_Base::_setupInlineCrypt()
881
- * @access private
882
- */
883
- function _setupInlineCrypt()
884
- {
885
- // Note: _setupInlineCrypt() will be called only if $this->changed === true
886
- // So here we are'nt under the same heavy timing-stress as we are in _de/encryptBlock() or de/encrypt().
887
- // However...the here generated function- $code, stored as php callback in $this->inline_crypt, must work as fast as even possible.
888
-
889
- $lambda_functions =& Crypt_Rijndael::_getLambdaFunctions();
890
-
891
- // We create max. 10 hi-optimized code for memory reason. Means: For each $key one ultra fast inline-crypt function.
892
- // (Currently, for Crypt_Rijndael/AES, one generated $lambda_function cost on php5.5@32bit ~80kb unfreeable mem and ~130kb on php5.5@64bit)
893
- // After that, we'll still create very fast optimized code but not the hi-ultimative code, for each $mode one.
894
- $gen_hi_opt_code = (bool)(count($lambda_functions) < 10);
895
-
896
- // Generation of a uniqe hash for our generated code
897
- $code_hash = "Crypt_Rijndael, {$this->mode}, {$this->Nr}, {$this->Nb}";
898
- if ($gen_hi_opt_code) {
899
- $code_hash = str_pad($code_hash, 32) . $this->_hashInlineCryptFunction($this->key);
900
- }
901
-
902
- if (!isset($lambda_functions[$code_hash])) {
903
- switch (true) {
904
- case $gen_hi_opt_code:
905
- // The hi-optimized $lambda_functions will use the key-words hardcoded for better performance.
906
- $w = $this->w;
907
- $dw = $this->dw;
908
- $init_encrypt = '';
909
- $init_decrypt = '';
910
- break;
911
- default:
912
- for ($i = 0, $cw = count($this->w); $i < $cw; ++$i) {
913
- $w[] = '$w[' . $i . ']';
914
- $dw[] = '$dw[' . $i . ']';
915
- }
916
- $init_encrypt = '$w = $self->w;';
917
- $init_decrypt = '$dw = $self->dw;';
918
- }
919
-
920
- $Nr = $this->Nr;
921
- $Nb = $this->Nb;
922
- $c = $this->c;
923
-
924
- // Generating encrypt code:
925
- $init_encrypt.= '
926
- static $tables;
927
- if (empty($tables)) {
928
- $tables = &$self->_getTables();
929
- }
930
- $t0 = $tables[0];
931
- $t1 = $tables[1];
932
- $t2 = $tables[2];
933
- $t3 = $tables[3];
934
- $sbox = $tables[4];
935
- ';
936
-
937
- $s = 'e';
938
- $e = 's';
939
- $wc = $Nb - 1;
940
-
941
- // Preround: addRoundKey
942
- $encrypt_block = '$in = unpack("N*", $in);'."\n";
943
- for ($i = 0; $i < $Nb; ++$i) {
944
- $encrypt_block .= '$s'.$i.' = $in['.($i + 1).'] ^ '.$w[++$wc].";\n";
945
- }
946
-
947
- // Mainrounds: shiftRows + subWord + mixColumns + addRoundKey
948
- for ($round = 1; $round < $Nr; ++$round) {
949
- list($s, $e) = array($e, $s);
950
- for ($i = 0; $i < $Nb; ++$i) {
951
- $encrypt_block.=
952
- '$'.$e.$i.' =
953
- $t0[($'.$s.$i .' >> 24) & 0xff] ^
954
- $t1[($'.$s.(($i + $c[1]) % $Nb).' >> 16) & 0xff] ^
955
- $t2[($'.$s.(($i + $c[2]) % $Nb).' >> 8) & 0xff] ^
956
- $t3[ $'.$s.(($i + $c[3]) % $Nb).' & 0xff] ^
957
- '.$w[++$wc].";\n";
958
- }
959
- }
960
-
961
- // Finalround: subWord + shiftRows + addRoundKey
962
- for ($i = 0; $i < $Nb; ++$i) {
963
- $encrypt_block.=
964
- '$'.$e.$i.' =
965
- $sbox[ $'.$e.$i.' & 0xff] |
966
- ($sbox[($'.$e.$i.' >> 8) & 0xff] << 8) |
967
- ($sbox[($'.$e.$i.' >> 16) & 0xff] << 16) |
968
- ($sbox[($'.$e.$i.' >> 24) & 0xff] << 24);'."\n";
969
- }
970
- $encrypt_block .= '$in = pack("N*"'."\n";
971
- for ($i = 0; $i < $Nb; ++$i) {
972
- $encrypt_block.= ',
973
- ($'.$e.$i .' & '.((int)0xFF000000).') ^
974
- ($'.$e.(($i + $c[1]) % $Nb).' & 0x00FF0000 ) ^
975
- ($'.$e.(($i + $c[2]) % $Nb).' & 0x0000FF00 ) ^
976
- ($'.$e.(($i + $c[3]) % $Nb).' & 0x000000FF ) ^
977
- '.$w[$i]."\n";
978
- }
979
- $encrypt_block .= ');';
980
-
981
- // Generating decrypt code:
982
- $init_decrypt.= '
983
- static $invtables;
984
- if (empty($invtables)) {
985
- $invtables = &$self->_getInvTables();
986
- }
987
- $dt0 = $invtables[0];
988
- $dt1 = $invtables[1];
989
- $dt2 = $invtables[2];
990
- $dt3 = $invtables[3];
991
- $isbox = $invtables[4];
992
- ';
993
-
994
- $s = 'e';
995
- $e = 's';
996
- $wc = $Nb - 1;
997
-
998
- // Preround: addRoundKey
999
- $decrypt_block = '$in = unpack("N*", $in);'."\n";
1000
- for ($i = 0; $i < $Nb; ++$i) {
1001
- $decrypt_block .= '$s'.$i.' = $in['.($i + 1).'] ^ '.$dw[++$wc].';'."\n";
1002
- }
1003
-
1004
- // Mainrounds: shiftRows + subWord + mixColumns + addRoundKey
1005
- for ($round = 1; $round < $Nr; ++$round) {
1006
- list($s, $e) = array($e, $s);
1007
- for ($i = 0; $i < $Nb; ++$i) {
1008
- $decrypt_block.=
1009
- '$'.$e.$i.' =
1010
- $dt0[($'.$s.$i .' >> 24) & 0xff] ^
1011
- $dt1[($'.$s.(($Nb + $i - $c[1]) % $Nb).' >> 16) & 0xff] ^
1012
- $dt2[($'.$s.(($Nb + $i - $c[2]) % $Nb).' >> 8) & 0xff] ^
1013
- $dt3[ $'.$s.(($Nb + $i - $c[3]) % $Nb).' & 0xff] ^
1014
- '.$dw[++$wc].";\n";
1015
- }
1016
- }
1017
-
1018
- // Finalround: subWord + shiftRows + addRoundKey
1019
- for ($i = 0; $i < $Nb; ++$i) {
1020
- $decrypt_block.=
1021
- '$'.$e.$i.' =
1022
- $isbox[ $'.$e.$i.' & 0xff] |
1023
- ($isbox[($'.$e.$i.' >> 8) & 0xff] << 8) |
1024
- ($isbox[($'.$e.$i.' >> 16) & 0xff] << 16) |
1025
- ($isbox[($'.$e.$i.' >> 24) & 0xff] << 24);'."\n";
1026
- }
1027
- $decrypt_block .= '$in = pack("N*"'."\n";
1028
- for ($i = 0; $i < $Nb; ++$i) {
1029
- $decrypt_block.= ',
1030
- ($'.$e.$i. ' & '.((int)0xFF000000).') ^
1031
- ($'.$e.(($Nb + $i - $c[1]) % $Nb).' & 0x00FF0000 ) ^
1032
- ($'.$e.(($Nb + $i - $c[2]) % $Nb).' & 0x0000FF00 ) ^
1033
- ($'.$e.(($Nb + $i - $c[3]) % $Nb).' & 0x000000FF ) ^
1034
- '.$dw[$i]."\n";
1035
- }
1036
- $decrypt_block .= ');';
1037
-
1038
- $lambda_functions[$code_hash] = $this->_createInlineCryptFunction(
1039
- array(
1040
- 'init_crypt' => '',
1041
- 'init_encrypt' => $init_encrypt,
1042
- 'init_decrypt' => $init_decrypt,
1043
- 'encrypt_block' => $encrypt_block,
1044
- 'decrypt_block' => $decrypt_block
1045
- )
1046
- );
1047
- }
1048
- $this->inline_crypt = $lambda_functions[$code_hash];
1049
- }
1050
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/phpseclib/Crypt/TripleDES.php DELETED
@@ -1,517 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Pure-PHP implementation of Triple DES.
5
- *
6
- * Uses mcrypt, if available, and an internal implementation, otherwise. Operates in the EDE3 mode (encrypt-decrypt-encrypt).
7
- *
8
- * PHP versions 4 and 5
9
- *
10
- * Here's a short example of how to use this library:
11
- * <code>
12
- * <?php
13
- * include 'Crypt/TripleDES.php';
14
- *
15
- * $des = new Crypt_TripleDES();
16
- *
17
- * $des->setKey('abcdefghijklmnopqrstuvwx');
18
- *
19
- * $size = 10 * 1024;
20
- * $plaintext = '';
21
- * for ($i = 0; $i < $size; $i++) {
22
- * $plaintext.= 'a';
23
- * }
24
- *
25
- * echo $des->decrypt($des->encrypt($plaintext));
26
- * ?>
27
- * </code>
28
- *
29
- * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
30
- * of this software and associated documentation files (the "Software"), to deal
31
- * in the Software without restriction, including without limitation the rights
32
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
33
- * copies of the Software, and to permit persons to whom the Software is
34
- * furnished to do so, subject to the following conditions:
35
- *
36
- * The above copyright notice and this permission notice shall be included in
37
- * all copies or substantial portions of the Software.
38
- *
39
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
40
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
41
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
42
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
43
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
44
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
45
- * THE SOFTWARE.
46
- *
47
- * @category Crypt
48
- * @package Crypt_TripleDES
49
- * @author Jim Wigginton <terrafrost@php.net>
50
- * @copyright 2007 Jim Wigginton
51
- * @license http://www.opensource.org/licenses/mit-license.html MIT License
52
- * @link http://phpseclib.sourceforge.net
53
- */
54
-
55
- /**
56
- * Include Crypt_DES
57
- */
58
- if (!class_exists('Crypt_DES')) {
59
- include_once 'DES.php';
60
- }
61
-
62
- /**#@+
63
- * @access public
64
- * @see self::Crypt_TripleDES()
65
- */
66
- /**
67
- * Encrypt / decrypt using inner chaining
68
- *
69
- * Inner chaining is used by SSH-1 and is generally considered to be less secure then outer chaining (CRYPT_DES_MODE_CBC3).
70
- */
71
- define('CRYPT_MODE_3CBC', -2);
72
- /**
73
- * BC version of the above.
74
- */
75
- define('CRYPT_DES_MODE_3CBC', -2);
76
- /**
77
- * Encrypt / decrypt using outer chaining
78
- *
79
- * Outer chaining is used by SSH-2 and when the mode is set to CRYPT_DES_MODE_CBC.
80
- */
81
- define('CRYPT_MODE_CBC3', CRYPT_MODE_CBC);
82
- /**
83
- * BC version of the above.
84
- */
85
- define('CRYPT_DES_MODE_CBC3', CRYPT_MODE_CBC3);
86
- /**#@-*/
87
-
88
- /**
89
- * Pure-PHP implementation of Triple DES.
90
- *
91
- * @package Crypt_TripleDES
92
- * @author Jim Wigginton <terrafrost@php.net>
93
- * @access public
94
- */
95
- class Crypt_TripleDES extends Crypt_DES
96
- {
97
- /**
98
- * Key Length (in bytes)
99
- *
100
- * @see Crypt_TripleDES::setKeyLength()
101
- * @var int
102
- * @access private
103
- */
104
- var $key_length = 24;
105
-
106
- /**
107
- * The default salt used by setPassword()
108
- *
109
- * @see Crypt_Base::password_default_salt
110
- * @see Crypt_Base::setPassword()
111
- * @var string
112
- * @access private
113
- */
114
- var $password_default_salt = 'phpseclib';
115
-
116
- /**
117
- * The namespace used by the cipher for its constants.
118
- *
119
- * @see Crypt_DES::const_namespace
120
- * @see Crypt_Base::const_namespace
121
- * @var string
122
- * @access private
123
- */
124
- var $const_namespace = 'DES';
125
-
126
- /**
127
- * The mcrypt specific name of the cipher
128
- *
129
- * @see Crypt_DES::cipher_name_mcrypt
130
- * @see Crypt_Base::cipher_name_mcrypt
131
- * @var string
132
- * @access private
133
- */
134
- var $cipher_name_mcrypt = 'tripledes';
135
-
136
- /**
137
- * Optimizing value while CFB-encrypting
138
- *
139
- * @see Crypt_Base::cfb_init_len
140
- * @var int
141
- * @access private
142
- */
143
- var $cfb_init_len = 750;
144
-
145
- /**
146
- * max possible size of $key
147
- *
148
- * @see self::setKey()
149
- * @see Crypt_DES::setKey()
150
- * @var string
151
- * @access private
152
- */
153
- var $key_length_max = 24;
154
-
155
- /**
156
- * Internal flag whether using CRYPT_DES_MODE_3CBC or not
157
- *
158
- * @var bool
159
- * @access private
160
- */
161
- var $mode_3cbc;
162
-
163
- /**
164
- * The Crypt_DES objects
165
- *
166
- * Used only if $mode_3cbc === true
167
- *
168
- * @var array
169
- * @access private
170
- */
171
- var $des;
172
-
173
- /**
174
- * Default Constructor.
175
- *
176
- * Determines whether or not the mcrypt extension should be used.
177
- *
178
- * $mode could be:
179
- *
180
- * - CRYPT_DES_MODE_ECB
181
- *
182
- * - CRYPT_DES_MODE_CBC
183
- *
184
- * - CRYPT_DES_MODE_CTR
185
- *
186
- * - CRYPT_DES_MODE_CFB
187
- *
188
- * - CRYPT_DES_MODE_OFB
189
- *
190
- * - CRYPT_DES_MODE_3CBC
191
- *
192
- * If not explicitly set, CRYPT_DES_MODE_CBC will be used.
193
- *
194
- * @see Crypt_DES::Crypt_DES()
195
- * @see Crypt_Base::Crypt_Base()
196
- * @param int $mode
197
- * @access public
198
- */
199
- function __construct($mode = CRYPT_MODE_CBC)
200
- {
201
- switch ($mode) {
202
- // In case of CRYPT_DES_MODE_3CBC, we init as CRYPT_DES_MODE_CBC
203
- // and additional flag us internally as 3CBC
204
- case CRYPT_DES_MODE_3CBC:
205
- parent::Crypt_Base(CRYPT_MODE_CBC);
206
- $this->mode_3cbc = true;
207
-
208
- // This three $des'es will do the 3CBC work (if $key > 64bits)
209
- $this->des = array(
210
- new Crypt_DES(CRYPT_MODE_CBC),
211
- new Crypt_DES(CRYPT_MODE_CBC),
212
- new Crypt_DES(CRYPT_MODE_CBC),
213
- );
214
-
215
- // we're going to be doing the padding, ourselves, so disable it in the Crypt_DES objects
216
- $this->des[0]->disablePadding();
217
- $this->des[1]->disablePadding();
218
- $this->des[2]->disablePadding();
219
- break;
220
- // If not 3CBC, we init as usual
221
- default:
222
- parent::__construct($mode);
223
- }
224
- }
225
-
226
- /**
227
- * PHP4 compatible Default Constructor.
228
- *
229
- * @see self::__construct()
230
- * @param int $mode
231
- * @access public
232
- */
233
- function Crypt_TripleDES($mode = CRYPT_MODE_CBC)
234
- {
235
- $this->__construct($mode);
236
- }
237
-
238
- /**
239
- * Test for engine validity
240
- *
241
- * This is mainly just a wrapper to set things up for Crypt_Base::isValidEngine()
242
- *
243
- * @see Crypt_Base::Crypt_Base()
244
- * @param int $engine
245
- * @access public
246
- * @return bool
247
- */
248
- function isValidEngine($engine)
249
- {
250
- if ($engine == CRYPT_ENGINE_OPENSSL) {
251
- $this->cipher_name_openssl_ecb = 'des-ede3';
252
- $mode = $this->_openssl_translate_mode();
253
- $this->cipher_name_openssl = $mode == 'ecb' ? 'des-ede3' : 'des-ede3-' . $mode;
254
- }
255
-
256
- return parent::isValidEngine($engine);
257
- }
258
-
259
- /**
260
- * Sets the initialization vector. (optional)
261
- *
262
- * SetIV is not required when CRYPT_DES_MODE_ECB is being used. If not explicitly set, it'll be assumed
263
- * to be all zero's.
264
- *
265
- * @see Crypt_Base::setIV()
266
- * @access public
267
- * @param string $iv
268
- */
269
- function setIV($iv)
270
- {
271
- parent::setIV($iv);
272
- if ($this->mode_3cbc) {
273
- $this->des[0]->setIV($iv);
274
- $this->des[1]->setIV($iv);
275
- $this->des[2]->setIV($iv);
276
- }
277
- }
278
-
279
- /**
280
- * Sets the key length.
281
- *
282
- * Valid key lengths are 64, 128 and 192
283
- *
284
- * @see Crypt_Base:setKeyLength()
285
- * @access public
286
- * @param int $length
287
- */
288
- function setKeyLength($length)
289
- {
290
- $length >>= 3;
291
- switch (true) {
292
- case $length <= 8:
293
- $this->key_length = 8;
294
- break;
295
- case $length <= 16:
296
- $this->key_length = 16;
297
- break;
298
- default:
299
- $this->key_length = 24;
300
- }
301
-
302
- parent::setKeyLength($length);
303
- }
304
-
305
- /**
306
- * Sets the key.
307
- *
308
- * Keys can be of any length. Triple DES, itself, can use 128-bit (eg. strlen($key) == 16) or
309
- * 192-bit (eg. strlen($key) == 24) keys. This function pads and truncates $key as appropriate.
310
- *
311
- * DES also requires that every eighth bit be a parity bit, however, we'll ignore that.
312
- *
313
- * If the key is not explicitly set, it'll be assumed to be all null bytes.
314
- *
315
- * @access public
316
- * @see Crypt_DES::setKey()
317
- * @see Crypt_Base::setKey()
318
- * @param string $key
319
- */
320
- function setKey($key)
321
- {
322
- $length = $this->explicit_key_length ? $this->key_length : strlen($key);
323
- if ($length > 8) {
324
- $key = str_pad(substr($key, 0, 24), 24, chr(0));
325
- // if $key is between 64 and 128-bits, use the first 64-bits as the last, per this:
326
- // http://php.net/function.mcrypt-encrypt#47973
327
- $key = $length <= 16 ? substr_replace($key, substr($key, 0, 8), 16) : substr($key, 0, 24);
328
- } else {
329
- $key = str_pad($key, 8, chr(0));
330
- }
331
- parent::setKey($key);
332
-
333
- // And in case of CRYPT_DES_MODE_3CBC:
334
- // if key <= 64bits we not need the 3 $des to work,
335
- // because we will then act as regular DES-CBC with just a <= 64bit key.
336
- // So only if the key > 64bits (> 8 bytes) we will call setKey() for the 3 $des.
337
- if ($this->mode_3cbc && $length > 8) {
338
- $this->des[0]->setKey(substr($key, 0, 8));
339
- $this->des[1]->setKey(substr($key, 8, 8));
340
- $this->des[2]->setKey(substr($key, 16, 8));
341
- }
342
- }
343
-
344
- /**
345
- * Encrypts a message.
346
- *
347
- * @see Crypt_Base::encrypt()
348
- * @access public
349
- * @param string $plaintext
350
- * @return string $cipertext
351
- */
352
- function encrypt($plaintext)
353
- {
354
- // parent::en/decrypt() is able to do all the work for all modes and keylengths,
355
- // except for: CRYPT_MODE_3CBC (inner chaining CBC) with a key > 64bits
356
-
357
- // if the key is smaller then 8, do what we'd normally do
358
- if ($this->mode_3cbc && strlen($this->key) > 8) {
359
- return $this->des[2]->encrypt(
360
- $this->des[1]->decrypt(
361
- $this->des[0]->encrypt(
362
- $this->_pad($plaintext)
363
- )
364
- )
365
- );
366
- }
367
-
368
- return parent::encrypt($plaintext);
369
- }
370
-
371
- /**
372
- * Decrypts a message.
373
- *
374
- * @see Crypt_Base::decrypt()
375
- * @access public
376
- * @param string $ciphertext
377
- * @return string $plaintext
378
- */
379
- function decrypt($ciphertext)
380
- {
381
- if ($this->mode_3cbc && strlen($this->key) > 8) {
382
- return $this->_unpad(
383
- $this->des[0]->decrypt(
384
- $this->des[1]->encrypt(
385
- $this->des[2]->decrypt(
386
- str_pad($ciphertext, (strlen($ciphertext) + 7) & 0xFFFFFFF8, "\0")
387
- )
388
- )
389
- )
390
- );
391
- }
392
-
393
- return parent::decrypt($ciphertext);
394
- }
395
-
396
- /**
397
- * Treat consecutive "packets" as if they are a continuous buffer.
398
- *
399
- * Say you have a 16-byte plaintext $plaintext. Using the default behavior, the two following code snippets
400
- * will yield different outputs:
401
- *
402
- * <code>
403
- * echo $des->encrypt(substr($plaintext, 0, 8));
404
- * echo $des->encrypt(substr($plaintext, 8, 8));
405
- * </code>
406
- * <code>
407
- * echo $des->encrypt($plaintext);
408
- * </code>
409
- *
410
- * The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates
411
- * another, as demonstrated with the following:
412
- *
413
- * <code>
414
- * $des->encrypt(substr($plaintext, 0, 8));
415
- * echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8)));
416
- * </code>
417
- * <code>
418
- * echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8)));
419
- * </code>
420
- *
421
- * With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different
422
- * outputs. The reason is due to the fact that the initialization vector's change after every encryption /
423
- * decryption round when the continuous buffer is enabled. When it's disabled, they remain constant.
424
- *
425
- * Put another way, when the continuous buffer is enabled, the state of the Crypt_DES() object changes after each
426
- * encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that
427
- * continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them),
428
- * however, they are also less intuitive and more likely to cause you problems.
429
- *
430
- * @see Crypt_Base::enableContinuousBuffer()
431
- * @see self::disableContinuousBuffer()
432
- * @access public
433
- */
434
- function enableContinuousBuffer()
435
- {
436
- parent::enableContinuousBuffer();
437
- if ($this->mode_3cbc) {
438
- $this->des[0]->enableContinuousBuffer();
439
- $this->des[1]->enableContinuousBuffer();
440
- $this->des[2]->enableContinuousBuffer();
441
- }
442
- }
443
-
444
- /**
445
- * Treat consecutive packets as if they are a discontinuous buffer.
446
- *
447
- * The default behavior.
448
- *
449
- * @see Crypt_Base::disableContinuousBuffer()
450
- * @see self::enableContinuousBuffer()
451
- * @access public
452
- */
453
- function disableContinuousBuffer()
454
- {
455
- parent::disableContinuousBuffer();
456
- if ($this->mode_3cbc) {
457
- $this->des[0]->disableContinuousBuffer();
458
- $this->des[1]->disableContinuousBuffer();
459
- $this->des[2]->disableContinuousBuffer();
460
- }
461
- }
462
-
463
- /**
464
- * Creates the key schedule
465
- *
466
- * @see Crypt_DES::_setupKey()
467
- * @see Crypt_Base::_setupKey()
468
- * @access private
469
- */
470
- function _setupKey()
471
- {
472
- switch (true) {
473
- // if $key <= 64bits we configure our internal pure-php cipher engine
474
- // to act as regular [1]DES, not as 3DES. mcrypt.so::tripledes does the same.
475
- case strlen($this->key) <= 8:
476
- $this->des_rounds = 1;
477
- break;
478
-
479
- // otherwise, if $key > 64bits, we configure our engine to work as 3DES.
480
- default:
481
- $this->des_rounds = 3;
482
-
483
- // (only) if 3CBC is used we have, of course, to setup the $des[0-2] keys also separately.
484
- if ($this->mode_3cbc) {
485
- $this->des[0]->_setupKey();
486
- $this->des[1]->_setupKey();
487
- $this->des[2]->_setupKey();
488
-
489
- // because $des[0-2] will, now, do all the work we can return here
490
- // not need unnecessary stress parent::_setupKey() with our, now unused, $key.
491
- return;
492
- }
493
- }
494
- // setup our key
495
- parent::_setupKey();
496
- }
497
-
498
- /**
499
- * Sets the internal crypt engine
500
- *
501
- * @see Crypt_Base::Crypt_Base()
502
- * @see Crypt_Base::setPreferredEngine()
503
- * @param int $engine
504
- * @access public
505
- * @return int
506
- */
507
- function setPreferredEngine($engine)
508
- {
509
- if ($this->mode_3cbc) {
510
- $this->des[0]->setPreferredEngine($engine);
511
- $this->des[1]->setPreferredEngine($engine);
512
- $this->des[2]->setPreferredEngine($engine);
513
- }
514
-
515
- return parent::setPreferredEngine($engine);
516
- }
517
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/phpseclib/Crypt/Twofish.php DELETED
@@ -1,881 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Pure-PHP implementation of Twofish.
5
- *
6
- * Uses mcrypt, if available, and an internal implementation, otherwise.
7
- *
8
- * PHP versions 4 and 5
9
- *
10
- * Useful resources are as follows:
11
- *
12
- * - {@link http://en.wikipedia.org/wiki/Twofish Wikipedia description of Twofish}
13
- *
14
- * Here's a short example of how to use this library:
15
- * <code>
16
- * <?php
17
- * include 'Crypt/Twofish.php';
18
- *
19
- * $twofish = new Crypt_Twofish();
20
- *
21
- * $twofish->setKey('12345678901234567890123456789012');
22
- *
23
- * $plaintext = str_repeat('a', 1024);
24
- *
25
- * echo $twofish->decrypt($twofish->encrypt($plaintext));
26
- * ?>
27
- * </code>
28
- *
29
- * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
30
- * of this software and associated documentation files (the "Software"), to deal
31
- * in the Software without restriction, including without limitation the rights
32
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
33
- * copies of the Software, and to permit persons to whom the Software is
34
- * furnished to do so, subject to the following conditions:
35
- *
36
- * The above copyright notice and this permission notice shall be included in
37
- * all copies or substantial portions of the Software.
38
- *
39
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
40
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
41
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
42
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
43
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
44
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
45
- * THE SOFTWARE.
46
- *
47
- * @category Crypt
48
- * @package Crypt_Twofish
49
- * @author Jim Wigginton <terrafrost@php.net>
50
- * @author Hans-Juergen Petrich <petrich@tronic-media.com>
51
- * @copyright 2007 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_Base
58
- *
59
- * Base cipher class
60
- */
61
- if (!class_exists('Crypt_Base')) {
62
- include_once 'Base.php';
63
- }
64
-
65
- /**#@+
66
- * @access public
67
- * @see self::encrypt()
68
- * @see self::decrypt()
69
- */
70
- /**
71
- * Encrypt / decrypt using the Counter mode.
72
- *
73
- * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
74
- *
75
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
76
- */
77
- define('CRYPT_TWOFISH_MODE_CTR', CRYPT_MODE_CTR);
78
- /**
79
- * Encrypt / decrypt using the Electronic Code Book mode.
80
- *
81
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
82
- */
83
- define('CRYPT_TWOFISH_MODE_ECB', CRYPT_MODE_ECB);
84
- /**
85
- * Encrypt / decrypt using the Code Book Chaining mode.
86
- *
87
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
88
- */
89
- define('CRYPT_TWOFISH_MODE_CBC', CRYPT_MODE_CBC);
90
- /**
91
- * Encrypt / decrypt using the Cipher Feedback mode.
92
- *
93
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
94
- */
95
- define('CRYPT_TWOFISH_MODE_CFB', CRYPT_MODE_CFB);
96
- /**
97
- * Encrypt / decrypt using the Cipher Feedback mode.
98
- *
99
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
100
- */
101
- define('CRYPT_TWOFISH_MODE_OFB', CRYPT_MODE_OFB);
102
- /**#@-*/
103
-
104
- /**
105
- * Pure-PHP implementation of Twofish.
106
- *
107
- * @package Crypt_Twofish
108
- * @author Jim Wigginton <terrafrost@php.net>
109
- * @author Hans-Juergen Petrich <petrich@tronic-media.com>
110
- * @access public
111
- */
112
- class Crypt_Twofish extends Crypt_Base
113
- {
114
- /**
115
- * The namespace used by the cipher for its constants.
116
- *
117
- * @see Crypt_Base::const_namespace
118
- * @var string
119
- * @access private
120
- */
121
- var $const_namespace = 'TWOFISH';
122
-
123
- /**
124
- * The mcrypt specific name of the cipher
125
- *
126
- * @see Crypt_Base::cipher_name_mcrypt
127
- * @var string
128
- * @access private
129
- */
130
- var $cipher_name_mcrypt = 'twofish';
131
-
132
- /**
133
- * Optimizing value while CFB-encrypting
134
- *
135
- * @see Crypt_Base::cfb_init_len
136
- * @var int
137
- * @access private
138
- */
139
- var $cfb_init_len = 800;
140
-
141
- /**
142
- * Q-Table
143
- *
144
- * @var array
145
- * @access private
146
- */
147
- var $q0 = array(
148
- 0xA9, 0x67, 0xB3, 0xE8, 0x04, 0xFD, 0xA3, 0x76,
149
- 0x9A, 0x92, 0x80, 0x78, 0xE4, 0xDD, 0xD1, 0x38,
150
- 0x0D, 0xC6, 0x35, 0x98, 0x18, 0xF7, 0xEC, 0x6C,
151
- 0x43, 0x75, 0x37, 0x26, 0xFA, 0x13, 0x94, 0x48,
152
- 0xF2, 0xD0, 0x8B, 0x30, 0x84, 0x54, 0xDF, 0x23,
153
- 0x19, 0x5B, 0x3D, 0x59, 0xF3, 0xAE, 0xA2, 0x82,
154
- 0x63, 0x01, 0x83, 0x2E, 0xD9, 0x51, 0x9B, 0x7C,
155
- 0xA6, 0xEB, 0xA5, 0xBE, 0x16, 0x0C, 0xE3, 0x61,
156
- 0xC0, 0x8C, 0x3A, 0xF5, 0x73, 0x2C, 0x25, 0x0B,
157
- 0xBB, 0x4E, 0x89, 0x6B, 0x53, 0x6A, 0xB4, 0xF1,
158
- 0xE1, 0xE6, 0xBD, 0x45, 0xE2, 0xF4, 0xB6, 0x66,
159
- 0xCC, 0x95, 0x03, 0x56, 0xD4, 0x1C, 0x1E, 0xD7,
160
- 0xFB, 0xC3, 0x8E, 0xB5, 0xE9, 0xCF, 0xBF, 0xBA,
161
- 0xEA, 0x77, 0x39, 0xAF, 0x33, 0xC9, 0x62, 0x71,
162
- 0x81, 0x79, 0x09, 0xAD, 0x24, 0xCD, 0xF9, 0xD8,
163
- 0xE5, 0xC5, 0xB9, 0x4D, 0x44, 0x08, 0x86, 0xE7,
164
- 0xA1, 0x1D, 0xAA, 0xED, 0x06, 0x70, 0xB2, 0xD2,
165
- 0x41, 0x7B, 0xA0, 0x11, 0x31, 0xC2, 0x27, 0x90,
166
- 0x20, 0xF6, 0x60, 0xFF, 0x96, 0x5C, 0xB1, 0xAB,
167
- 0x9E, 0x9C, 0x52, 0x1B, 0x5F, 0x93, 0x0A, 0xEF,
168
- 0x91, 0x85, 0x49, 0xEE, 0x2D, 0x4F, 0x8F, 0x3B,
169
- 0x47, 0x87, 0x6D, 0x46, 0xD6, 0x3E, 0x69, 0x64,
170
- 0x2A, 0xCE, 0xCB, 0x2F, 0xFC, 0x97, 0x05, 0x7A,
171
- 0xAC, 0x7F, 0xD5, 0x1A, 0x4B, 0x0E, 0xA7, 0x5A,
172
- 0x28, 0x14, 0x3F, 0x29, 0x88, 0x3C, 0x4C, 0x02,
173
- 0xB8, 0xDA, 0xB0, 0x17, 0x55, 0x1F, 0x8A, 0x7D,
174
- 0x57, 0xC7, 0x8D, 0x74, 0xB7, 0xC4, 0x9F, 0x72,
175
- 0x7E, 0x15, 0x22, 0x12, 0x58, 0x07, 0x99, 0x34,
176
- 0x6E, 0x50, 0xDE, 0x68, 0x65, 0xBC, 0xDB, 0xF8,
177
- 0xC8, 0xA8, 0x2B, 0x40, 0xDC, 0xFE, 0x32, 0xA4,
178
- 0xCA, 0x10, 0x21, 0xF0, 0xD3, 0x5D, 0x0F, 0x00,
179
- 0x6F, 0x9D, 0x36, 0x42, 0x4A, 0x5E, 0xC1, 0xE0
180
- );
181
-
182
- /**
183
- * Q-Table
184
- *
185
- * @var array
186
- * @access private
187
- */
188
- var $q1 = array(
189
- 0x75, 0xF3, 0xC6, 0xF4, 0xDB, 0x7B, 0xFB, 0xC8,
190
- 0x4A, 0xD3, 0xE6, 0x6B, 0x45, 0x7D, 0xE8, 0x4B,
191
- 0xD6, 0x32, 0xD8, 0xFD, 0x37, 0x71, 0xF1, 0xE1,
192
- 0x30, 0x0F, 0xF8, 0x1B, 0x87, 0xFA, 0x06, 0x3F,
193
- 0x5E, 0xBA, 0xAE, 0x5B, 0x8A, 0x00, 0xBC, 0x9D,
194
- 0x6D, 0xC1, 0xB1, 0x0E, 0x80, 0x5D, 0xD2, 0xD5,
195
- 0xA0, 0x84, 0x07, 0x14, 0xB5, 0x90, 0x2C, 0xA3,
196
- 0xB2, 0x73, 0x4C, 0x54, 0x92, 0x74, 0x36, 0x51,
197
- 0x38, 0xB0, 0xBD, 0x5A, 0xFC, 0x60, 0x62, 0x96,
198
- 0x6C, 0x42, 0xF7, 0x10, 0x7C, 0x28, 0x27, 0x8C,
199
- 0x13, 0x95, 0x9C, 0xC7, 0x24, 0x46, 0x3B, 0x70,
200
- 0xCA, 0xE3, 0x85, 0xCB, 0x11, 0xD0, 0x93, 0xB8,
201
- 0xA6, 0x83, 0x20, 0xFF, 0x9F, 0x77, 0xC3, 0xCC,
202
- 0x03, 0x6F, 0x08, 0xBF, 0x40, 0xE7, 0x2B, 0xE2,
203
- 0x79, 0x0C, 0xAA, 0x82, 0x41, 0x3A, 0xEA, 0xB9,
204
- 0xE4, 0x9A, 0xA4, 0x97, 0x7E, 0xDA, 0x7A, 0x17,
205
- 0x66, 0x94, 0xA1, 0x1D, 0x3D, 0xF0, 0xDE, 0xB3,
206
- 0x0B, 0x72, 0xA7, 0x1C, 0xEF, 0xD1, 0x53, 0x3E,
207
- 0x8F, 0x33, 0x26, 0x5F, 0xEC, 0x76, 0x2A, 0x49,
208
- 0x81, 0x88, 0xEE, 0x21, 0xC4, 0x1A, 0xEB, 0xD9,
209
- 0xC5, 0x39, 0x99, 0xCD, 0xAD, 0x31, 0x8B, 0x01,
210
- 0x18, 0x23, 0xDD, 0x1F, 0x4E, 0x2D, 0xF9, 0x48,
211
- 0x4F, 0xF2, 0x65, 0x8E, 0x78, 0x5C, 0x58, 0x19,
212
- 0x8D, 0xE5, 0x98, 0x57, 0x67, 0x7F, 0x05, 0x64,
213
- 0xAF, 0x63, 0xB6, 0xFE, 0xF5, 0xB7, 0x3C, 0xA5,
214
- 0xCE, 0xE9, 0x68, 0x44, 0xE0, 0x4D, 0x43, 0x69,
215
- 0x29, 0x2E, 0xAC, 0x15, 0x59, 0xA8, 0x0A, 0x9E,
216
- 0x6E, 0x47, 0xDF, 0x34, 0x35, 0x6A, 0xCF, 0xDC,
217
- 0x22, 0xC9, 0xC0, 0x9B, 0x89, 0xD4, 0xED, 0xAB,
218
- 0x12, 0xA2, 0x0D, 0x52, 0xBB, 0x02, 0x2F, 0xA9,
219
- 0xD7, 0x61, 0x1E, 0xB4, 0x50, 0x04, 0xF6, 0xC2,
220
- 0x16, 0x25, 0x86, 0x56, 0x55, 0x09, 0xBE, 0x91
221
- );
222
-
223
- /**
224
- * M-Table
225
- *
226
- * @var array
227
- * @access private
228
- */
229
- var $m0 = array(
230
- 0xBCBC3275, 0xECEC21F3, 0x202043C6, 0xB3B3C9F4, 0xDADA03DB, 0x02028B7B, 0xE2E22BFB, 0x9E9EFAC8,
231
- 0xC9C9EC4A, 0xD4D409D3, 0x18186BE6, 0x1E1E9F6B, 0x98980E45, 0xB2B2387D, 0xA6A6D2E8, 0x2626B74B,
232
- 0x3C3C57D6, 0x93938A32, 0x8282EED8, 0x525298FD, 0x7B7BD437, 0xBBBB3771, 0x5B5B97F1, 0x474783E1,
233
- 0x24243C30, 0x5151E20F, 0xBABAC6F8, 0x4A4AF31B, 0xBFBF4887, 0x0D0D70FA, 0xB0B0B306, 0x7575DE3F,
234
- 0xD2D2FD5E, 0x7D7D20BA, 0x666631AE, 0x3A3AA35B, 0x59591C8A, 0x00000000, 0xCDCD93BC, 0x1A1AE09D,
235
- 0xAEAE2C6D, 0x7F7FABC1, 0x2B2BC7B1, 0xBEBEB90E, 0xE0E0A080, 0x8A8A105D, 0x3B3B52D2, 0x6464BAD5,
236
- 0xD8D888A0, 0xE7E7A584, 0x5F5FE807, 0x1B1B1114, 0x2C2CC2B5, 0xFCFCB490, 0x3131272C, 0x808065A3,
237
- 0x73732AB2, 0x0C0C8173, 0x79795F4C, 0x6B6B4154, 0x4B4B0292, 0x53536974, 0x94948F36, 0x83831F51,
238
- 0x2A2A3638, 0xC4C49CB0, 0x2222C8BD, 0xD5D5F85A, 0xBDBDC3FC, 0x48487860, 0xFFFFCE62, 0x4C4C0796,
239
- 0x4141776C, 0xC7C7E642, 0xEBEB24F7, 0x1C1C1410, 0x5D5D637C, 0x36362228, 0x6767C027, 0xE9E9AF8C,
240
- 0x4444F913, 0x1414EA95, 0xF5F5BB9C, 0xCFCF18C7, 0x3F3F2D24, 0xC0C0E346, 0x7272DB3B, 0x54546C70,
241
- 0x29294CCA, 0xF0F035E3, 0x0808FE85, 0xC6C617CB, 0xF3F34F11, 0x8C8CE4D0, 0xA4A45993, 0xCACA96B8,
242
- 0x68683BA6, 0xB8B84D83, 0x38382820, 0xE5E52EFF, 0xADAD569F, 0x0B0B8477, 0xC8C81DC3, 0x9999FFCC,
243
- 0x5858ED03, 0x19199A6F, 0x0E0E0A08, 0x95957EBF, 0x70705040, 0xF7F730E7, 0x6E6ECF2B, 0x1F1F6EE2,
244
- 0xB5B53D79, 0x09090F0C, 0x616134AA, 0x57571682, 0x9F9F0B41, 0x9D9D803A, 0x111164EA, 0x2525CDB9,
245
- 0xAFAFDDE4, 0x4545089A, 0xDFDF8DA4, 0xA3A35C97, 0xEAEAD57E, 0x353558DA, 0xEDEDD07A, 0x4343FC17,
246
- 0xF8F8CB66, 0xFBFBB194, 0x3737D3A1, 0xFAFA401D, 0xC2C2683D, 0xB4B4CCF0, 0x32325DDE, 0x9C9C71B3,
247
- 0x5656E70B, 0xE3E3DA72, 0x878760A7, 0x15151B1C, 0xF9F93AEF, 0x6363BFD1, 0x3434A953, 0x9A9A853E,
248
- 0xB1B1428F, 0x7C7CD133, 0x88889B26, 0x3D3DA65F, 0xA1A1D7EC, 0xE4E4DF76, 0x8181942A, 0x91910149,
249
- 0x0F0FFB81, 0xEEEEAA88, 0x161661EE, 0xD7D77321, 0x9797F5C4, 0xA5A5A81A, 0xFEFE3FEB, 0x6D6DB5D9,
250
- 0x7878AEC5, 0xC5C56D39, 0x1D1DE599, 0x7676A4CD, 0x3E3EDCAD, 0xCBCB6731, 0xB6B6478B, 0xEFEF5B01,
251
- 0x12121E18, 0x6060C523, 0x6A6AB0DD, 0x4D4DF61F, 0xCECEE94E, 0xDEDE7C2D, 0x55559DF9, 0x7E7E5A48,
252
- 0x2121B24F, 0x03037AF2, 0xA0A02665, 0x5E5E198E, 0x5A5A6678, 0x65654B5C, 0x62624E58, 0xFDFD4519,
253
- 0x0606F48D, 0x404086E5, 0xF2F2BE98, 0x3333AC57, 0x17179067, 0x05058E7F, 0xE8E85E05, 0x4F4F7D64,
254
- 0x89896AAF, 0x10109563, 0x74742FB6, 0x0A0A75FE, 0x5C5C92F5, 0x9B9B74B7, 0x2D2D333C, 0x3030D6A5,
255
- 0x2E2E49CE, 0x494989E9, 0x46467268, 0x77775544, 0xA8A8D8E0, 0x9696044D, 0x2828BD43, 0xA9A92969,
256
- 0xD9D97929, 0x8686912E, 0xD1D187AC, 0xF4F44A15, 0x8D8D1559, 0xD6D682A8, 0xB9B9BC0A, 0x42420D9E,
257
- 0xF6F6C16E, 0x2F2FB847, 0xDDDD06DF, 0x23233934, 0xCCCC6235, 0xF1F1C46A, 0xC1C112CF, 0x8585EBDC,
258
- 0x8F8F9E22, 0x7171A1C9, 0x9090F0C0, 0xAAAA539B, 0x0101F189, 0x8B8BE1D4, 0x4E4E8CED, 0x8E8E6FAB,
259
- 0xABABA212, 0x6F6F3EA2, 0xE6E6540D, 0xDBDBF252, 0x92927BBB, 0xB7B7B602, 0x6969CA2F, 0x3939D9A9,
260
- 0xD3D30CD7, 0xA7A72361, 0xA2A2AD1E, 0xC3C399B4, 0x6C6C4450, 0x07070504, 0x04047FF6, 0x272746C2,
261
- 0xACACA716, 0xD0D07625, 0x50501386, 0xDCDCF756, 0x84841A55, 0xE1E15109, 0x7A7A25BE, 0x1313EF91
262
- );
263
-
264
- /**
265
- * M-Table
266
- *
267
- * @var array
268
- * @access private
269
- */
270
- var $m1 = array(
271
- 0xA9D93939, 0x67901717, 0xB3719C9C, 0xE8D2A6A6, 0x04050707, 0xFD985252, 0xA3658080, 0x76DFE4E4,
272
- 0x9A084545, 0x92024B4B, 0x80A0E0E0, 0x78665A5A, 0xE4DDAFAF, 0xDDB06A6A, 0xD1BF6363, 0x38362A2A,
273
- 0x0D54E6E6, 0xC6432020, 0x3562CCCC, 0x98BEF2F2, 0x181E1212, 0xF724EBEB, 0xECD7A1A1, 0x6C774141,
274
- 0x43BD2828, 0x7532BCBC, 0x37D47B7B, 0x269B8888, 0xFA700D0D, 0x13F94444, 0x94B1FBFB, 0x485A7E7E,
275
- 0xF27A0303, 0xD0E48C8C, 0x8B47B6B6, 0x303C2424, 0x84A5E7E7, 0x54416B6B, 0xDF06DDDD, 0x23C56060,
276
- 0x1945FDFD, 0x5BA33A3A, 0x3D68C2C2, 0x59158D8D, 0xF321ECEC, 0xAE316666, 0xA23E6F6F, 0x82165757,
277
- 0x63951010, 0x015BEFEF, 0x834DB8B8, 0x2E918686, 0xD9B56D6D, 0x511F8383, 0x9B53AAAA, 0x7C635D5D,
278
- 0xA63B6868, 0xEB3FFEFE, 0xA5D63030, 0xBE257A7A, 0x16A7ACAC, 0x0C0F0909, 0xE335F0F0, 0x6123A7A7,
279
- 0xC0F09090, 0x8CAFE9E9, 0x3A809D9D, 0xF5925C5C, 0x73810C0C, 0x2C273131, 0x2576D0D0, 0x0BE75656,
280
- 0xBB7B9292, 0x4EE9CECE, 0x89F10101, 0x6B9F1E1E, 0x53A93434, 0x6AC4F1F1, 0xB499C3C3, 0xF1975B5B,
281
- 0xE1834747, 0xE66B1818, 0xBDC82222, 0x450E9898, 0xE26E1F1F, 0xF4C9B3B3, 0xB62F7474, 0x66CBF8F8,
282
- 0xCCFF9999, 0x95EA1414, 0x03ED5858, 0x56F7DCDC, 0xD4E18B8B, 0x1C1B1515, 0x1EADA2A2, 0xD70CD3D3,
283
- 0xFB2BE2E2, 0xC31DC8C8, 0x8E195E5E, 0xB5C22C2C, 0xE9894949, 0xCF12C1C1, 0xBF7E9595, 0xBA207D7D,
284
- 0xEA641111, 0x77840B0B, 0x396DC5C5, 0xAF6A8989, 0x33D17C7C, 0xC9A17171, 0x62CEFFFF, 0x7137BBBB,
285
- 0x81FB0F0F, 0x793DB5B5, 0x0951E1E1, 0xADDC3E3E, 0x242D3F3F, 0xCDA47676, 0xF99D5555, 0xD8EE8282,
286
- 0xE5864040, 0xC5AE7878, 0xB9CD2525, 0x4D049696, 0x44557777, 0x080A0E0E, 0x86135050, 0xE730F7F7,
287
- 0xA1D33737, 0x1D40FAFA, 0xAA346161, 0xED8C4E4E, 0x06B3B0B0, 0x706C5454, 0xB22A7373, 0xD2523B3B,
288
- 0x410B9F9F, 0x7B8B0202, 0xA088D8D8, 0x114FF3F3, 0x3167CBCB, 0xC2462727, 0x27C06767, 0x90B4FCFC,
289
- 0x20283838, 0xF67F0404, 0x60784848, 0xFF2EE5E5, 0x96074C4C, 0x5C4B6565, 0xB1C72B2B, 0xAB6F8E8E,
290
- 0x9E0D4242, 0x9CBBF5F5, 0x52F2DBDB, 0x1BF34A4A, 0x5FA63D3D, 0x9359A4A4, 0x0ABCB9B9, 0xEF3AF9F9,
291
- 0x91EF1313, 0x85FE0808, 0x49019191, 0xEE611616, 0x2D7CDEDE, 0x4FB22121, 0x8F42B1B1, 0x3BDB7272,
292
- 0x47B82F2F, 0x8748BFBF, 0x6D2CAEAE, 0x46E3C0C0, 0xD6573C3C, 0x3E859A9A, 0x6929A9A9, 0x647D4F4F,
293
- 0x2A948181, 0xCE492E2E, 0xCB17C6C6, 0x2FCA6969, 0xFCC3BDBD, 0x975CA3A3, 0x055EE8E8, 0x7AD0EDED,
294
- 0xAC87D1D1, 0x7F8E0505, 0xD5BA6464, 0x1AA8A5A5, 0x4BB72626, 0x0EB9BEBE, 0xA7608787, 0x5AF8D5D5,
295
- 0x28223636, 0x14111B1B, 0x3FDE7575, 0x2979D9D9, 0x88AAEEEE, 0x3C332D2D, 0x4C5F7979, 0x02B6B7B7,
296
- 0xB896CACA, 0xDA583535, 0xB09CC4C4, 0x17FC4343, 0x551A8484, 0x1FF64D4D, 0x8A1C5959, 0x7D38B2B2,
297
- 0x57AC3333, 0xC718CFCF, 0x8DF40606, 0x74695353, 0xB7749B9B, 0xC4F59797, 0x9F56ADAD, 0x72DAE3E3,
298
- 0x7ED5EAEA, 0x154AF4F4, 0x229E8F8F, 0x12A2ABAB, 0x584E6262, 0x07E85F5F, 0x99E51D1D, 0x34392323,
299
- 0x6EC1F6F6, 0x50446C6C, 0xDE5D3232, 0x68724646, 0x6526A0A0, 0xBC93CDCD, 0xDB03DADA, 0xF8C6BABA,
300
- 0xC8FA9E9E, 0xA882D6D6, 0x2BCF6E6E, 0x40507070, 0xDCEB8585, 0xFE750A0A, 0x328A9393, 0xA48DDFDF,
301
- 0xCA4C2929, 0x10141C1C, 0x2173D7D7, 0xF0CCB4B4, 0xD309D4D4, 0x5D108A8A, 0x0FE25151, 0x00000000,
302
- 0x6F9A1919, 0x9DE01A1A, 0x368F9494, 0x42E6C7C7, 0x4AECC9C9, 0x5EFDD2D2, 0xC1AB7F7F, 0xE0D8A8A8
303
- );
304
-
305
- /**
306
- * M-Table
307
- *
308
- * @var array
309
- * @access private
310
- */
311
- var $m2 = array(
312
- 0xBC75BC32, 0xECF3EC21, 0x20C62043, 0xB3F4B3C9, 0xDADBDA03, 0x027B028B, 0xE2FBE22B, 0x9EC89EFA,
313
- 0xC94AC9EC, 0xD4D3D409, 0x18E6186B, 0x1E6B1E9F, 0x9845980E, 0xB27DB238, 0xA6E8A6D2, 0x264B26B7,
314
- 0x3CD63C57, 0x9332938A, 0x82D882EE, 0x52FD5298, 0x7B377BD4, 0xBB71BB37, 0x5BF15B97, 0x47E14783,
315
- 0x2430243C, 0x510F51E2, 0xBAF8BAC6, 0x4A1B4AF3, 0xBF87BF48, 0x0DFA0D70, 0xB006B0B3, 0x753F75DE,
316
- 0xD25ED2FD, 0x7DBA7D20, 0x66AE6631, 0x3A5B3AA3, 0x598A591C, 0x00000000, 0xCDBCCD93, 0x1A9D1AE0,
317
- 0xAE6DAE2C, 0x7FC17FAB, 0x2BB12BC7, 0xBE0EBEB9, 0xE080E0A0, 0x8A5D8A10, 0x3BD23B52, 0x64D564BA,
318
- 0xD8A0D888, 0xE784E7A5, 0x5F075FE8, 0x1B141B11, 0x2CB52CC2, 0xFC90FCB4, 0x312C3127, 0x80A38065,
319
- 0x73B2732A, 0x0C730C81, 0x794C795F, 0x6B546B41, 0x4B924B02, 0x53745369, 0x9436948F, 0x8351831F,
320
- 0x2A382A36, 0xC4B0C49C, 0x22BD22C8, 0xD55AD5F8, 0xBDFCBDC3, 0x48604878, 0xFF62FFCE, 0x4C964C07,
321
- 0x416C4177, 0xC742C7E6, 0xEBF7EB24, 0x1C101C14, 0x5D7C5D63, 0x36283622, 0x672767C0, 0xE98CE9AF,
322
- 0x441344F9, 0x149514EA, 0xF59CF5BB, 0xCFC7CF18, 0x3F243F2D, 0xC046C0E3, 0x723B72DB, 0x5470546C,
323
- 0x29CA294C, 0xF0E3F035, 0x088508FE, 0xC6CBC617, 0xF311F34F, 0x8CD08CE4, 0xA493A459, 0xCAB8CA96,
324
- 0x68A6683B, 0xB883B84D, 0x38203828, 0xE5FFE52E, 0xAD9FAD56, 0x0B770B84, 0xC8C3C81D, 0x99CC99FF,
325
- 0x580358ED, 0x196F199A, 0x0E080E0A, 0x95BF957E, 0x70407050, 0xF7E7F730, 0x6E2B6ECF, 0x1FE21F6E,
326
- 0xB579B53D, 0x090C090F, 0x61AA6134, 0x57825716, 0x9F419F0B, 0x9D3A9D80, 0x11EA1164, 0x25B925CD,
327
- 0xAFE4AFDD, 0x459A4508, 0xDFA4DF8D, 0xA397A35C, 0xEA7EEAD5, 0x35DA3558, 0xED7AEDD0, 0x431743FC,
328
- 0xF866F8CB, 0xFB94FBB1, 0x37A137D3, 0xFA1DFA40, 0xC23DC268, 0xB4F0B4CC, 0x32DE325D, 0x9CB39C71,
329
- 0x560B56E7, 0xE372E3DA, 0x87A78760, 0x151C151B, 0xF9EFF93A, 0x63D163BF, 0x345334A9, 0x9A3E9A85,
330
- 0xB18FB142, 0x7C337CD1, 0x8826889B, 0x3D5F3DA6, 0xA1ECA1D7, 0xE476E4DF, 0x812A8194, 0x91499101,
331
- 0x0F810FFB, 0xEE88EEAA, 0x16EE1661, 0xD721D773, 0x97C497F5, 0xA51AA5A8, 0xFEEBFE3F, 0x6DD96DB5,
332
- 0x78C578AE, 0xC539C56D, 0x1D991DE5, 0x76CD76A4, 0x3EAD3EDC, 0xCB31CB67, 0xB68BB647, 0xEF01EF5B,
333
- 0x1218121E, 0x602360C5, 0x6ADD6AB0, 0x4D1F4DF6, 0xCE4ECEE9, 0xDE2DDE7C, 0x55F9559D, 0x7E487E5A,
334
- 0x214F21B2, 0x03F2037A, 0xA065A026, 0x5E8E5E19, 0x5A785A66, 0x655C654B, 0x6258624E, 0xFD19FD45,
335
- 0x068D06F4, 0x40E54086, 0xF298F2BE, 0x335733AC, 0x17671790, 0x057F058E, 0xE805E85E, 0x4F644F7D,
336
- 0x89AF896A, 0x10631095, 0x74B6742F, 0x0AFE0A75, 0x5CF55C92, 0x9BB79B74, 0x2D3C2D33, 0x30A530D6,
337
- 0x2ECE2E49, 0x49E94989, 0x46684672, 0x77447755, 0xA8E0A8D8, 0x964D9604, 0x284328BD, 0xA969A929,
338
- 0xD929D979, 0x862E8691, 0xD1ACD187, 0xF415F44A, 0x8D598D15, 0xD6A8D682, 0xB90AB9BC, 0x429E420D,
339
- 0xF66EF6C1, 0x2F472FB8, 0xDDDFDD06, 0x23342339, 0xCC35CC62, 0xF16AF1C4, 0xC1CFC112, 0x85DC85EB,
340
- 0x8F228F9E, 0x71C971A1, 0x90C090F0, 0xAA9BAA53, 0x018901F1, 0x8BD48BE1, 0x4EED4E8C, 0x8EAB8E6F,
341
- 0xAB12ABA2, 0x6FA26F3E, 0xE60DE654, 0xDB52DBF2, 0x92BB927B, 0xB702B7B6, 0x692F69CA, 0x39A939D9,
342
- 0xD3D7D30C, 0xA761A723, 0xA21EA2AD, 0xC3B4C399, 0x6C506C44, 0x07040705, 0x04F6047F, 0x27C22746,
343
- 0xAC16ACA7, 0xD025D076, 0x50865013, 0xDC56DCF7, 0x8455841A, 0xE109E151, 0x7ABE7A25, 0x139113EF
344
- );
345
-
346
- /**
347
- * M-Table
348
- *
349
- * @var array
350
- * @access private
351
- */
352
- var $m3 = array(
353
- 0xD939A9D9, 0x90176790, 0x719CB371, 0xD2A6E8D2, 0x05070405, 0x9852FD98, 0x6580A365, 0xDFE476DF,
354
- 0x08459A08, 0x024B9202, 0xA0E080A0, 0x665A7866, 0xDDAFE4DD, 0xB06ADDB0, 0xBF63D1BF, 0x362A3836,
355
- 0x54E60D54, 0x4320C643, 0x62CC3562, 0xBEF298BE, 0x1E12181E, 0x24EBF724, 0xD7A1ECD7, 0x77416C77,
356
- 0xBD2843BD, 0x32BC7532, 0xD47B37D4, 0x9B88269B, 0x700DFA70, 0xF94413F9, 0xB1FB94B1, 0x5A7E485A,
357
- 0x7A03F27A, 0xE48CD0E4, 0x47B68B47, 0x3C24303C, 0xA5E784A5, 0x416B5441, 0x06DDDF06, 0xC56023C5,
358
- 0x45FD1945, 0xA33A5BA3, 0x68C23D68, 0x158D5915, 0x21ECF321, 0x3166AE31, 0x3E6FA23E, 0x16578216,
359
- 0x95106395, 0x5BEF015B, 0x4DB8834D, 0x91862E91, 0xB56DD9B5, 0x1F83511F, 0x53AA9B53, 0x635D7C63,
360
- 0x3B68A63B, 0x3FFEEB3F, 0xD630A5D6, 0x257ABE25, 0xA7AC16A7, 0x0F090C0F, 0x35F0E335, 0x23A76123,
361
- 0xF090C0F0, 0xAFE98CAF, 0x809D3A80, 0x925CF592, 0x810C7381, 0x27312C27, 0x76D02576, 0xE7560BE7,
362
- 0x7B92BB7B, 0xE9CE4EE9, 0xF10189F1, 0x9F1E6B9F, 0xA93453A9, 0xC4F16AC4, 0x99C3B499, 0x975BF197,
363
- 0x8347E183, 0x6B18E66B, 0xC822BDC8, 0x0E98450E, 0x6E1FE26E, 0xC9B3F4C9, 0x2F74B62F, 0xCBF866CB,
364
- 0xFF99CCFF, 0xEA1495EA, 0xED5803ED, 0xF7DC56F7, 0xE18BD4E1, 0x1B151C1B, 0xADA21EAD, 0x0CD3D70C,
365
- 0x2BE2FB2B, 0x1DC8C31D, 0x195E8E19, 0xC22CB5C2, 0x8949E989, 0x12C1CF12, 0x7E95BF7E, 0x207DBA20,
366
- 0x6411EA64, 0x840B7784, 0x6DC5396D, 0x6A89AF6A, 0xD17C33D1, 0xA171C9A1, 0xCEFF62CE, 0x37BB7137,
367
- 0xFB0F81FB, 0x3DB5793D, 0x51E10951, 0xDC3EADDC, 0x2D3F242D, 0xA476CDA4, 0x9D55F99D, 0xEE82D8EE,
368
- 0x8640E586, 0xAE78C5AE, 0xCD25B9CD, 0x04964D04, 0x55774455, 0x0A0E080A, 0x13508613, 0x30F7E730,
369
- 0xD337A1D3, 0x40FA1D40, 0x3461AA34, 0x8C4EED8C, 0xB3B006B3, 0x6C54706C, 0x2A73B22A, 0x523BD252,
370
- 0x0B9F410B, 0x8B027B8B, 0x88D8A088, 0x4FF3114F, 0x67CB3167, 0x4627C246, 0xC06727C0, 0xB4FC90B4,
371
- 0x28382028, 0x7F04F67F, 0x78486078, 0x2EE5FF2E, 0x074C9607, 0x4B655C4B, 0xC72BB1C7, 0x6F8EAB6F,
372
- 0x0D429E0D, 0xBBF59CBB, 0xF2DB52F2, 0xF34A1BF3, 0xA63D5FA6, 0x59A49359, 0xBCB90ABC, 0x3AF9EF3A,
373
- 0xEF1391EF, 0xFE0885FE, 0x01914901, 0x6116EE61, 0x7CDE2D7C, 0xB2214FB2, 0x42B18F42, 0xDB723BDB,
374
- 0xB82F47B8, 0x48BF8748, 0x2CAE6D2C, 0xE3C046E3, 0x573CD657, 0x859A3E85, 0x29A96929, 0x7D4F647D,
375
- 0x94812A94, 0x492ECE49, 0x17C6CB17, 0xCA692FCA, 0xC3BDFCC3, 0x5CA3975C, 0x5EE8055E, 0xD0ED7AD0,
376
- 0x87D1AC87, 0x8E057F8E, 0xBA64D5BA, 0xA8A51AA8, 0xB7264BB7, 0xB9BE0EB9, 0x6087A760, 0xF8D55AF8,
377
- 0x22362822, 0x111B1411, 0xDE753FDE, 0x79D92979, 0xAAEE88AA, 0x332D3C33, 0x5F794C5F, 0xB6B702B6,
378
- 0x96CAB896, 0x5835DA58, 0x9CC4B09C, 0xFC4317FC, 0x1A84551A, 0xF64D1FF6, 0x1C598A1C, 0x38B27D38,
379
- 0xAC3357AC, 0x18CFC718, 0xF4068DF4, 0x69537469, 0x749BB774, 0xF597C4F5, 0x56AD9F56, 0xDAE372DA,
380
- 0xD5EA7ED5, 0x4AF4154A, 0x9E8F229E, 0xA2AB12A2, 0x4E62584E, 0xE85F07E8, 0xE51D99E5, 0x39233439,
381
- 0xC1F66EC1, 0x446C5044, 0x5D32DE5D, 0x72466872, 0x26A06526, 0x93CDBC93, 0x03DADB03, 0xC6BAF8C6,
382
- 0xFA9EC8FA, 0x82D6A882, 0xCF6E2BCF, 0x50704050, 0xEB85DCEB, 0x750AFE75, 0x8A93328A, 0x8DDFA48D,
383
- 0x4C29CA4C, 0x141C1014, 0x73D72173, 0xCCB4F0CC, 0x09D4D309, 0x108A5D10, 0xE2510FE2, 0x00000000,
384
- 0x9A196F9A, 0xE01A9DE0, 0x8F94368F, 0xE6C742E6, 0xECC94AEC, 0xFDD25EFD, 0xAB7FC1AB, 0xD8A8E0D8
385
- );
386
-
387
- /**
388
- * The Key Schedule Array
389
- *
390
- * @var array
391
- * @access private
392
- */
393
- var $K = array();
394
-
395
- /**
396
- * The Key depended S-Table 0
397
- *
398
- * @var array
399
- * @access private
400
- */
401
- var $S0 = array();
402
-
403
- /**
404
- * The Key depended S-Table 1
405
- *
406
- * @var array
407
- * @access private
408
- */
409
- var $S1 = array();
410
-
411
- /**
412
- * The Key depended S-Table 2
413
- *
414
- * @var array
415
- * @access private
416
- */
417
- var $S2 = array();
418
-
419
- /**
420
- * The Key depended S-Table 3
421
- *
422
- * @var array
423
- * @access private
424
- */
425
- var $S3 = array();
426
-
427
- /**
428
- * Holds the last used key
429
- *
430
- * @var array
431
- * @access private
432
- */
433
- var $kl;
434
-
435
- /**
436
- * The Key Length (in bytes)
437
- *
438
- * @see Crypt_Twofish::setKeyLength()
439
- * @var int
440
- * @access private
441
- */
442
- var $key_length = 16;
443
-
444
- /**
445
- * Sets the key length.
446
- *
447
- * Valid key lengths are 128, 192 or 256 bits
448
- *
449
- * @access public
450
- * @param int $length
451
- */
452
- function setKeyLength($length)
453
- {
454
- switch (true) {
455
- case $length <= 128:
456
- $this->key_length = 16;
457
- break;
458
- case $length <= 192:
459
- $this->key_length = 24;
460
- break;
461
- default:
462
- $this->key_length = 32;
463
- }
464
-
465
- parent::setKeyLength($length);
466
- }
467
-
468
- /**
469
- * Setup the key (expansion)
470
- *
471
- * @see Crypt_Base::_setupKey()
472
- * @access private
473
- */
474
- function _setupKey()
475
- {
476
- if (isset($this->kl['key']) && $this->key === $this->kl['key']) {
477
- // already expanded
478
- return;
479
- }
480
- $this->kl = array('key' => $this->key);
481
-
482
- /* Key expanding and generating the key-depended s-boxes */
483
- $le_longs = unpack('V*', $this->key);
484
- $key = unpack('C*', $this->key);
485
- $m0 = $this->m0;
486
- $m1 = $this->m1;
487
- $m2 = $this->m2;
488
- $m3 = $this->m3;
489
- $q0 = $this->q0;
490
- $q1 = $this->q1;
491
-
492
- $K = $S0 = $S1 = $S2 = $S3 = array();
493
-
494
- switch (strlen($this->key)) {
495
- case 16:
496
- list($s7, $s6, $s5, $s4) = $this->_mdsrem($le_longs[1], $le_longs[2]);
497
- list($s3, $s2, $s1, $s0) = $this->_mdsrem($le_longs[3], $le_longs[4]);
498
- for ($i = 0, $j = 1; $i < 40; $i+= 2, $j+= 2) {
499
- $A = $m0[$q0[$q0[$i] ^ $key[ 9]] ^ $key[1]] ^
500
- $m1[$q0[$q1[$i] ^ $key[10]] ^ $key[2]] ^
501
- $m2[$q1[$q0[$i] ^ $key[11]] ^ $key[3]] ^
502
- $m3[$q1[$q1[$i] ^ $key[12]] ^ $key[4]];
503
- $B = $m0[$q0[$q0[$j] ^ $key[13]] ^ $key[5]] ^
504
- $m1[$q0[$q1[$j] ^ $key[14]] ^ $key[6]] ^
505
- $m2[$q1[$q0[$j] ^ $key[15]] ^ $key[7]] ^
506
- $m3[$q1[$q1[$j] ^ $key[16]] ^ $key[8]];
507
- $B = ($B << 8) | ($B >> 24 & 0xff);
508
- $K[] = $A+= $B;
509
- $K[] = (($A+= $B) << 9 | $A >> 23 & 0x1ff);
510
- }
511
- for ($i = 0; $i < 256; ++$i) {
512
- $S0[$i] = $m0[$q0[$q0[$i] ^ $s4] ^ $s0];
513
- $S1[$i] = $m1[$q0[$q1[$i] ^ $s5] ^ $s1];
514
- $S2[$i] = $m2[$q1[$q0[$i] ^ $s6] ^ $s2];
515
- $S3[$i] = $m3[$q1[$q1[$i] ^ $s7] ^ $s3];
516
- }
517
- break;
518
- case 24:
519
- list($sb, $sa, $s9, $s8) = $this->_mdsrem($le_longs[1], $le_longs[2]);
520
- list($s7, $s6, $s5, $s4) = $this->_mdsrem($le_longs[3], $le_longs[4]);
521
- list($s3, $s2, $s1, $s0) = $this->_mdsrem($le_longs[5], $le_longs[6]);
522
- for ($i = 0, $j = 1; $i < 40; $i+= 2, $j+= 2) {
523
- $A = $m0[$q0[$q0[$q1[$i] ^ $key[17]] ^ $key[ 9]] ^ $key[1]] ^
524
- $m1[$q0[$q1[$q1[$i] ^ $key[18]] ^ $key[10]] ^ $key[2]] ^
525
- $m2[$q1[$q0[$q0[$i] ^ $key[19]] ^ $key[11]] ^ $key[3]] ^
526
- $m3[$q1[$q1[$q0[$i] ^ $key[20]] ^ $key[12]] ^ $key[4]];
527
- $B = $m0[$q0[$q0[$q1[$j] ^ $key[21]] ^ $key[13]] ^ $key[5]] ^
528
- $m1[$q0[$q1[$q1[$j] ^ $key[22]] ^ $key[14]] ^ $key[6]] ^
529
- $m2[$q1[$q0[$q0[$j] ^ $key[23]] ^ $key[15]] ^ $key[7]] ^
530
- $m3[$q1[$q1[$q0[$j] ^ $key[24]] ^ $key[16]] ^ $key[8]];
531
- $B = ($B << 8) | ($B >> 24 & 0xff);
532
- $K[] = $A+= $B;
533
- $K[] = (($A+= $B) << 9 | $A >> 23 & 0x1ff);
534
- }
535
- for ($i = 0; $i < 256; ++$i) {
536
- $S0[$i] = $m0[$q0[$q0[$q1[$i] ^ $s8] ^ $s4] ^ $s0];
537
- $S1[$i] = $m1[$q0[$q1[$q1[$i] ^ $s9] ^ $s5] ^ $s1];
538
- $S2[$i] = $m2[$q1[$q0[$q0[$i] ^ $sa] ^ $s6] ^ $s2];
539
- $S3[$i] = $m3[$q1[$q1[$q0[$i] ^ $sb] ^ $s7] ^ $s3];
540
- }
541
- break;
542
- default: // 32
543
- list($sf, $se, $sd, $sc) = $this->_mdsrem($le_longs[1], $le_longs[2]);
544
- list($sb, $sa, $s9, $s8) = $this->_mdsrem($le_longs[3], $le_longs[4]);
545
- list($s7, $s6, $s5, $s4) = $this->_mdsrem($le_longs[5], $le_longs[6]);
546
- list($s3, $s2, $s1, $s0) = $this->_mdsrem($le_longs[7], $le_longs[8]);
547
- for ($i = 0, $j = 1; $i < 40; $i+= 2, $j+= 2) {
548
- $A = $m0[$q0[$q0[$q1[$q1[$i] ^ $key[25]] ^ $key[17]] ^ $key[ 9]] ^ $key[1]] ^
549
- $m1[$q0[$q1[$q1[$q0[$i] ^ $key[26]] ^ $key[18]] ^ $key[10]] ^ $key[2]] ^
550
- $m2[$q1[$q0[$q0[$q0[$i] ^ $key[27]] ^ $key[19]] ^ $key[11]] ^ $key[3]] ^
551
- $m3[$q1[$q1[$q0[$q1[$i] ^ $key[28]] ^ $key[20]] ^ $key[12]] ^ $key[4]];
552
- $B = $m0[$q0[$q0[$q1[$q1[$j] ^ $key[29]] ^ $key[21]] ^ $key[13]] ^ $key[5]] ^
553
- $m1[$q0[$q1[$q1[$q0[$j] ^ $key[30]] ^ $key[22]] ^ $key[14]] ^ $key[6]] ^
554
- $m2[$q1[$q0[$q0[$q0[$j] ^ $key[31]] ^ $key[23]] ^ $key[15]] ^ $key[7]] ^
555
- $m3[$q1[$q1[$q0[$q1[$j] ^ $key[32]] ^ $key[24]] ^ $key[16]] ^ $key[8]];
556
- $B = ($B << 8) | ($B >> 24 & 0xff);
557
- $K[] = $A+= $B;
558
- $K[] = (($A+= $B) << 9 | $A >> 23 & 0x1ff);
559
- }
560
- for ($i = 0; $i < 256; ++$i) {
561
- $S0[$i] = $m0[$q0[$q0[$q1[$q1[$i] ^ $sc] ^ $s8] ^ $s4] ^ $s0];
562
- $S1[$i] = $m1[$q0[$q1[$q1[$q0[$i] ^ $sd] ^ $s9] ^ $s5] ^ $s1];
563
- $S2[$i] = $m2[$q1[$q0[$q0[$q0[$i] ^ $se] ^ $sa] ^ $s6] ^ $s2];
564
- $S3[$i] = $m3[$q1[$q1[$q0[$q1[$i] ^ $sf] ^ $sb] ^ $s7] ^ $s3];
565
- }
566
- }
567
-
568
- $this->K = $K;
569
- $this->S0 = $S0;
570
- $this->S1 = $S1;
571
- $this->S2 = $S2;
572
- $this->S3 = $S3;
573
- }
574
-
575
- /**
576
- * _mdsrem function using by the twofish cipher algorithm
577
- *
578
- * @access private
579
- * @param string $A
580
- * @param string $B
581
- * @return array
582
- */
583
- function _mdsrem($A, $B)
584
- {
585
- // No gain by unrolling this loop.
586
- for ($i = 0; $i < 8; ++$i) {
587
- // Get most significant coefficient.
588
- $t = 0xff & ($B >> 24);
589
-
590
- // Shift the others up.
591
- $B = ($B << 8) | (0xff & ($A >> 24));
592
- $A<<= 8;
593
-
594
- $u = $t << 1;
595
-
596
- // Subtract the modular polynomial on overflow.
597
- if ($t & 0x80) {
598
- $u^= 0x14d;
599
- }
600
-
601
- // Remove t * (a * x^2 + 1).
602
- $B ^= $t ^ ($u << 16);
603
-
604
- // Form u = a*t + t/a = t*(a + 1/a).
605
- $u^= 0x7fffffff & ($t >> 1);
606
-
607
- // Add the modular polynomial on underflow.
608
- if ($t & 0x01) {
609
- $u^= 0xa6 ;
610
- }
611
-
612
- // Remove t * (a + 1/a) * (x^3 + x).
613
- $B^= ($u << 24) | ($u << 8);
614
- }
615
-
616
- return array(
617
- 0xff & $B >> 24,
618
- 0xff & $B >> 16,
619
- 0xff & $B >> 8,
620
- 0xff & $B);
621
- }
622
-
623
- /**
624
- * Encrypts a block
625
- *
626
- * @access private
627
- * @param string $in
628
- * @return string
629
- */
630
- function _encryptBlock($in)
631
- {
632
- $S0 = $this->S0;
633
- $S1 = $this->S1;
634
- $S2 = $this->S2;
635
- $S3 = $this->S3;
636
- $K = $this->K;
637
-
638
- $in = unpack("V4", $in);
639
- $R0 = $K[0] ^ $in[1];
640
- $R1 = $K[1] ^ $in[2];
641
- $R2 = $K[2] ^ $in[3];
642
- $R3 = $K[3] ^ $in[4];
643
-
644
- $ki = 7;
645
- while ($ki < 39) {
646
- $t0 = $S0[ $R0 & 0xff] ^
647
- $S1[($R0 >> 8) & 0xff] ^
648
- $S2[($R0 >> 16) & 0xff] ^
649
- $S3[($R0 >> 24) & 0xff];
650
- $t1 = $S0[($R1 >> 24) & 0xff] ^
651
- $S1[ $R1 & 0xff] ^
652
- $S2[($R1 >> 8) & 0xff] ^
653
- $S3[($R1 >> 16) & 0xff];
654
- $R2^= $t0 + $t1 + $K[++$ki];
655
- $R2 = ($R2 >> 1 & 0x7fffffff) | ($R2 << 31);
656
- $R3 = ((($R3 >> 31) & 1) | ($R3 << 1)) ^ ($t0 + ($t1 << 1) + $K[++$ki]);
657
-
658
- $t0 = $S0[ $R2 & 0xff] ^
659
- $S1[($R2 >> 8) & 0xff] ^
660
- $S2[($R2 >> 16) & 0xff] ^
661
- $S3[($R2 >> 24) & 0xff];
662
- $t1 = $S0[($R3 >> 24) & 0xff] ^
663
- $S1[ $R3 & 0xff] ^
664
- $S2[($R3 >> 8) & 0xff] ^
665
- $S3[($R3 >> 16) & 0xff];
666
- $R0^= ($t0 + $t1 + $K[++$ki]);
667
- $R0 = ($R0 >> 1 & 0x7fffffff) | ($R0 << 31);
668
- $R1 = ((($R1 >> 31) & 1) | ($R1 << 1)) ^ ($t0 + ($t1 << 1) + $K[++$ki]);
669
- }
670
-
671
- // @codingStandardsIgnoreStart
672
- return pack("V4", $K[4] ^ $R2,
673
- $K[5] ^ $R3,
674
- $K[6] ^ $R0,
675
- $K[7] ^ $R1);
676
- // @codingStandardsIgnoreEnd
677
- }
678
-
679
- /**
680
- * Decrypts a block
681
- *
682
- * @access private
683
- * @param string $in
684
- * @return string
685
- */
686
- function _decryptBlock($in)
687
- {
688
- $S0 = $this->S0;
689
- $S1 = $this->S1;
690
- $S2 = $this->S2;
691
- $S3 = $this->S3;
692
- $K = $this->K;
693
-
694
- $in = unpack("V4", $in);
695
- $R0 = $K[4] ^ $in[1];
696
- $R1 = $K[5] ^ $in[2];
697
- $R2 = $K[6] ^ $in[3];
698
- $R3 = $K[7] ^ $in[4];
699
-
700
- $ki = 40;
701
- while ($ki > 8) {
702
- $t0 = $S0[$R0 & 0xff] ^
703
- $S1[$R0 >> 8 & 0xff] ^
704
- $S2[$R0 >> 16 & 0xff] ^
705
- $S3[$R0 >> 24 & 0xff];
706
- $t1 = $S0[$R1 >> 24 & 0xff] ^
707
- $S1[$R1 & 0xff] ^
708
- $S2[$R1 >> 8 & 0xff] ^
709
- $S3[$R1 >> 16 & 0xff];
710
- $R3^= $t0 + ($t1 << 1) + $K[--$ki];
711
- $R3 = $R3 >> 1 & 0x7fffffff | $R3 << 31;
712
- $R2 = ($R2 >> 31 & 0x1 | $R2 << 1) ^ ($t0 + $t1 + $K[--$ki]);
713
-
714
- $t0 = $S0[$R2 & 0xff] ^
715
- $S1[$R2 >> 8 & 0xff] ^
716
- $S2[$R2 >> 16 & 0xff] ^
717
- $S3[$R2 >> 24 & 0xff];
718
- $t1 = $S0[$R3 >> 24 & 0xff] ^
719
- $S1[$R3 & 0xff] ^
720
- $S2[$R3 >> 8 & 0xff] ^
721
- $S3[$R3 >> 16 & 0xff];
722
- $R1^= $t0 + ($t1 << 1) + $K[--$ki];
723
- $R1 = $R1 >> 1 & 0x7fffffff | $R1 << 31;
724
- $R0 = ($R0 >> 31 & 0x1 | $R0 << 1) ^ ($t0 + $t1 + $K[--$ki]);
725
- }
726
-
727
- // @codingStandardsIgnoreStart
728
- return pack("V4", $K[0] ^ $R2,
729
- $K[1] ^ $R3,
730
- $K[2] ^ $R0,
731
- $K[3] ^ $R1);
732
- // @codingStandardsIgnoreEnd
733
- }
734
-
735
- /**
736
- * Setup the performance-optimized function for de/encrypt()
737
- *
738
- * @see Crypt_Base::_setupInlineCrypt()
739
- * @access private
740
- */
741
- function _setupInlineCrypt()
742
- {
743
- $lambda_functions =& Crypt_Twofish::_getLambdaFunctions();
744
-
745
- // Max. 10 Ultra-Hi-optimized inline-crypt functions. After that, we'll (still) create very fast code, but not the ultimate fast one.
746
- // (Currently, for Crypt_Twofish, one generated $lambda_function cost on php5.5@32bit ~140kb unfreeable mem and ~240kb on php5.5@64bit)
747
- $gen_hi_opt_code = (bool)(count($lambda_functions) < 10);
748
-
749
- // Generation of a unique hash for our generated code
750
- $code_hash = "Crypt_Twofish, {$this->mode}";
751
- if ($gen_hi_opt_code) {
752
- $code_hash = str_pad($code_hash, 32) . $this->_hashInlineCryptFunction($this->key);
753
- }
754
-
755
- if (!isset($lambda_functions[$code_hash])) {
756
- switch (true) {
757
- case $gen_hi_opt_code:
758
- $K = $this->K;
759
- $init_crypt = '
760
- static $S0, $S1, $S2, $S3;
761
- if (!$S0) {
762
- for ($i = 0; $i < 256; ++$i) {
763
- $S0[] = (int)$self->S0[$i];
764
- $S1[] = (int)$self->S1[$i];
765
- $S2[] = (int)$self->S2[$i];
766
- $S3[] = (int)$self->S3[$i];
767
- }
768
- }
769
- ';
770
- break;
771
- default:
772
- $K = array();
773
- for ($i = 0; $i < 40; ++$i) {
774
- $K[] = '$K_' . $i;
775
- }
776
- $init_crypt = '
777
- $S0 = $self->S0;
778
- $S1 = $self->S1;
779
- $S2 = $self->S2;
780
- $S3 = $self->S3;
781
- list(' . implode(',', $K) . ') = $self->K;
782
- ';
783
- }
784
-
785
- // Generating encrypt code:
786
- $encrypt_block = '
787
- $in = unpack("V4", $in);
788
- $R0 = '.$K[0].' ^ $in[1];
789
- $R1 = '.$K[1].' ^ $in[2];
790
- $R2 = '.$K[2].' ^ $in[3];
791
- $R3 = '.$K[3].' ^ $in[4];
792
- ';
793
- for ($ki = 7, $i = 0; $i < 8; ++$i) {
794
- $encrypt_block.= '
795
- $t0 = $S0[ $R0 & 0xff] ^
796
- $S1[($R0 >> 8) & 0xff] ^
797
- $S2[($R0 >> 16) & 0xff] ^
798
- $S3[($R0 >> 24) & 0xff];
799
- $t1 = $S0[($R1 >> 24) & 0xff] ^
800
- $S1[ $R1 & 0xff] ^
801
- $S2[($R1 >> 8) & 0xff] ^
802
- $S3[($R1 >> 16) & 0xff];
803
- $R2^= ($t0 + $t1 + '.$K[++$ki].');
804
- $R2 = ($R2 >> 1 & 0x7fffffff) | ($R2 << 31);
805
- $R3 = ((($R3 >> 31) & 1) | ($R3 << 1)) ^ ($t0 + ($t1 << 1) + '.$K[++$ki].');
806
-
807
- $t0 = $S0[ $R2 & 0xff] ^
808
- $S1[($R2 >> 8) & 0xff] ^
809
- $S2[($R2 >> 16) & 0xff] ^
810
- $S3[($R2 >> 24) & 0xff];
811
- $t1 = $S0[($R3 >> 24) & 0xff] ^
812
- $S1[ $R3 & 0xff] ^
813
- $S2[($R3 >> 8) & 0xff] ^
814
- $S3[($R3 >> 16) & 0xff];
815
- $R0^= ($t0 + $t1 + '.$K[++$ki].');
816
- $R0 = ($R0 >> 1 & 0x7fffffff) | ($R0 << 31);
817
- $R1 = ((($R1 >> 31) & 1) | ($R1 << 1)) ^ ($t0 + ($t1 << 1) + '.$K[++$ki].');
818
- ';
819
- }
820
- $encrypt_block.= '
821
- $in = pack("V4", '.$K[4].' ^ $R2,
822
- '.$K[5].' ^ $R3,
823
- '.$K[6].' ^ $R0,
824
- '.$K[7].' ^ $R1);
825
- ';
826
-
827
- // Generating decrypt code:
828
- $decrypt_block = '
829
- $in = unpack("V4", $in);
830
- $R0 = '.$K[4].' ^ $in[1];
831
- $R1 = '.$K[5].' ^ $in[2];
832
- $R2 = '.$K[6].' ^ $in[3];
833
- $R3 = '.$K[7].' ^ $in[4];
834
- ';
835
- for ($ki = 40, $i = 0; $i < 8; ++$i) {
836
- $decrypt_block.= '
837
- $t0 = $S0[$R0 & 0xff] ^
838
- $S1[$R0 >> 8 & 0xff] ^
839
- $S2[$R0 >> 16 & 0xff] ^
840
- $S3[$R0 >> 24 & 0xff];
841
- $t1 = $S0[$R1 >> 24 & 0xff] ^
842
- $S1[$R1 & 0xff] ^
843
- $S2[$R1 >> 8 & 0xff] ^
844
- $S3[$R1 >> 16 & 0xff];
845
- $R3^= $t0 + ($t1 << 1) + '.$K[--$ki].';
846
- $R3 = $R3 >> 1 & 0x7fffffff | $R3 << 31;
847
- $R2 = ($R2 >> 31 & 0x1 | $R2 << 1) ^ ($t0 + $t1 + '.$K[--$ki].');
848
-
849
- $t0 = $S0[$R2 & 0xff] ^
850
- $S1[$R2 >> 8 & 0xff] ^
851
- $S2[$R2 >> 16 & 0xff] ^
852
- $S3[$R2 >> 24 & 0xff];
853
- $t1 = $S0[$R3 >> 24 & 0xff] ^
854
- $S1[$R3 & 0xff] ^
855
- $S2[$R3 >> 8 & 0xff] ^
856
- $S3[$R3 >> 16 & 0xff];
857
- $R1^= $t0 + ($t1 << 1) + '.$K[--$ki].';
858
- $R1 = $R1 >> 1 & 0x7fffffff | $R1 << 31;
859
- $R0 = ($R0 >> 31 & 0x1 | $R0 << 1) ^ ($t0 + $t1 + '.$K[--$ki].');
860
- ';
861
- }
862
- $decrypt_block.= '
863
- $in = pack("V4", '.$K[0].' ^ $R2,
864
- '.$K[1].' ^ $R3,
865
- '.$K[2].' ^ $R0,
866
- '.$K[3].' ^ $R1);
867
- ';
868
-
869
- $lambda_functions[$code_hash] = $this->_createInlineCryptFunction(
870
- array(
871
- 'init_crypt' => $init_crypt,
872
- 'init_encrypt' => '',
873
- 'init_decrypt' => '',
874
- 'encrypt_block' => $encrypt_block,
875
- 'decrypt_block' => $decrypt_block
876
- )
877
- );
878
- }
879
- $this->inline_crypt = $lambda_functions[$code_hash];
880
- }
881
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/phpseclib/File/ANSI.php DELETED
@@ -1,601 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Pure-PHP ANSI Decoder
5
- *
6
- * PHP versions 4 and 5
7
- *
8
- * If you call read() in Net_SSH2 you may get {@link http://en.wikipedia.org/wiki/ANSI_escape_code ANSI escape codes} back.
9
- * They'd look like chr(0x1B) . '[00m' or whatever (0x1B = ESC). They tell a
10
- * {@link http://en.wikipedia.org/wiki/Terminal_emulator terminal emulator} how to format the characters, what
11
- * color to display them in, etc. File_ANSI is a {@link http://en.wikipedia.org/wiki/VT100 VT100} terminal emulator.
12
- *
13
- * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
14
- * of this software and associated documentation files (the "Software"), to deal
15
- * in the Software without restriction, including without limitation the rights
16
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17
- * copies of the Software, and to permit persons to whom the Software is
18
- * furnished to do so, subject to the following conditions:
19
- *
20
- * The above copyright notice and this permission notice shall be included in
21
- * all copies or substantial portions of the Software.
22
- *
23
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29
- * THE SOFTWARE.
30
- *
31
- * @category File
32
- * @package File_ANSI
33
- * @author Jim Wigginton <terrafrost@php.net>
34
- * @copyright 2012 Jim Wigginton
35
- * @license http://www.opensource.org/licenses/mit-license.html MIT License
36
- * @link http://phpseclib.sourceforge.net
37
- */
38
-
39
- /**
40
- * Pure-PHP ANSI Decoder
41
- *
42
- * @package File_ANSI
43
- * @author Jim Wigginton <terrafrost@php.net>
44
- * @access public
45
- */
46
- class File_ANSI
47
- {
48
- /**
49
- * Max Width
50
- *
51
- * @var int
52
- * @access private
53
- */
54
- var $max_x;
55
-
56
- /**
57
- * Max Height
58
- *
59
- * @var int
60
- * @access private
61
- */
62
- var $max_y;
63
-
64
- /**
65
- * Max History
66
- *
67
- * @var int
68
- * @access private
69
- */
70
- var $max_history;
71
-
72
- /**
73
- * History
74
- *
75
- * @var array
76
- * @access private
77
- */
78
- var $history;
79
-
80
- /**
81
- * History Attributes
82
- *
83
- * @var array
84
- * @access private
85
- */
86
- var $history_attrs;
87
-
88
- /**
89
- * Current Column
90
- *
91
- * @var int
92
- * @access private
93
- */
94
- var $x;
95
-
96
- /**
97
- * Current Row
98
- *
99
- * @var int
100
- * @access private
101
- */
102
- var $y;
103
-
104
- /**
105
- * Old Column
106
- *
107
- * @var int
108
- * @access private
109
- */
110
- var $old_x;
111
-
112
- /**
113
- * Old Row
114
- *
115
- * @var int
116
- * @access private
117
- */
118
- var $old_y;
119
-
120
- /**
121
- * An empty attribute cell
122
- *
123
- * @var object
124
- * @access private
125
- */
126
- var $base_attr_cell;
127
-
128
- /**
129
- * The current attribute cell
130
- *
131
- * @var object
132
- * @access private
133
- */
134
- var $attr_cell;
135
-
136
- /**
137
- * An empty attribute row
138
- *
139
- * @var array
140
- * @access private
141
- */
142
- var $attr_row;
143
-
144
- /**
145
- * The current screen text
146
- *
147
- * @var array
148
- * @access private
149
- */
150
- var $screen;
151
-
152
- /**
153
- * The current screen attributes
154
- *
155
- * @var array
156
- * @access private
157
- */
158
- var $attrs;
159
-
160
- /**
161
- * Current ANSI code
162
- *
163
- * @var string
164
- * @access private
165
- */
166
- var $ansi;
167
-
168
- /**
169
- * Tokenization
170
- *
171
- * @var array
172
- * @access private
173
- */
174
- var $tokenization;
175
-
176
- /**
177
- * Default Constructor.
178
- *
179
- * @return File_ANSI
180
- * @access public
181
- */
182
- function __construct()
183
- {
184
- $attr_cell = new stdClass();
185
- $attr_cell->bold = false;
186
- $attr_cell->underline = false;
187
- $attr_cell->blink = false;
188
- $attr_cell->background = 'black';
189
- $attr_cell->foreground = 'white';
190
- $attr_cell->reverse = false;
191
- $this->base_attr_cell = clone($attr_cell);
192
- $this->attr_cell = clone($attr_cell);
193
-
194
- $this->setHistory(200);
195
- $this->setDimensions(80, 24);
196
- }
197
-
198
- /**
199
- * PHP4 compatible Default Constructor.
200
- *
201
- * @see self::__construct()
202
- * @access public
203
- */
204
- function File_ANSI()
205
- {
206
- $this->__construct($mode);
207
- }
208
-
209
- /**
210
- * Set terminal width and height
211
- *
212
- * Resets the screen as well
213
- *
214
- * @param int $x
215
- * @param int $y
216
- * @access public
217
- */
218
- function setDimensions($x, $y)
219
- {
220
- $this->max_x = $x - 1;
221
- $this->max_y = $y - 1;
222
- $this->x = $this->y = 0;
223
- $this->history = $this->history_attrs = array();
224
- $this->attr_row = array_fill(0, $this->max_x + 2, $this->base_attr_cell);
225
- $this->screen = array_fill(0, $this->max_y + 1, '');
226
- $this->attrs = array_fill(0, $this->max_y + 1, $this->attr_row);
227
- $this->ansi = '';
228
- }
229
-
230
- /**
231
- * Set the number of lines that should be logged past the terminal height
232
- *
233
- * @param int $x
234
- * @param int $y
235
- * @access public
236
- */
237
- function setHistory($history)
238
- {
239
- $this->max_history = $history;
240
- }
241
-
242
- /**
243
- * Load a string
244
- *
245
- * @param string $source
246
- * @access public
247
- */
248
- function loadString($source)
249
- {
250
- $this->setDimensions($this->max_x + 1, $this->max_y + 1);
251
- $this->appendString($source);
252
- }
253
-
254
- /**
255
- * Appdend a string
256
- *
257
- * @param string $source
258
- * @access public
259
- */
260
- function appendString($source)
261
- {
262
- $this->tokenization = array('');
263
- for ($i = 0; $i < strlen($source); $i++) {
264
- if (strlen($this->ansi)) {
265
- $this->ansi.= $source[$i];
266
- $chr = ord($source[$i]);
267
- // http://en.wikipedia.org/wiki/ANSI_escape_code#Sequence_elements
268
- // single character CSI's not currently supported
269
- switch (true) {
270
- case $this->ansi == "\x1B=":
271
- $this->ansi = '';
272
- continue 2;
273
- case strlen($this->ansi) == 2 && $chr >= 64 && $chr <= 95 && $chr != ord('['):
274
- case strlen($this->ansi) > 2 && $chr >= 64 && $chr <= 126:
275
- break;
276
- default:
277
- continue 2;
278
- }
279
- $this->tokenization[] = $this->ansi;
280
- $this->tokenization[] = '';
281
- // http://ascii-table.com/ansi-escape-sequences-vt-100.php
282
- switch ($this->ansi) {
283
- case "\x1B[H": // Move cursor to upper left corner
284
- $this->old_x = $this->x;
285
- $this->old_y = $this->y;
286
- $this->x = $this->y = 0;
287
- break;
288
- case "\x1B[J": // Clear screen from cursor down
289
- $this->history = array_merge($this->history, array_slice(array_splice($this->screen, $this->y + 1), 0, $this->old_y));
290
- $this->screen = array_merge($this->screen, array_fill($this->y, $this->max_y, ''));
291
-
292
- $this->history_attrs = array_merge($this->history_attrs, array_slice(array_splice($this->attrs, $this->y + 1), 0, $this->old_y));
293
- $this->attrs = array_merge($this->attrs, array_fill($this->y, $this->max_y, $this->attr_row));
294
-
295
- if (count($this->history) == $this->max_history) {
296
- array_shift($this->history);
297
- array_shift($this->history_attrs);
298
- }
299
- case "\x1B[K": // Clear screen from cursor right
300
- $this->screen[$this->y] = substr($this->screen[$this->y], 0, $this->x);
301
-
302
- array_splice($this->attrs[$this->y], $this->x + 1, $this->max_x - $this->x, array_fill($this->x, $this->max_x - $this->x - 1, $this->base_attr_cell));
303
- break;
304
- case "\x1B[2K": // Clear entire line
305
- $this->screen[$this->y] = str_repeat(' ', $this->x);
306
- $this->attrs[$this->y] = $this->attr_row;
307
- break;
308
- case "\x1B[?1h": // set cursor key to application
309
- case "\x1B[?25h": // show the cursor
310
- case "\x1B(B": // set united states g0 character set
311
- break;
312
- case "\x1BE": // Move to next line
313
- $this->_newLine();
314
- $this->x = 0;
315
- break;
316
- default:
317
- switch (true) {
318
- case preg_match('#\x1B\[(\d+)B#', $this->ansi, $match): // Move cursor down n lines
319
- $this->old_y = $this->y;
320
- $this->y+= $match[1];
321
- break;
322
- case preg_match('#\x1B\[(\d+);(\d+)H#', $this->ansi, $match): // Move cursor to screen location v,h
323
- $this->old_x = $this->x;
324
- $this->old_y = $this->y;
325
- $this->x = $match[2] - 1;
326
- $this->y = $match[1] - 1;
327
- break;
328
- case preg_match('#\x1B\[(\d+)C#', $this->ansi, $match): // Move cursor right n lines
329
- $this->old_x = $this->x;
330
- $this->x+= $match[1];
331
- break;
332
- case preg_match('#\x1B\[(\d+)D#', $this->ansi, $match): // Move cursor left n lines
333
- $this->old_x = $this->x;
334
- $this->x-= $match[1];
335
- break;
336
- case preg_match('#\x1B\[(\d+);(\d+)r#', $this->ansi, $match): // Set top and bottom lines of a window
337
- break;
338
- case preg_match('#\x1B\[(\d*(?:;\d*)*)m#', $this->ansi, $match): // character attributes
339
- $attr_cell = &$this->attr_cell;
340
- $mods = explode(';', $match[1]);
341
- foreach ($mods as $mod) {
342
- switch ($mod) {
343
- case 0: // Turn off character attributes
344
- $attr_cell = clone($this->base_attr_cell);
345
- break;
346
- case 1: // Turn bold mode on
347
- $attr_cell->bold = true;
348
- break;
349
- case 4: // Turn underline mode on
350
- $attr_cell->underline = true;
351
- break;
352
- case 5: // Turn blinking mode on
353
- $attr_cell->blink = true;
354
- break;
355
- case 7: // Turn reverse video on
356
- $attr_cell->reverse = !$attr_cell->reverse;
357
- $temp = $attr_cell->background;
358
- $attr_cell->background = $attr_cell->foreground;
359
- $attr_cell->foreground = $temp;
360
- break;
361
- default: // set colors
362
- //$front = $attr_cell->reverse ? &$attr_cell->background : &$attr_cell->foreground;
363
- $front = &$attr_cell->{ $attr_cell->reverse ? 'background' : 'foreground' };
364
- //$back = $attr_cell->reverse ? &$attr_cell->foreground : &$attr_cell->background;
365
- $back = &$attr_cell->{ $attr_cell->reverse ? 'foreground' : 'background' };
366
- switch ($mod) {
367
- // @codingStandardsIgnoreStart
368
- case 30: $front = 'black'; break;
369
- case 31: $front = 'red'; break;
370
- case 32: $front = 'green'; break;
371
- case 33: $front = 'yellow'; break;
372
- case 34: $front = 'blue'; break;
373
- case 35: $front = 'magenta'; break;
374
- case 36: $front = 'cyan'; break;
375
- case 37: $front = 'white'; break;
376
-
377
- case 40: $back = 'black'; break;
378
- case 41: $back = 'red'; break;
379
- case 42: $back = 'green'; break;
380
- case 43: $back = 'yellow'; break;
381
- case 44: $back = 'blue'; break;
382
- case 45: $back = 'magenta'; break;
383
- case 46: $back = 'cyan'; break;
384
- case 47: $back = 'white'; break;
385
- // @codingStandardsIgnoreEnd
386
-
387
- default:
388
- //user_error('Unsupported attribute: ' . $mod);
389
- $this->ansi = '';
390
- break 2;
391
- }
392
- }
393
- }
394
- break;
395
- default:
396
- //user_error("{$this->ansi} is unsupported\r\n");
397
- }
398
- }
399
- $this->ansi = '';
400
- continue;
401
- }
402
-
403
- $this->tokenization[count($this->tokenization) - 1].= $source[$i];
404
- switch ($source[$i]) {
405
- case "\r":
406
- $this->x = 0;
407
- break;
408
- case "\n":
409
- $this->_newLine();
410
- break;
411
- case "\x08": // backspace
412
- if ($this->x) {
413
- $this->x--;
414
- $this->attrs[$this->y][$this->x] = clone($this->base_attr_cell);
415
- $this->screen[$this->y] = substr_replace(
416
- $this->screen[$this->y],
417
- $source[$i],
418
- $this->x,
419
- 1
420
- );
421
- }
422
- break;
423
- case "\x0F": // shift
424
- break;
425
- case "\x1B": // start ANSI escape code
426
- $this->tokenization[count($this->tokenization) - 1] = substr($this->tokenization[count($this->tokenization) - 1], 0, -1);
427
- //if (!strlen($this->tokenization[count($this->tokenization) - 1])) {
428
- // array_pop($this->tokenization);
429
- //}
430
- $this->ansi.= "\x1B";
431
- break;
432
- default:
433
- $this->attrs[$this->y][$this->x] = clone($this->attr_cell);
434
- if ($this->x > strlen($this->screen[$this->y])) {
435
- $this->screen[$this->y] = str_repeat(' ', $this->x);
436
- }
437
- $this->screen[$this->y] = substr_replace(
438
- $this->screen[$this->y],
439
- $source[$i],
440
- $this->x,
441
- 1
442
- );
443
-
444
- if ($this->x > $this->max_x) {
445
- $this->x = 0;
446
- $this->y++;
447
- } else {
448
- $this->x++;
449
- }
450
- }
451
- }
452
- }
453
-
454
- /**
455
- * Add a new line
456
- *
457
- * Also update the $this->screen and $this->history buffers
458
- *
459
- * @access private
460
- */
461
- function _newLine()
462
- {
463
- //if ($this->y < $this->max_y) {
464
- // $this->y++;
465
- //}
466
-
467
- while ($this->y >= $this->max_y) {
468
- $this->history = array_merge($this->history, array(array_shift($this->screen)));
469
- $this->screen[] = '';
470
-
471
- $this->history_attrs = array_merge($this->history_attrs, array(array_shift($this->attrs)));
472
- $this->attrs[] = $this->attr_row;
473
-
474
- if (count($this->history) >= $this->max_history) {
475
- array_shift($this->history);
476
- array_shift($this->history_attrs);
477
- }
478
-
479
- $this->y--;
480
- }
481
- $this->y++;
482
- }
483
-
484
- /**
485
- * Returns the current coordinate without preformating
486
- *
487
- * @access private
488
- * @return string
489
- */
490
- function _processCoordinate($last_attr, $cur_attr, $char)
491
- {
492
- $output = '';
493
-
494
- if ($last_attr != $cur_attr) {
495
- $close = $open = '';
496
- if ($last_attr->foreground != $cur_attr->foreground) {
497
- if ($cur_attr->foreground != 'white') {
498
- $open.= '<span style="color: ' . $cur_attr->foreground . '">';
499
- }
500
- if ($last_attr->foreground != 'white') {
501
- $close = '</span>' . $close;
502
- }
503
- }
504
- if ($last_attr->background != $cur_attr->background) {
505
- if ($cur_attr->background != 'black') {
506
- $open.= '<span style="background: ' . $cur_attr->background . '">';
507
- }
508
- if ($last_attr->background != 'black') {
509
- $close = '</span>' . $close;
510
- }
511
- }
512
- if ($last_attr->bold != $cur_attr->bold) {
513
- if ($cur_attr->bold) {
514
- $open.= '<b>';
515
- } else {
516
- $close = '</b>' . $close;
517
- }
518
- }
519
- if ($last_attr->underline != $cur_attr->underline) {
520
- if ($cur_attr->underline) {
521
- $open.= '<u>';
522
- } else {
523
- $close = '</u>' . $close;
524
- }
525
- }
526
- if ($last_attr->blink != $cur_attr->blink) {
527
- if ($cur_attr->blink) {
528
- $open.= '<blink>';
529
- } else {
530
- $close = '</blink>' . $close;
531
- }
532
- }
533
- $output.= $close . $open;
534
- }
535
-
536
- $output.= htmlspecialchars($char);
537
-
538
- return $output;
539
- }
540
-
541
- /**
542
- * Returns the current screen without preformating
543
- *
544
- * @access private
545
- * @return string
546
- */
547
- function _getScreen()
548
- {
549
- $output = '';
550
- $last_attr = $this->base_attr_cell;
551
- for ($i = 0; $i <= $this->max_y; $i++) {
552
- for ($j = 0; $j <= $this->max_x; $j++) {
553
- $cur_attr = $this->attrs[$i][$j];
554
- $output.= $this->_processCoordinate($last_attr, $cur_attr, isset($this->screen[$i][$j]) ? $this->screen[$i][$j] : '');
555
- $last_attr = $this->attrs[$i][$j];
556
- }
557
- $output.= "\r\n";
558
- }
559
- $output = substr($output, 0, -2);
560
- // close any remaining open tags
561
- $output.= $this->_processCoordinate($last_attr, $this->base_attr_cell, '');
562
- return rtrim($output);
563
- }
564
-
565
- /**
566
- * Returns the current screen
567
- *
568
- * @access public
569
- * @return string
570
- */
571
- function getScreen()
572
- {
573
- return '<pre width="' . ($this->max_x + 1) . '" style="color: white; background: black">' . $this->_getScreen() . '</pre>';
574
- }
575
-
576
- /**
577
- * Returns the current screen and the x previous lines
578
- *
579
- * @access public
580
- * @return string
581
- */
582
- function getHistory()
583
- {
584
- $scrollback = '';
585
- $last_attr = $this->base_attr_cell;
586
- for ($i = 0; $i < count($this->history); $i++) {
587
- for ($j = 0; $j <= $this->max_x + 1; $j++) {
588
- $cur_attr = $this->history_attrs[$i][$j];
589
- $scrollback.= $this->_processCoordinate($last_attr, $cur_attr, isset($this->history[$i][$j]) ? $this->history[$i][$j] : '');
590
- $last_attr = $this->history_attrs[$i][$j];
591
- }
592
- $scrollback.= "\r\n";
593
- }
594
- $base_attr_cell = $this->base_attr_cell;
595
- $this->base_attr_cell = $last_attr;
596
- $scrollback.= $this->_getScreen();
597
- $this->base_attr_cell = $base_attr_cell;
598
-
599
- return '<pre width="' . ($this->max_x + 1) . '" style="color: white; background: black">' . $scrollback . '</span></pre>';
600
- }
601
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/phpseclib/File/ASN1.php DELETED
@@ -1,1407 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Pure-PHP ASN.1 Parser
5
- *
6
- * PHP versions 4 and 5
7
- *
8
- * ASN.1 provides the semantics for data encoded using various schemes. The most commonly
9
- * utilized scheme is DER or the "Distinguished Encoding Rules". PEM's are base64 encoded
10
- * DER blobs.
11
- *
12
- * File_ASN1 decodes and encodes DER formatted messages and places them in a semantic context.
13
- *
14
- * Uses the 1988 ASN.1 syntax.
15
- *
16
- * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
17
- * of this software and associated documentation files (the "Software"), to deal
18
- * in the Software without restriction, including without limitation the rights
19
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
20
- * copies of the Software, and to permit persons to whom the Software is
21
- * furnished to do so, subject to the following conditions:
22
- *
23
- * The above copyright notice and this permission notice shall be included in
24
- * all copies or substantial portions of the Software.
25
- *
26
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
29
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
30
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
31
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
32
- * THE SOFTWARE.
33
- *
34
- * @category File
35
- * @package File_ASN1
36
- * @author Jim Wigginton <terrafrost@php.net>
37
- * @copyright 2012 Jim Wigginton
38
- * @license http://www.opensource.org/licenses/mit-license.html MIT License
39
- * @link http://phpseclib.sourceforge.net
40
- */
41
-
42
- /**#@+
43
- * Tag Classes
44
- *
45
- * @access private
46
- * @link http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#page=12
47
- */
48
- define('FILE_ASN1_CLASS_UNIVERSAL', 0);
49
- define('FILE_ASN1_CLASS_APPLICATION', 1);
50
- define('FILE_ASN1_CLASS_CONTEXT_SPECIFIC', 2);
51
- define('FILE_ASN1_CLASS_PRIVATE', 3);
52
- /**#@-*/
53
-
54
- /**#@+
55
- * Tag Classes
56
- *
57
- * @access private
58
- * @link http://www.obj-sys.com/asn1tutorial/node124.html
59
- */
60
- define('FILE_ASN1_TYPE_BOOLEAN', 1);
61
- define('FILE_ASN1_TYPE_INTEGER', 2);
62
- define('FILE_ASN1_TYPE_BIT_STRING', 3);
63
- define('FILE_ASN1_TYPE_OCTET_STRING', 4);
64
- define('FILE_ASN1_TYPE_NULL', 5);
65
- define('FILE_ASN1_TYPE_OBJECT_IDENTIFIER', 6);
66
- //define('FILE_ASN1_TYPE_OBJECT_DESCRIPTOR', 7);
67
- //define('FILE_ASN1_TYPE_INSTANCE_OF', 8); // EXTERNAL
68
- define('FILE_ASN1_TYPE_REAL', 9);
69
- define('FILE_ASN1_TYPE_ENUMERATED', 10);
70
- //define('FILE_ASN1_TYPE_EMBEDDED', 11);
71
- define('FILE_ASN1_TYPE_UTF8_STRING', 12);
72
- //define('FILE_ASN1_TYPE_RELATIVE_OID', 13);
73
- define('FILE_ASN1_TYPE_SEQUENCE', 16); // SEQUENCE OF
74
- define('FILE_ASN1_TYPE_SET', 17); // SET OF
75
- /**#@-*/
76
- /**#@+
77
- * More Tag Classes
78
- *
79
- * @access private
80
- * @link http://www.obj-sys.com/asn1tutorial/node10.html
81
- */
82
- define('FILE_ASN1_TYPE_NUMERIC_STRING', 18);
83
- define('FILE_ASN1_TYPE_PRINTABLE_STRING', 19);
84
- define('FILE_ASN1_TYPE_TELETEX_STRING', 20); // T61String
85
- define('FILE_ASN1_TYPE_VIDEOTEX_STRING', 21);
86
- define('FILE_ASN1_TYPE_IA5_STRING', 22);
87
- define('FILE_ASN1_TYPE_UTC_TIME', 23);
88
- define('FILE_ASN1_TYPE_GENERALIZED_TIME', 24);
89
- define('FILE_ASN1_TYPE_GRAPHIC_STRING', 25);
90
- define('FILE_ASN1_TYPE_VISIBLE_STRING', 26); // ISO646String
91
- define('FILE_ASN1_TYPE_GENERAL_STRING', 27);
92
- define('FILE_ASN1_TYPE_UNIVERSAL_STRING', 28);
93
- //define('FILE_ASN1_TYPE_CHARACTER_STRING', 29);
94
- define('FILE_ASN1_TYPE_BMP_STRING', 30);
95
- /**#@-*/
96
-
97
- /**#@+
98
- * Tag Aliases
99
- *
100
- * These tags are kinda place holders for other tags.
101
- *
102
- * @access private
103
- */
104
- define('FILE_ASN1_TYPE_CHOICE', -1);
105
- define('FILE_ASN1_TYPE_ANY', -2);
106
- /**#@-*/
107
-
108
- /**
109
- * ASN.1 Element
110
- *
111
- * Bypass normal encoding rules in File_ASN1::encodeDER()
112
- *
113
- * @package File_ASN1
114
- * @author Jim Wigginton <terrafrost@php.net>
115
- * @access public
116
- */
117
- class File_ASN1_Element
118
- {
119
- /**
120
- * Raw element value
121
- *
122
- * @var string
123
- * @access private
124
- */
125
- var $element;
126
-
127
- /**
128
- * Constructor
129
- *
130
- * @param string $encoded
131
- * @return File_ASN1_Element
132
- * @access public
133
- */
134
- function __construct($encoded)
135
- {
136
- $this->element = $encoded;
137
- }
138
-
139
- /**
140
- * PHP4 compatible Default Constructor.
141
- *
142
- * @see self::__construct()
143
- * @param int $mode
144
- * @access public
145
- */
146
- function File_ASN1_Element($encoded)
147
- {
148
- $this->__construct($encoded);
149
- }
150
- }
151
-
152
- /**
153
- * Pure-PHP ASN.1 Parser
154
- *
155
- * @package File_ASN1
156
- * @author Jim Wigginton <terrafrost@php.net>
157
- * @access public
158
- */
159
- class File_ASN1
160
- {
161
- /**
162
- * ASN.1 object identifier
163
- *
164
- * @var array
165
- * @access private
166
- * @link http://en.wikipedia.org/wiki/Object_identifier
167
- */
168
- var $oids = array();
169
-
170
- /**
171
- * Default date format
172
- *
173
- * @var string
174
- * @access private
175
- * @link http://php.net/class.datetime
176
- */
177
- var $format = 'D, d M Y H:i:s O';
178
-
179
- /**
180
- * Default date format
181
- *
182
- * @var array
183
- * @access private
184
- * @see self::setTimeFormat()
185
- * @see self::asn1map()
186
- * @link http://php.net/class.datetime
187
- */
188
- var $encoded;
189
-
190
- /**
191
- * Filters
192
- *
193
- * If the mapping type is FILE_ASN1_TYPE_ANY what do we actually encode it as?
194
- *
195
- * @var array
196
- * @access private
197
- * @see self::_encode_der()
198
- */
199
- var $filters;
200
-
201
- /**
202
- * Type mapping table for the ANY type.
203
- *
204
- * Structured or unknown types are mapped to a FILE_ASN1_Element.
205
- * Unambiguous types get the direct mapping (int/real/bool).
206
- * Others are mapped as a choice, with an extra indexing level.
207
- *
208
- * @var array
209
- * @access public
210
- */
211
- var $ANYmap = array(
212
- FILE_ASN1_TYPE_BOOLEAN => true,
213
- FILE_ASN1_TYPE_INTEGER => true,
214
- FILE_ASN1_TYPE_BIT_STRING => 'bitString',
215
- FILE_ASN1_TYPE_OCTET_STRING => 'octetString',
216
- FILE_ASN1_TYPE_NULL => 'null',
217
- FILE_ASN1_TYPE_OBJECT_IDENTIFIER => 'objectIdentifier',
218
- FILE_ASN1_TYPE_REAL => true,
219
- FILE_ASN1_TYPE_ENUMERATED => 'enumerated',
220
- FILE_ASN1_TYPE_UTF8_STRING => 'utf8String',
221
- FILE_ASN1_TYPE_NUMERIC_STRING => 'numericString',
222
- FILE_ASN1_TYPE_PRINTABLE_STRING => 'printableString',
223
- FILE_ASN1_TYPE_TELETEX_STRING => 'teletexString',
224
- FILE_ASN1_TYPE_VIDEOTEX_STRING => 'videotexString',
225
- FILE_ASN1_TYPE_IA5_STRING => 'ia5String',
226
- FILE_ASN1_TYPE_UTC_TIME => 'utcTime',
227
- FILE_ASN1_TYPE_GENERALIZED_TIME => 'generalTime',
228
- FILE_ASN1_TYPE_GRAPHIC_STRING => 'graphicString',
229
- FILE_ASN1_TYPE_VISIBLE_STRING => 'visibleString',
230
- FILE_ASN1_TYPE_GENERAL_STRING => 'generalString',
231
- FILE_ASN1_TYPE_UNIVERSAL_STRING => 'universalString',
232
- //FILE_ASN1_TYPE_CHARACTER_STRING => 'characterString',
233
- FILE_ASN1_TYPE_BMP_STRING => 'bmpString'
234
- );
235
-
236
- /**
237
- * String type to character size mapping table.
238
- *
239
- * Non-convertable types are absent from this table.
240
- * size == 0 indicates variable length encoding.
241
- *
242
- * @var array
243
- * @access public
244
- */
245
- var $stringTypeSize = array(
246
- FILE_ASN1_TYPE_UTF8_STRING => 0,
247
- FILE_ASN1_TYPE_BMP_STRING => 2,
248
- FILE_ASN1_TYPE_UNIVERSAL_STRING => 4,
249
- FILE_ASN1_TYPE_PRINTABLE_STRING => 1,
250
- FILE_ASN1_TYPE_TELETEX_STRING => 1,
251
- FILE_ASN1_TYPE_IA5_STRING => 1,
252
- FILE_ASN1_TYPE_VISIBLE_STRING => 1,
253
- );
254
-
255
- /**
256
- * Default Constructor.
257
- *
258
- * @access public
259
- */
260
- function __construct()
261
- {
262
- static $static_init = null;
263
- if (!$static_init) {
264
- $static_init = true;
265
- if (!class_exists('Math_BigInteger')) {
266
- include_once 'Math/BigInteger.php';
267
- }
268
- }
269
- }
270
-
271
- /**
272
- * PHP4 compatible Default Constructor.
273
- *
274
- * @see self::__construct()
275
- * @access public
276
- */
277
- function File_ASN1()
278
- {
279
- $this->__construct($mode);
280
- }
281
-
282
- /**
283
- * Parse BER-encoding
284
- *
285
- * Serves a similar purpose to openssl's asn1parse
286
- *
287
- * @param string $encoded
288
- * @return array
289
- * @access public
290
- */
291
- function decodeBER($encoded)
292
- {
293
- if (is_object($encoded) && strtolower(get_class($encoded)) == 'file_asn1_element') {
294
- $encoded = $encoded->element;
295
- }
296
-
297
- $this->encoded = $encoded;
298
- // encapsulate in an array for BC with the old decodeBER
299
- return array($this->_decode_ber($encoded));
300
- }
301
-
302
- /**
303
- * Parse BER-encoding (Helper function)
304
- *
305
- * Sometimes we want to get the BER encoding of a particular tag. $start lets us do that without having to reencode.
306
- * $encoded is passed by reference for the recursive calls done for FILE_ASN1_TYPE_BIT_STRING and
307
- * FILE_ASN1_TYPE_OCTET_STRING. In those cases, the indefinite length is used.
308
- *
309
- * @param string $encoded
310
- * @param int $start
311
- * @param int $encoded_pos
312
- * @return array
313
- * @access private
314
- */
315
- function _decode_ber($encoded, $start = 0, $encoded_pos = 0)
316
- {
317
- $current = array('start' => $start);
318
-
319
- $type = ord($encoded[$encoded_pos++]);
320
- $start++;
321
-
322
- $constructed = ($type >> 5) & 1;
323
-
324
- $tag = $type & 0x1F;
325
- if ($tag == 0x1F) {
326
- $tag = 0;
327
- // process septets (since the eighth bit is ignored, it's not an octet)
328
- do {
329
- $loop = ord($encoded[0]) >> 7;
330
- $tag <<= 7;
331
- $tag |= ord($encoded[$encoded_pos++]) & 0x7F;
332
- $start++;
333
- } while ($loop);
334
- }
335
-
336
- // Length, as discussed in paragraph 8.1.3 of X.690-0207.pdf#page=13
337
- $length = ord($encoded[$encoded_pos++]);
338
- $start++;
339
- if ($length == 0x80) { // indefinite length
340
- // "[A sender shall] use the indefinite form (see 8.1.3.6) if the encoding is constructed and is not all
341
- // immediately available." -- paragraph 8.1.3.2.c
342
- $length = strlen($encoded) - $encoded_pos;
343
- } elseif ($length & 0x80) { // definite length, long form
344
- // technically, the long form of the length can be represented by up to 126 octets (bytes), but we'll only
345
- // support it up to four.
346
- $length&= 0x7F;
347
- $temp = substr($encoded, $encoded_pos, $length);
348
- $encoded_pos += $length;
349
- // tags of indefinte length don't really have a header length; this length includes the tag
350
- $current+= array('headerlength' => $length + 2);
351
- $start+= $length;
352
- extract(unpack('Nlength', substr(str_pad($temp, 4, chr(0), STR_PAD_LEFT), -4)));
353
- } else {
354
- $current+= array('headerlength' => 2);
355
- }
356
-
357
- if ($length > (strlen($encoded) - $encoded_pos)) {
358
- return false;
359
- }
360
-
361
- $content = substr($encoded, $encoded_pos, $length);
362
- $content_pos = 0;
363
-
364
- // at this point $length can be overwritten. it's only accurate for definite length things as is
365
-
366
- /* Class is UNIVERSAL, APPLICATION, PRIVATE, or CONTEXT-SPECIFIC. The UNIVERSAL class is restricted to the ASN.1
367
- built-in types. It defines an application-independent data type that must be distinguishable from all other
368
- data types. The other three classes are user defined. The APPLICATION class distinguishes data types that
369
- have a wide, scattered use within a particular presentation context. PRIVATE distinguishes data types within
370
- a particular organization or country. CONTEXT-SPECIFIC distinguishes members of a sequence or set, the
371
- alternatives of a CHOICE, or universally tagged set members. Only the class number appears in braces for this
372
- data type; the term CONTEXT-SPECIFIC does not appear.
373
-
374
- -- http://www.obj-sys.com/asn1tutorial/node12.html */
375
- $class = ($type >> 6) & 3;
376
- switch ($class) {
377
- case FILE_ASN1_CLASS_APPLICATION:
378
- case FILE_ASN1_CLASS_PRIVATE:
379
- case FILE_ASN1_CLASS_CONTEXT_SPECIFIC:
380
- if (!$constructed) {
381
- return array(
382
- 'type' => $class,
383
- 'constant' => $tag,
384
- 'content' => $content,
385
- 'length' => $length + $start - $current['start']
386
- );
387
- }
388
-
389
- $newcontent = array();
390
- $remainingLength = $length;
391
- while ($remainingLength > 0) {
392
- $temp = $this->_decode_ber($content, $start, $content_pos);
393
- $length = $temp['length'];
394
- // end-of-content octets - see paragraph 8.1.5
395
- if (substr($content, $content_pos + $length, 2) == "\0\0") {
396
- $length+= 2;
397
- $start+= $length;
398
- $newcontent[] = $temp;
399
- break;
400
- }
401
- $start+= $length;
402
- $remainingLength-= $length;
403
- $newcontent[] = $temp;
404
- $content_pos += $length;
405
- }
406
-
407
- return array(
408
- 'type' => $class,
409
- 'constant' => $tag,
410
- // the array encapsulation is for BC with the old format
411
- 'content' => $newcontent,
412
- // the only time when $content['headerlength'] isn't defined is when the length is indefinite.
413
- // the absence of $content['headerlength'] is how we know if something is indefinite or not.
414
- // technically, it could be defined to be 2 and then another indicator could be used but whatever.
415
- 'length' => $start - $current['start']
416
- ) + $current;
417
- }
418
-
419
- $current+= array('type' => $tag);
420
-
421
- // decode UNIVERSAL tags
422
- switch ($tag) {
423
- case FILE_ASN1_TYPE_BOOLEAN:
424
- // "The contents octets shall consist of a single octet." -- paragraph 8.2.1
425
- //if (strlen($content) != 1) {
426
- // return false;
427
- //}
428
- $current['content'] = (bool) ord($content[$content_pos]);
429
- break;
430
- case FILE_ASN1_TYPE_INTEGER:
431
- case FILE_ASN1_TYPE_ENUMERATED:
432
- $current['content'] = new Math_BigInteger(substr($content, $content_pos), -256);
433
- break;
434
- case FILE_ASN1_TYPE_REAL: // not currently supported
435
- return false;
436
- case FILE_ASN1_TYPE_BIT_STRING:
437
- // The initial octet shall encode, as an unsigned binary integer with bit 1 as the least significant bit,
438
- // the number of unused bits in the final subsequent octet. The number shall be in the range zero to
439
- // seven.
440
- if (!$constructed) {
441
- $current['content'] = substr($content, $content_pos);
442
- } else {
443
- $temp = $this->_decode_ber($content, $start, $content_pos);
444
- $length-= (strlen($content) - $content_pos);
445
- $last = count($temp) - 1;
446
- for ($i = 0; $i < $last; $i++) {
447
- // all subtags should be bit strings
448
- //if ($temp[$i]['type'] != FILE_ASN1_TYPE_BIT_STRING) {
449
- // return false;
450
- //}
451
- $current['content'].= substr($temp[$i]['content'], 1);
452
- }
453
- // all subtags should be bit strings
454
- //if ($temp[$last]['type'] != FILE_ASN1_TYPE_BIT_STRING) {
455
- // return false;
456
- //}
457
- $current['content'] = $temp[$last]['content'][0] . $current['content'] . substr($temp[$i]['content'], 1);
458
- }
459
- break;
460
- case FILE_ASN1_TYPE_OCTET_STRING:
461
- if (!$constructed) {
462
- $current['content'] = substr($content, $content_pos);
463
- } else {
464
- $current['content'] = '';
465
- $length = 0;
466
- while (substr($content, $content_pos, 2) != "\0\0") {
467
- $temp = $this->_decode_ber($content, $length + $start, $content_pos);
468
- $content_pos += $temp['length'];
469
- // all subtags should be octet strings
470
- //if ($temp['type'] != FILE_ASN1_TYPE_OCTET_STRING) {
471
- // return false;
472
- //}
473
- $current['content'].= $temp['content'];
474
- $length+= $temp['length'];
475
- }
476
- if (substr($content, $content_pos, 2) == "\0\0") {
477
- $length+= 2; // +2 for the EOC
478
- }
479
- }
480
- break;
481
- case FILE_ASN1_TYPE_NULL:
482
- // "The contents octets shall not contain any octets." -- paragraph 8.8.2
483
- //if (strlen($content)) {
484
- // return false;
485
- //}
486
- break;
487
- case FILE_ASN1_TYPE_SEQUENCE:
488
- case FILE_ASN1_TYPE_SET:
489
- $offset = 0;
490
- $current['content'] = array();
491
- $content_len = strlen($content);
492
- while ($content_pos < $content_len) {
493
- // if indefinite length construction was used and we have an end-of-content string next
494
- // 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
495
- if (!isset($current['headerlength']) && substr($content, $content_pos, 2) == "\0\0") {
496
- $length = $offset + 2; // +2 for the EOC
497
- break 2;
498
- }
499
- $temp = $this->_decode_ber($content, $start + $offset, $content_pos);
500
- $content_pos += $temp['length'];
501
- $current['content'][] = $temp;
502
- $offset+= $temp['length'];
503
- }
504
- break;
505
- case FILE_ASN1_TYPE_OBJECT_IDENTIFIER:
506
- $temp = ord($content[$content_pos++]);
507
- $current['content'] = sprintf('%d.%d', floor($temp / 40), $temp % 40);
508
- $valuen = 0;
509
- // process septets
510
- $content_len = strlen($content);
511
- while ($content_pos < $content_len) {
512
- $temp = ord($content[$content_pos++]);
513
- $valuen <<= 7;
514
- $valuen |= $temp & 0x7F;
515
- if (~$temp & 0x80) {
516
- $current['content'].= ".$valuen";
517
- $valuen = 0;
518
- }
519
- }
520
- // the eighth bit of the last byte should not be 1
521
- //if ($temp >> 7) {
522
- // return false;
523
- //}
524
- break;
525
- /* Each character string type shall be encoded as if it had been declared:
526
- [UNIVERSAL x] IMPLICIT OCTET STRING
527
-
528
- -- X.690-0207.pdf#page=23 (paragraph 8.21.3)
529
-
530
- Per that, we're not going to do any validation. If there are any illegal characters in the string,
531
- we don't really care */
532
- case FILE_ASN1_TYPE_NUMERIC_STRING:
533
- // 0,1,2,3,4,5,6,7,8,9, and space
534
- case FILE_ASN1_TYPE_PRINTABLE_STRING:
535
- // Upper and lower case letters, digits, space, apostrophe, left/right parenthesis, plus sign, comma,
536
- // hyphen, full stop, solidus, colon, equal sign, question mark
537
- case FILE_ASN1_TYPE_TELETEX_STRING:
538
- // The Teletex character set in CCITT's T61, space, and delete
539
- // see http://en.wikipedia.org/wiki/Teletex#Character_sets
540
- case FILE_ASN1_TYPE_VIDEOTEX_STRING:
541
- // The Videotex character set in CCITT's T.100 and T.101, space, and delete
542
- case FILE_ASN1_TYPE_VISIBLE_STRING:
543
- // Printing character sets of international ASCII, and space
544
- case FILE_ASN1_TYPE_IA5_STRING:
545
- // International Alphabet 5 (International ASCII)
546
- case FILE_ASN1_TYPE_GRAPHIC_STRING:
547
- // All registered G sets, and space
548
- case FILE_ASN1_TYPE_GENERAL_STRING:
549
- // All registered C and G sets, space and delete
550
- case FILE_ASN1_TYPE_UTF8_STRING:
551
- // ????
552
- case FILE_ASN1_TYPE_BMP_STRING:
553
- $current['content'] = substr($content, $content_pos);
554
- break;
555
- case FILE_ASN1_TYPE_UTC_TIME:
556
- case FILE_ASN1_TYPE_GENERALIZED_TIME:
557
- $current['content'] = $this->_decodeTime(substr($content, $content_pos), $tag);
558
- default:
559
- }
560
-
561
- $start+= $length;
562
-
563
- // ie. length is the length of the full TLV encoding - it's not just the length of the value
564
- return $current + array('length' => $start - $current['start']);
565
- }
566
-
567
- /**
568
- * ASN.1 Map
569
- *
570
- * Provides an ASN.1 semantic mapping ($mapping) from a parsed BER-encoding to a human readable format.
571
- *
572
- * "Special" mappings may be applied on a per tag-name basis via $special.
573
- *
574
- * @param array $decoded
575
- * @param array $mapping
576
- * @param array $special
577
- * @return array
578
- * @access public
579
- */
580
- function asn1map($decoded, $mapping, $special = array())
581
- {
582
- if (isset($mapping['explicit']) && is_array($decoded['content'])) {
583
- $decoded = $decoded['content'][0];
584
- }
585
-
586
- switch (true) {
587
- case $mapping['type'] == FILE_ASN1_TYPE_ANY:
588
- $intype = $decoded['type'];
589
- if (isset($decoded['constant']) || !isset($this->ANYmap[$intype]) || (ord($this->encoded[$decoded['start']]) & 0x20)) {
590
- return new File_ASN1_Element(substr($this->encoded, $decoded['start'], $decoded['length']));
591
- }
592
- $inmap = $this->ANYmap[$intype];
593
- if (is_string($inmap)) {
594
- return array($inmap => $this->asn1map($decoded, array('type' => $intype) + $mapping, $special));
595
- }
596
- break;
597
- case $mapping['type'] == FILE_ASN1_TYPE_CHOICE:
598
- foreach ($mapping['children'] as $key => $option) {
599
- switch (true) {
600
- case isset($option['constant']) && $option['constant'] == $decoded['constant']:
601
- case !isset($option['constant']) && $option['type'] == $decoded['type']:
602
- $value = $this->asn1map($decoded, $option, $special);
603
- break;
604
- case !isset($option['constant']) && $option['type'] == FILE_ASN1_TYPE_CHOICE:
605
- $v = $this->asn1map($decoded, $option, $special);
606
- if (isset($v)) {
607
- $value = $v;
608
- }
609
- }
610
- if (isset($value)) {
611
- if (isset($special[$key])) {
612
- $value = call_user_func($special[$key], $value);
613
- }
614
- return array($key => $value);
615
- }
616
- }
617
- return null;
618
- case isset($mapping['implicit']):
619
- case isset($mapping['explicit']):
620
- case $decoded['type'] == $mapping['type']:
621
- break;
622
- default:
623
- // if $decoded['type'] and $mapping['type'] are both strings, but different types of strings,
624
- // let it through
625
- switch (true) {
626
- case $decoded['type'] < 18: // FILE_ASN1_TYPE_NUMERIC_STRING == 18
627
- case $decoded['type'] > 30: // FILE_ASN1_TYPE_BMP_STRING == 30
628
- case $mapping['type'] < 18:
629
- case $mapping['type'] > 30:
630
- return null;
631
- }
632
- }
633
-
634
- if (isset($mapping['implicit'])) {
635
- $decoded['type'] = $mapping['type'];
636
- }
637
-
638
- switch ($decoded['type']) {
639
- case FILE_ASN1_TYPE_SEQUENCE:
640
- $map = array();
641
-
642
- // ignore the min and max
643
- if (isset($mapping['min']) && isset($mapping['max'])) {
644
- $child = $mapping['children'];
645
- foreach ($decoded['content'] as $content) {
646
- if (($map[] = $this->asn1map($content, $child, $special)) === null) {
647
- return null;
648
- }
649
- }
650
-
651
- return $map;
652
- }
653
-
654
- $n = count($decoded['content']);
655
- $i = 0;
656
-
657
- foreach ($mapping['children'] as $key => $child) {
658
- $maymatch = $i < $n; // Match only existing input.
659
- if ($maymatch) {
660
- $temp = $decoded['content'][$i];
661
-
662
- if ($child['type'] != FILE_ASN1_TYPE_CHOICE) {
663
- // Get the mapping and input class & constant.
664
- $childClass = $tempClass = FILE_ASN1_CLASS_UNIVERSAL;
665
- $constant = null;
666
- if (isset($temp['constant'])) {
667
- $tempClass = isset($temp['class']) ? $temp['class'] : FILE_ASN1_CLASS_CONTEXT_SPECIFIC;
668
- }
669
- if (isset($child['class'])) {
670
- $childClass = $child['class'];
671
- $constant = $child['cast'];
672
- } elseif (isset($child['constant'])) {
673
- $childClass = FILE_ASN1_CLASS_CONTEXT_SPECIFIC;
674
- $constant = $child['constant'];
675
- }
676
-
677
- if (isset($constant) && isset($temp['constant'])) {
678
- // Can only match if constants and class match.
679
- $maymatch = $constant == $temp['constant'] && $childClass == $tempClass;
680
- } else {
681
- // Can only match if no constant expected and type matches or is generic.
682
- $maymatch = !isset($child['constant']) && array_search($child['type'], array($temp['type'], FILE_ASN1_TYPE_ANY, FILE_ASN1_TYPE_CHOICE)) !== false;
683
- }
684
- }
685
- }
686
-
687
- if ($maymatch) {
688
- // Attempt submapping.
689
- $candidate = $this->asn1map($temp, $child, $special);
690
- $maymatch = $candidate !== null;
691
- }
692
-
693
- if ($maymatch) {
694
- // Got the match: use it.
695
- if (isset($special[$key])) {
696
- $candidate = call_user_func($special[$key], $candidate);
697
- }
698
- $map[$key] = $candidate;
699
- $i++;
700
- } elseif (isset($child['default'])) {
701
- $map[$key] = $child['default']; // Use default.
702
- } elseif (!isset($child['optional'])) {
703
- return null; // Syntax error.
704
- }
705
- }
706
-
707
- // Fail mapping if all input items have not been consumed.
708
- return $i < $n ? null: $map;
709
-
710
- // the main diff between sets and sequences is the encapsulation of the foreach in another for loop
711
- case FILE_ASN1_TYPE_SET:
712
- $map = array();
713
-
714
- // ignore the min and max
715
- if (isset($mapping['min']) && isset($mapping['max'])) {
716
- $child = $mapping['children'];
717
- foreach ($decoded['content'] as $content) {
718
- if (($map[] = $this->asn1map($content, $child, $special)) === null) {
719
- return null;
720
- }
721
- }
722
-
723
- return $map;
724
- }
725
-
726
- for ($i = 0; $i < count($decoded['content']); $i++) {
727
- $temp = $decoded['content'][$i];
728
- $tempClass = FILE_ASN1_CLASS_UNIVERSAL;
729
- if (isset($temp['constant'])) {
730
- $tempClass = isset($temp['class']) ? $temp['class'] : FILE_ASN1_CLASS_CONTEXT_SPECIFIC;
731
- }
732
-
733
- foreach ($mapping['children'] as $key => $child) {
734
- if (isset($map[$key])) {
735
- continue;
736
- }
737
- $maymatch = true;
738
- if ($child['type'] != FILE_ASN1_TYPE_CHOICE) {
739
- $childClass = FILE_ASN1_CLASS_UNIVERSAL;
740
- $constant = null;
741
- if (isset($child['class'])) {
742
- $childClass = $child['class'];
743
- $constant = $child['cast'];
744
- } elseif (isset($child['constant'])) {
745
- $childClass = FILE_ASN1_CLASS_CONTEXT_SPECIFIC;
746
- $constant = $child['constant'];
747
- }
748
-
749
- if (isset($constant) && isset($temp['constant'])) {
750
- // Can only match if constants and class match.
751
- $maymatch = $constant == $temp['constant'] && $childClass == $tempClass;
752
- } else {
753
- // Can only match if no constant expected and type matches or is generic.
754
- $maymatch = !isset($child['constant']) && array_search($child['type'], array($temp['type'], FILE_ASN1_TYPE_ANY, FILE_ASN1_TYPE_CHOICE)) !== false;
755
- }
756
- }
757
-
758
- if ($maymatch) {
759
- // Attempt submapping.
760
- $candidate = $this->asn1map($temp, $child, $special);
761
- $maymatch = $candidate !== null;
762
- }
763
-
764
- if (!$maymatch) {
765
- break;
766
- }
767
-
768
- // Got the match: use it.
769
- if (isset($special[$key])) {
770
- $candidate = call_user_func($special[$key], $candidate);
771
- }
772
- $map[$key] = $candidate;
773
- break;
774
- }
775
- }
776
-
777
- foreach ($mapping['children'] as $key => $child) {
778
- if (!isset($map[$key])) {
779
- if (isset($child['default'])) {
780
- $map[$key] = $child['default'];
781
- } elseif (!isset($child['optional'])) {
782
- return null;
783
- }
784
- }
785
- }
786
- return $map;
787
- case FILE_ASN1_TYPE_OBJECT_IDENTIFIER:
788
- return isset($this->oids[$decoded['content']]) ? $this->oids[$decoded['content']] : $decoded['content'];
789
- case FILE_ASN1_TYPE_UTC_TIME:
790
- case FILE_ASN1_TYPE_GENERALIZED_TIME:
791
- if (isset($mapping['implicit'])) {
792
- $decoded['content'] = $this->_decodeTime($decoded['content'], $decoded['type']);
793
- }
794
- return @date($this->format, $decoded['content']);
795
- case FILE_ASN1_TYPE_BIT_STRING:
796
- if (isset($mapping['mapping'])) {
797
- $offset = ord($decoded['content'][0]);
798
- $size = (strlen($decoded['content']) - 1) * 8 - $offset;
799
- /*
800
- From X.680-0207.pdf#page=46 (21.7):
801
-
802
- "When a "NamedBitList" is used in defining a bitstring type ASN.1 encoding rules are free to add (or remove)
803
- arbitrarily any trailing 0 bits to (or from) values that are being encoded or decoded. Application designers should
804
- therefore ensure that different semantics are not associated with such values which differ only in the number of trailing
805
- 0 bits."
806
- */
807
- $bits = count($mapping['mapping']) == $size ? array() : array_fill(0, count($mapping['mapping']) - $size, false);
808
- for ($i = strlen($decoded['content']) - 1; $i > 0; $i--) {
809
- $current = ord($decoded['content'][$i]);
810
- for ($j = $offset; $j < 8; $j++) {
811
- $bits[] = (bool) ($current & (1 << $j));
812
- }
813
- $offset = 0;
814
- }
815
- $values = array();
816
- $map = array_reverse($mapping['mapping']);
817
- foreach ($map as $i => $value) {
818
- if ($bits[$i]) {
819
- $values[] = $value;
820
- }
821
- }
822
- return $values;
823
- }
824
- case FILE_ASN1_TYPE_OCTET_STRING:
825
- return base64_encode($decoded['content']);
826
- case FILE_ASN1_TYPE_NULL:
827
- return '';
828
- case FILE_ASN1_TYPE_BOOLEAN:
829
- return $decoded['content'];
830
- case FILE_ASN1_TYPE_NUMERIC_STRING:
831
- case FILE_ASN1_TYPE_PRINTABLE_STRING:
832
- case FILE_ASN1_TYPE_TELETEX_STRING:
833
- case FILE_ASN1_TYPE_VIDEOTEX_STRING:
834
- case FILE_ASN1_TYPE_IA5_STRING:
835
- case FILE_ASN1_TYPE_GRAPHIC_STRING:
836
- case FILE_ASN1_TYPE_VISIBLE_STRING:
837
- case FILE_ASN1_TYPE_GENERAL_STRING:
838
- case FILE_ASN1_TYPE_UNIVERSAL_STRING:
839
- case FILE_ASN1_TYPE_UTF8_STRING:
840
- case FILE_ASN1_TYPE_BMP_STRING:
841
- return $decoded['content'];
842
- case FILE_ASN1_TYPE_INTEGER:
843
- case FILE_ASN1_TYPE_ENUMERATED:
844
- $temp = $decoded['content'];
845
- if (isset($mapping['implicit'])) {
846
- $temp = new Math_BigInteger($decoded['content'], -256);
847
- }
848
- if (isset($mapping['mapping'])) {
849
- $temp = (int) $temp->toString();
850
- return isset($mapping['mapping'][$temp]) ?
851
- $mapping['mapping'][$temp] :
852
- false;
853
- }
854
- return $temp;
855
- }
856
- }
857
-
858
- /**
859
- * ASN.1 Encode
860
- *
861
- * DER-encodes an ASN.1 semantic mapping ($mapping). Some libraries would probably call this function
862
- * an ASN.1 compiler.
863
- *
864
- * "Special" mappings can be applied via $special.
865
- *
866
- * @param string $source
867
- * @param string $mapping
868
- * @param int $idx
869
- * @return string
870
- * @access public
871
- */
872
- function encodeDER($source, $mapping, $special = array())
873
- {
874
- $this->location = array();
875
- return $this->_encode_der($source, $mapping, null, $special);
876
- }
877
-
878
- /**
879
- * ASN.1 Encode (Helper function)
880
- *
881
- * @param string $source
882
- * @param string $mapping
883
- * @param int $idx
884
- * @return string
885
- * @access private
886
- */
887
- function _encode_der($source, $mapping, $idx = null, $special = array())
888
- {
889
- if (is_object($source) && strtolower(get_class($source)) == 'file_asn1_element') {
890
- return $source->element;
891
- }
892
-
893
- // do not encode (implicitly optional) fields with value set to default
894
- if (isset($mapping['default']) && $source === $mapping['default']) {
895
- return '';
896
- }
897
-
898
- if (isset($idx)) {
899
- if (isset($special[$idx])) {
900
- $source = call_user_func($special[$idx], $source);
901
- }
902
- $this->location[] = $idx;
903
- }
904
-
905
- $tag = $mapping['type'];
906
-
907
- switch ($tag) {
908
- case FILE_ASN1_TYPE_SET: // Children order is not important, thus process in sequence.
909
- case FILE_ASN1_TYPE_SEQUENCE:
910
- $tag|= 0x20; // set the constructed bit
911
-
912
- // ignore the min and max
913
- if (isset($mapping['min']) && isset($mapping['max'])) {
914
- $value = array();
915
- $child = $mapping['children'];
916
-
917
- foreach ($source as $content) {
918
- $temp = $this->_encode_der($content, $child, null, $special);
919
- if ($temp === false) {
920
- return false;
921
- }
922
- $value[]= $temp;
923
- }
924
- /* "The encodings of the component values of a set-of value shall appear in ascending order, the encodings being compared
925
- as octet strings with the shorter components being padded at their trailing end with 0-octets.
926
- NOTE - The padding octets are for comparison purposes only and do not appear in the encodings."
927
-
928
- -- sec 11.6 of http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf */
929
- if ($mapping['type'] == FILE_ASN1_TYPE_SET) {
930
- sort($value);
931
- }
932
- $value = implode($value, '');
933
- break;
934
- }
935
-
936
- $value = '';
937
- foreach ($mapping['children'] as $key => $child) {
938
- if (!array_key_exists($key, $source)) {
939
- if (!isset($child['optional'])) {
940
- return false;
941
- }
942
- continue;
943
- }
944
-
945
- $temp = $this->_encode_der($source[$key], $child, $key, $special);
946
- if ($temp === false) {
947
- return false;
948
- }
949
-
950
- // An empty child encoding means it has been optimized out.
951
- // Else we should have at least one tag byte.
952
- if ($temp === '') {
953
- continue;
954
- }
955
-
956
- // if isset($child['constant']) is true then isset($child['optional']) should be true as well
957
- if (isset($child['constant'])) {
958
- /*
959
- From X.680-0207.pdf#page=58 (30.6):
960
-
961
- "The tagging construction specifies explicit tagging if any of the following holds:
962
- ...
963
- c) the "Tag Type" alternative is used and the value of "TagDefault" for the module is IMPLICIT TAGS or
964
- AUTOMATIC TAGS, but the type defined by "Type" is an untagged choice type, an untagged open type, or
965
- an untagged "DummyReference" (see ITU-T Rec. X.683 | ISO/IEC 8824-4, 8.3)."
966
- */
967
- if (isset($child['explicit']) || $child['type'] == FILE_ASN1_TYPE_CHOICE) {
968
- $subtag = chr((FILE_ASN1_CLASS_CONTEXT_SPECIFIC << 6) | 0x20 | $child['constant']);
969
- $temp = $subtag . $this->_encodeLength(strlen($temp)) . $temp;
970
- } else {
971
- $subtag = chr((FILE_ASN1_CLASS_CONTEXT_SPECIFIC << 6) | (ord($temp[0]) & 0x20) | $child['constant']);
972
- $temp = $subtag . substr($temp, 1);
973
- }
974
- }
975
- $value.= $temp;
976
- }
977
- break;
978
- case FILE_ASN1_TYPE_CHOICE:
979
- $temp = false;
980
-
981
- foreach ($mapping['children'] as $key => $child) {
982
- if (!isset($source[$key])) {
983
- continue;
984
- }
985
-
986
- $temp = $this->_encode_der($source[$key], $child, $key, $special);
987
- if ($temp === false) {
988
- return false;
989
- }
990
-
991
- // An empty child encoding means it has been optimized out.
992
- // Else we should have at least one tag byte.
993
- if ($temp === '') {
994
- continue;
995
- }
996
-
997
- $tag = ord($temp[0]);
998
-
999
- // if isset($child['constant']) is true then isset($child['optional']) should be true as well
1000
- if (isset($child['constant'])) {
1001
- if (isset($child['explicit']) || $child['type'] == FILE_ASN1_TYPE_CHOICE) {
1002
- $subtag = chr((FILE_ASN1_CLASS_CONTEXT_SPECIFIC << 6) | 0x20 | $child['constant']);
1003
- $temp = $subtag . $this->_encodeLength(strlen($temp)) . $temp;
1004
- } else {
1005
- $subtag = chr((FILE_ASN1_CLASS_CONTEXT_SPECIFIC << 6) | (ord($temp[0]) & 0x20) | $child['constant']);
1006
- $temp = $subtag . substr($temp, 1);
1007
- }
1008
- }
1009
- }
1010
-
1011
- if (isset($idx)) {
1012
- array_pop($this->location);
1013
- }
1014
-
1015
- if ($temp && isset($mapping['cast'])) {
1016
- $temp[0] = chr(($mapping['class'] << 6) | ($tag & 0x20) | $mapping['cast']);
1017
- }
1018
-
1019
- return $temp;
1020
- case FILE_ASN1_TYPE_INTEGER:
1021
- case FILE_ASN1_TYPE_ENUMERATED:
1022
- if (!isset($mapping['mapping'])) {
1023
- if (is_numeric($source)) {
1024
- $source = new Math_BigInteger($source);
1025
- }
1026
- $value = $source->toBytes(true);
1027
- } else {
1028
- $value = array_search($source, $mapping['mapping']);
1029
- if ($value === false) {
1030
- return false;
1031
- }
1032
- $value = new Math_BigInteger($value);
1033
- $value = $value->toBytes(true);
1034
- }
1035
- if (!strlen($value)) {
1036
- $value = chr(0);
1037
- }
1038
- break;
1039
- case FILE_ASN1_TYPE_UTC_TIME:
1040
- case FILE_ASN1_TYPE_GENERALIZED_TIME:
1041
- $format = $mapping['type'] == FILE_ASN1_TYPE_UTC_TIME ? 'y' : 'Y';
1042
- $format.= 'mdHis';
1043
- $value = @gmdate($format, strtotime($source)) . 'Z';
1044
- break;
1045
- case FILE_ASN1_TYPE_BIT_STRING:
1046
- if (isset($mapping['mapping'])) {
1047
- $bits = array_fill(0, count($mapping['mapping']), 0);
1048
- $size = 0;
1049
- for ($i = 0; $i < count($mapping['mapping']); $i++) {
1050
- if (in_array($mapping['mapping'][$i], $source)) {
1051
- $bits[$i] = 1;
1052
- $size = $i;
1053
- }
1054
- }
1055
-
1056
- if (isset($mapping['min']) && $mapping['min'] >= 1 && $size < $mapping['min']) {
1057
- $size = $mapping['min'] - 1;
1058
- }
1059
-
1060
- $offset = 8 - (($size + 1) & 7);
1061
- $offset = $offset !== 8 ? $offset : 0;
1062
-
1063
- $value = chr($offset);
1064
-
1065
- for ($i = $size + 1; $i < count($mapping['mapping']); $i++) {
1066
- unset($bits[$i]);
1067
- }
1068
-
1069
- $bits = implode('', array_pad($bits, $size + $offset + 1, 0));
1070
- $bytes = explode(' ', rtrim(chunk_split($bits, 8, ' ')));
1071
- foreach ($bytes as $byte) {
1072
- $value.= chr(bindec($byte));
1073
- }
1074
-
1075
- break;
1076
- }
1077
- case FILE_ASN1_TYPE_OCTET_STRING:
1078
- /* The initial octet shall encode, as an unsigned binary integer with bit 1 as the least significant bit,
1079
- the number of unused bits in the final subsequent octet. The number shall be in the range zero to seven.
1080
-
1081
- -- http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#page=16 */
1082
- $value = base64_decode($source);
1083
- break;
1084
- case FILE_ASN1_TYPE_OBJECT_IDENTIFIER:
1085
- $oid = preg_match('#(?:\d+\.)+#', $source) ? $source : array_search($source, $this->oids);
1086
- if ($oid === false) {
1087
- user_error('Invalid OID');
1088
- return false;
1089
- }
1090
- $value = '';
1091
- $parts = explode('.', $oid);
1092
- $value = chr(40 * $parts[0] + $parts[1]);
1093
- for ($i = 2; $i < count($parts); $i++) {
1094
- $temp = '';
1095
- if (!$parts[$i]) {
1096
- $temp = "\0";
1097
- } else {
1098
- while ($parts[$i]) {
1099
- $temp = chr(0x80 | ($parts[$i] & 0x7F)) . $temp;
1100
- $parts[$i] >>= 7;
1101
- }
1102
- $temp[strlen($temp) - 1] = $temp[strlen($temp) - 1] & chr(0x7F);
1103
- }
1104
- $value.= $temp;
1105
- }
1106
- break;
1107
- case FILE_ASN1_TYPE_ANY:
1108
- $loc = $this->location;
1109
- if (isset($idx)) {
1110
- array_pop($this->location);
1111
- }
1112
-
1113
- switch (true) {
1114
- case !isset($source):
1115
- return $this->_encode_der(null, array('type' => FILE_ASN1_TYPE_NULL) + $mapping, null, $special);
1116
- case is_int($source):
1117
- case is_object($source) && strtolower(get_class($source)) == 'math_biginteger':
1118
- return $this->_encode_der($source, array('type' => FILE_ASN1_TYPE_INTEGER) + $mapping, null, $special);
1119
- case is_float($source):
1120
- return $this->_encode_der($source, array('type' => FILE_ASN1_TYPE_REAL) + $mapping, null, $special);
1121
- case is_bool($source):
1122
- return $this->_encode_der($source, array('type' => FILE_ASN1_TYPE_BOOLEAN) + $mapping, null, $special);
1123
- case is_array($source) && count($source) == 1:
1124
- $typename = implode('', array_keys($source));
1125
- $outtype = array_search($typename, $this->ANYmap, true);
1126
- if ($outtype !== false) {
1127
- return $this->_encode_der($source[$typename], array('type' => $outtype) + $mapping, null, $special);
1128
- }
1129
- }
1130
-
1131
- $filters = $this->filters;
1132
- foreach ($loc as $part) {
1133
- if (!isset($filters[$part])) {
1134
- $filters = false;
1135
- break;
1136
- }
1137
- $filters = $filters[$part];
1138
- }
1139
- if ($filters === false) {
1140
- user_error('No filters defined for ' . implode('/', $loc));
1141
- return false;
1142
- }
1143
- return $this->_encode_der($source, $filters + $mapping, null, $special);
1144
- case FILE_ASN1_TYPE_NULL:
1145
- $value = '';
1146
- break;
1147
- case FILE_ASN1_TYPE_NUMERIC_STRING:
1148
- case FILE_ASN1_TYPE_TELETEX_STRING:
1149
- case FILE_ASN1_TYPE_PRINTABLE_STRING:
1150
- case FILE_ASN1_TYPE_UNIVERSAL_STRING:
1151
- case FILE_ASN1_TYPE_UTF8_STRING:
1152
- case FILE_ASN1_TYPE_BMP_STRING:
1153
- case FILE_ASN1_TYPE_IA5_STRING:
1154
- case FILE_ASN1_TYPE_VISIBLE_STRING:
1155
- case FILE_ASN1_TYPE_VIDEOTEX_STRING:
1156
- case FILE_ASN1_TYPE_GRAPHIC_STRING:
1157
- case FILE_ASN1_TYPE_GENERAL_STRING:
1158
- $value = $source;
1159
- break;
1160
- case FILE_ASN1_TYPE_BOOLEAN:
1161
- $value = $source ? "\xFF" : "\x00";
1162
- break;
1163
- default:
1164
- user_error('Mapping provides no type definition for ' . implode('/', $this->location));
1165
- return false;
1166
- }
1167
-
1168
- if (isset($idx)) {
1169
- array_pop($this->location);
1170
- }
1171
-
1172
- if (isset($mapping['cast'])) {
1173
- if (isset($mapping['explicit']) || $mapping['type'] == FILE_ASN1_TYPE_CHOICE) {
1174
- $value = chr($tag) . $this->_encodeLength(strlen($value)) . $value;
1175
- $tag = ($mapping['class'] << 6) | 0x20 | $mapping['cast'];
1176
- } else {
1177
- $tag = ($mapping['class'] << 6) | (ord($temp[0]) & 0x20) | $mapping['cast'];
1178
- }
1179
- }
1180
-
1181
- return chr($tag) . $this->_encodeLength(strlen($value)) . $value;
1182
- }
1183
-
1184
- /**
1185
- * DER-encode the length
1186
- *
1187
- * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See
1188
- * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information.
1189
- *
1190
- * @access private
1191
- * @param int $length
1192
- * @return string
1193
- */
1194
- function _encodeLength($length)
1195
- {
1196
- if ($length <= 0x7F) {
1197
- return chr($length);
1198
- }
1199
-
1200
- $temp = ltrim(pack('N', $length), chr(0));
1201
- return pack('Ca*', 0x80 | strlen($temp), $temp);
1202
- }
1203
-
1204
- /**
1205
- * BER-decode the time
1206
- *
1207
- * Called by _decode_ber() and in the case of implicit tags asn1map().
1208
- *
1209
- * @access private
1210
- * @param string $content
1211
- * @param int $tag
1212
- * @return string
1213
- */
1214
- function _decodeTime($content, $tag)
1215
- {
1216
- /* UTCTime:
1217
- http://tools.ietf.org/html/rfc5280#section-4.1.2.5.1
1218
- http://www.obj-sys.com/asn1tutorial/node15.html
1219
-
1220
- GeneralizedTime:
1221
- http://tools.ietf.org/html/rfc5280#section-4.1.2.5.2
1222
- http://www.obj-sys.com/asn1tutorial/node14.html */
1223
-
1224
- $pattern = $tag == FILE_ASN1_TYPE_UTC_TIME ?
1225
- '#(..)(..)(..)(..)(..)(..)(.*)#' :
1226
- '#(....)(..)(..)(..)(..)(..).*([Z+-].*)$#';
1227
-
1228
- preg_match($pattern, $content, $matches);
1229
-
1230
- list(, $year, $month, $day, $hour, $minute, $second, $timezone) = $matches;
1231
-
1232
- if ($tag == FILE_ASN1_TYPE_UTC_TIME) {
1233
- $year = $year >= 50 ? "19$year" : "20$year";
1234
- }
1235
-
1236
- if ($timezone == 'Z') {
1237
- $mktime = 'gmmktime';
1238
- $timezone = 0;
1239
- } elseif (preg_match('#([+-])(\d\d)(\d\d)#', $timezone, $matches)) {
1240
- $mktime = 'gmmktime';
1241
- $timezone = 60 * $matches[3] + 3600 * $matches[2];
1242
- if ($matches[1] == '-') {
1243
- $timezone = -$timezone;
1244
- }
1245
- } else {
1246
- $mktime = 'mktime';
1247
- $timezone = 0;
1248
- }
1249
-
1250
- return @$mktime($hour, $minute, $second, $month, $day, $year) + $timezone;
1251
- }
1252
-
1253
- /**
1254
- * Set the time format
1255
- *
1256
- * Sets the time / date format for asn1map().
1257
- *
1258
- * @access public
1259
- * @param string $format
1260
- */
1261
- function setTimeFormat($format)
1262
- {
1263
- $this->format = $format;
1264
- }
1265
-
1266
- /**
1267
- * Load OIDs
1268
- *
1269
- * Load the relevant OIDs for a particular ASN.1 semantic mapping.
1270
- *
1271
- * @access public
1272
- * @param array $oids
1273
- */
1274
- function loadOIDs($oids)
1275
- {
1276
- $this->oids = $oids;
1277
- }
1278
-
1279
- /**
1280
- * Load filters
1281
- *
1282
- * See File_X509, etc, for an example.
1283
- *
1284
- * @access public
1285
- * @param array $filters
1286
- */
1287
- function loadFilters($filters)
1288
- {
1289
- $this->filters = $filters;
1290
- }
1291
-
1292
- /**
1293
- * String Shift
1294
- *
1295
- * Inspired by array_shift
1296
- *
1297
- * @param string $string
1298
- * @param int $index
1299
- * @return string
1300
- * @access private
1301
- */
1302
- function _string_shift(&$string, $index = 1)
1303
- {
1304
- $substr = substr($string, 0, $index);
1305
- $string = substr($string, $index);
1306
- return $substr;
1307
- }
1308
-
1309
- /**
1310
- * String type conversion
1311
- *
1312
- * This is a lazy conversion, dealing only with character size.
1313
- * No real conversion table is used.
1314
- *
1315
- * @param string $in
1316
- * @param int $from
1317
- * @param int $to
1318
- * @return string
1319
- * @access public
1320
- */
1321
- function convert($in, $from = FILE_ASN1_TYPE_UTF8_STRING, $to = FILE_ASN1_TYPE_UTF8_STRING)
1322
- {
1323
- if (!isset($this->stringTypeSize[$from]) || !isset($this->stringTypeSize[$to])) {
1324
- return false;
1325
- }
1326
- $insize = $this->stringTypeSize[$from];
1327
- $outsize = $this->stringTypeSize[$to];
1328
- $inlength = strlen($in);
1329
- $out = '';
1330
-
1331
- for ($i = 0; $i < $inlength;) {
1332
- if ($inlength - $i < $insize) {
1333
- return false;
1334
- }
1335
-
1336
- // Get an input character as a 32-bit value.
1337
- $c = ord($in[$i++]);
1338
- switch (true) {
1339
- case $insize == 4:
1340
- $c = ($c << 8) | ord($in[$i++]);
1341
- $c = ($c << 8) | ord($in[$i++]);
1342
- case $insize == 2:
1343
- $c = ($c << 8) | ord($in[$i++]);
1344
- case $insize == 1:
1345
- break;
1346
- case ($c & 0x80) == 0x00:
1347
- break;
1348
- case ($c & 0x40) == 0x00:
1349
- return false;
1350
- default:
1351
- $bit = 6;
1352
- do {
1353
- if ($bit > 25 || $i >= $inlength || (ord($in[$i]) & 0xC0) != 0x80) {
1354
- return false;
1355
- }
1356
- $c = ($c << 6) | (ord($in[$i++]) & 0x3F);
1357
- $bit += 5;
1358
- $mask = 1 << $bit;
1359
- } while ($c & $bit);
1360
- $c &= $mask - 1;
1361
- break;
1362
- }
1363
-
1364
- // Convert and append the character to output string.
1365
- $v = '';
1366
- switch (true) {
1367
- case $outsize == 4:
1368
- $v .= chr($c & 0xFF);
1369
- $c >>= 8;
1370
- $v .= chr($c & 0xFF);
1371
- $c >>= 8;
1372
- case $outsize == 2:
1373
- $v .= chr($c & 0xFF);
1374
- $c >>= 8;
1375
- case $outsize == 1:
1376
- $v .= chr($c & 0xFF);
1377
- $c >>= 8;
1378
- if ($c) {
1379
- return false;
1380
- }
1381
- break;
1382
- case ($c & 0x80000000) != 0:
1383
- return false;
1384
- case $c >= 0x04000000:
1385
- $v .= chr(0x80 | ($c & 0x3F));
1386
- $c = ($c >> 6) | 0x04000000;
1387
- case $c >= 0x00200000:
1388
- $v .= chr(0x80 | ($c & 0x3F));
1389
- $c = ($c >> 6) | 0x00200000;
1390
- case $c >= 0x00010000:
1391
- $v .= chr(0x80 | ($c & 0x3F));
1392
- $c = ($c >> 6) | 0x00010000;
1393
- case $c >= 0x00000800:
1394
- $v .= chr(0x80 | ($c & 0x3F));
1395
- $c = ($c >> 6) | 0x00000800;
1396
- case $c >= 0x00000080:
1397
- $v .= chr(0x80 | ($c & 0x3F));
1398
- $c = ($c >> 6) | 0x000000C0;
1399
- default:
1400
- $v .= chr($c);
1401
- break;
1402
- }
1403
- $out .= strrev($v);
1404
- }
1405
- return $out;
1406
- }
1407
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/phpseclib/File/X509.php DELETED
@@ -1,4884 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Pure-PHP X.509 Parser
5
- *
6
- * PHP versions 4 and 5
7
- *
8
- * Encode and decode X.509 certificates.
9
- *
10
- * The extensions are from {@link http://tools.ietf.org/html/rfc5280 RFC5280} and
11
- * {@link http://web.archive.org/web/19961027104704/http://www3.netscape.com/eng/security/cert-exts.html Netscape Certificate Extensions}.
12
- *
13
- * Note that loading an X.509 certificate and resaving it may invalidate the signature. The reason being that the signature is based on a
14
- * portion of the certificate that contains optional parameters with default values. ie. if the parameter isn't there the default value is
15
- * 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
16
- * be encoded. It can be encoded explicitly or left out all together. This would effect the signature value and thus may invalidate the
17
- * the certificate all together unless the certificate is re-signed.
18
- *
19
- * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
20
- * of this software and associated documentation files (the "Software"), to deal
21
- * in the Software without restriction, including without limitation the rights
22
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
23
- * copies of the Software, and to permit persons to whom the Software is
24
- * furnished to do so, subject to the following conditions:
25
- *
26
- * The above copyright notice and this permission notice shall be included in
27
- * all copies or substantial portions of the Software.
28
- *
29
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
31
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
32
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
33
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
34
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
35
- * THE SOFTWARE.
36
- *
37
- * @category File
38
- * @package File_X509
39
- * @author Jim Wigginton <terrafrost@php.net>
40
- * @copyright 2012 Jim Wigginton
41
- * @license http://www.opensource.org/licenses/mit-license.html MIT License
42
- * @link http://phpseclib.sourceforge.net
43
- */
44
-
45
- /**
46
- * Include File_ASN1
47
- */
48
- if (!class_exists('File_ASN1')) {
49
- include_once 'ASN1.php';
50
- }
51
-
52
- /**
53
- * Flag to only accept signatures signed by certificate authorities
54
- *
55
- * Not really used anymore but retained all the same to suppress E_NOTICEs from old installs
56
- *
57
- * @access public
58
- */
59
- define('FILE_X509_VALIDATE_SIGNATURE_BY_CA', 1);
60
-
61
- /**#@+
62
- * @access public
63
- * @see self::getDN()
64
- */
65
- /**
66
- * Return internal array representation
67
- */
68
- define('FILE_X509_DN_ARRAY', 0);
69
- /**
70
- * Return string
71
- */
72
- define('FILE_X509_DN_STRING', 1);
73
- /**
74
- * Return ASN.1 name string
75
- */
76
- define('FILE_X509_DN_ASN1', 2);
77
- /**
78
- * Return OpenSSL compatible array
79
- */
80
- define('FILE_X509_DN_OPENSSL', 3);
81
- /**
82
- * Return canonical ASN.1 RDNs string
83
- */
84
- define('FILE_X509_DN_CANON', 4);
85
- /**
86
- * Return name hash for file indexing
87
- */
88
- define('FILE_X509_DN_HASH', 5);
89
- /**#@-*/
90
-
91
- /**#@+
92
- * @access public
93
- * @see self::saveX509()
94
- * @see self::saveCSR()
95
- * @see self::saveCRL()
96
- */
97
- /**
98
- * Save as PEM
99
- *
100
- * ie. a base64-encoded PEM with a header and a footer
101
- */
102
- define('FILE_X509_FORMAT_PEM', 0);
103
- /**
104
- * Save as DER
105
- */
106
- define('FILE_X509_FORMAT_DER', 1);
107
- /**
108
- * Save as a SPKAC
109
- *
110
- * Only works on CSRs. Not currently supported.
111
- */
112
- define('FILE_X509_FORMAT_SPKAC', 2);
113
- /**
114
- * Auto-detect the format
115
- *
116
- * Used only by the load*() functions
117
- */
118
- define('FILE_X509_FORMAT_AUTO_DETECT', 3);
119
- /**#@-*/
120
-
121
- /**
122
- * Attribute value disposition.
123
- * If disposition is >= 0, this is the index of the target value.
124
- */
125
- define('FILE_X509_ATTR_ALL', -1); // All attribute values (array).
126
- define('FILE_X509_ATTR_APPEND', -2); // Add a value.
127
- define('FILE_X509_ATTR_REPLACE', -3); // Clear first, then add a value.
128
-
129
- /**
130
- * Pure-PHP X.509 Parser
131
- *
132
- * @package File_X509
133
- * @author Jim Wigginton <terrafrost@php.net>
134
- * @access public
135
- */
136
- class File_X509
137
- {
138
- /**
139
- * ASN.1 syntax for X.509 certificates
140
- *
141
- * @var array
142
- * @access private
143
- */
144
- var $Certificate;
145
-
146
- /**#@+
147
- * ASN.1 syntax for various extensions
148
- *
149
- * @access private
150
- */
151
- var $DirectoryString;
152
- var $PKCS9String;
153
- var $AttributeValue;
154
- var $Extensions;
155
- var $KeyUsage;
156
- var $ExtKeyUsageSyntax;
157
- var $BasicConstraints;
158
- var $KeyIdentifier;
159
- var $CRLDistributionPoints;
160
- var $AuthorityKeyIdentifier;
161
- var $CertificatePolicies;
162
- var $AuthorityInfoAccessSyntax;
163
- var $SubjectAltName;
164
- var $SubjectDirectoryAttributes;
165
- var $PrivateKeyUsagePeriod;
166
- var $IssuerAltName;
167
- var $PolicyMappings;
168
- var $NameConstraints;
169
-
170
- var $CPSuri;
171
- var $UserNotice;
172
-
173
- var $netscape_cert_type;
174
- var $netscape_comment;
175
- var $netscape_ca_policy_url;
176
-
177
- var $Name;
178
- var $RelativeDistinguishedName;
179
- var $CRLNumber;
180
- var $CRLReason;
181
- var $IssuingDistributionPoint;
182
- var $InvalidityDate;
183
- var $CertificateIssuer;
184
- var $HoldInstructionCode;
185
- var $SignedPublicKeyAndChallenge;
186
- /**#@-*/
187
-
188
- /**#@+
189
- * ASN.1 syntax for various DN attributes
190
- *
191
- * @access private
192
- */
193
- var $PostalAddress;
194
- /**#@-*/
195
-
196
- /**
197
- * ASN.1 syntax for Certificate Signing Requests (RFC2986)
198
- *
199
- * @var array
200
- * @access private
201
- */
202
- var $CertificationRequest;
203
-
204
- /**
205
- * ASN.1 syntax for Certificate Revocation Lists (RFC5280)
206
- *
207
- * @var array
208
- * @access private
209
- */
210
- var $CertificateList;
211
-
212
- /**
213
- * Distinguished Name
214
- *
215
- * @var array
216
- * @access private
217
- */
218
- var $dn;
219
-
220
- /**
221
- * Public key
222
- *
223
- * @var string
224
- * @access private
225
- */
226
- var $publicKey;
227
-
228
- /**
229
- * Private key
230
- *
231
- * @var string
232
- * @access private
233
- */
234
- var $privateKey;
235
-
236
- /**
237
- * Object identifiers for X.509 certificates
238
- *
239
- * @var array
240
- * @access private
241
- * @link http://en.wikipedia.org/wiki/Object_identifier
242
- */
243
- var $oids;
244
-
245
- /**
246
- * The certificate authorities
247
- *
248
- * @var array
249
- * @access private
250
- */
251
- var $CAs;
252
-
253
- /**
254
- * The currently loaded certificate
255
- *
256
- * @var array
257
- * @access private
258
- */
259
- var $currentCert;
260
-
261
- /**
262
- * The signature subject
263
- *
264
- * There's no guarantee File_X509 is going to re-encode an X.509 cert in the same way it was originally
265
- * encoded so we take save the portion of the original cert that the signature would have made for.
266
- *
267
- * @var string
268
- * @access private
269
- */
270
- var $signatureSubject;
271
-
272
- /**
273
- * Certificate Start Date
274
- *
275
- * @var string
276
- * @access private
277
- */
278
- var $startDate;
279
-
280
- /**
281
- * Certificate End Date
282
- *
283
- * @var string
284
- * @access private
285
- */
286
- var $endDate;
287
-
288
- /**
289
- * Serial Number
290
- *
291
- * @var string
292
- * @access private
293
- */
294
- var $serialNumber;
295
-
296
- /**
297
- * Key Identifier
298
- *
299
- * See {@link http://tools.ietf.org/html/rfc5280#section-4.2.1.1 RFC5280#section-4.2.1.1} and
300
- * {@link http://tools.ietf.org/html/rfc5280#section-4.2.1.2 RFC5280#section-4.2.1.2}.
301
- *
302
- * @var string
303
- * @access private
304
- */
305
- var $currentKeyIdentifier;
306
-
307
- /**
308
- * CA Flag
309
- *
310
- * @var bool
311
- * @access private
312
- */
313
- var $caFlag = false;
314
-
315
- /**
316
- * SPKAC Challenge
317
- *
318
- * @var string
319
- * @access private
320
- */
321
- var $challenge;
322
-
323
- /**
324
- * Default Constructor.
325
- *
326
- * @return File_X509
327
- * @access public
328
- */
329
- function __construct()
330
- {
331
- if (!class_exists('Math_BigInteger')) {
332
- include_once 'Math/BigInteger.php';
333
- }
334
-
335
- // Explicitly Tagged Module, 1988 Syntax
336
- // http://tools.ietf.org/html/rfc5280#appendix-A.1
337
-
338
- $this->DirectoryString = array(
339
- 'type' => FILE_ASN1_TYPE_CHOICE,
340
- 'children' => array(
341
- 'teletexString' => array('type' => FILE_ASN1_TYPE_TELETEX_STRING),
342
- 'printableString' => array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING),
343
- 'universalString' => array('type' => FILE_ASN1_TYPE_UNIVERSAL_STRING),
344
- 'utf8String' => array('type' => FILE_ASN1_TYPE_UTF8_STRING),
345
- 'bmpString' => array('type' => FILE_ASN1_TYPE_BMP_STRING)
346
- )
347
- );
348
-
349
- $this->PKCS9String = array(
350
- 'type' => FILE_ASN1_TYPE_CHOICE,
351
- 'children' => array(
352
- 'ia5String' => array('type' => FILE_ASN1_TYPE_IA5_STRING),
353
- 'directoryString' => $this->DirectoryString
354
- )
355
- );
356
-
357
- $this->AttributeValue = array('type' => FILE_ASN1_TYPE_ANY);
358
-
359
- $AttributeType = array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER);
360
-
361
- $AttributeTypeAndValue = array(
362
- 'type' => FILE_ASN1_TYPE_SEQUENCE,
363
- 'children' => array(
364
- 'type' => $AttributeType,
365
- 'value'=> $this->AttributeValue
366
- )
367
- );
368
-
369
- /*
370
- In practice, RDNs containing multiple name-value pairs (called "multivalued RDNs") are rare,
371
- but they can be useful at times when either there is no unique attribute in the entry or you
372
- want to ensure that the entry's DN contains some useful identifying information.
373
-
374
- - https://www.opends.org/wiki/page/DefinitionRelativeDistinguishedName
375
- */
376
- $this->RelativeDistinguishedName = array(
377
- 'type' => FILE_ASN1_TYPE_SET,
378
- 'min' => 1,
379
- 'max' => -1,
380
- 'children' => $AttributeTypeAndValue
381
- );
382
-
383
- // http://tools.ietf.org/html/rfc5280#section-4.1.2.4
384
- $RDNSequence = array(
385
- 'type' => FILE_ASN1_TYPE_SEQUENCE,
386
- // RDNSequence does not define a min or a max, which means it doesn't have one
387
- 'min' => 0,
388
- 'max' => -1,
389
- 'children' => $this->RelativeDistinguishedName
390
- );
391
-
392
- $this->Name = array(
393
- 'type' => FILE_ASN1_TYPE_CHOICE,
394
- 'children' => array(
395
- 'rdnSequence' => $RDNSequence
396
- )
397
- );
398
-
399
- // http://tools.ietf.org/html/rfc5280#section-4.1.1.2
400
- $AlgorithmIdentifier = array(
401
- 'type' => FILE_ASN1_TYPE_SEQUENCE,
402
- 'children' => array(
403
- 'algorithm' => array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER),
404
- 'parameters' => array(
405
- 'type' => FILE_ASN1_TYPE_ANY,
406
- 'optional' => true
407
- )
408
- )
409
- );
410
-
411
- /*
412
- A certificate using system MUST reject the certificate if it encounters
413
- a critical extension it does not recognize; however, a non-critical
414
- extension may be ignored if it is not recognized.
415
-
416
- http://tools.ietf.org/html/rfc5280#section-4.2
417
- */
418
- $Extension = array(
419
- 'type' => FILE_ASN1_TYPE_SEQUENCE,
420
- 'children' => array(
421
- 'extnId' => array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER),
422
- 'critical' => array(
423
- 'type' => FILE_ASN1_TYPE_BOOLEAN,
424
- 'optional' => true,
425
- 'default' => false
426
- ),
427
- 'extnValue' => array('type' => FILE_ASN1_TYPE_OCTET_STRING)
428
- )
429
- );
430
-
431
- $this->Extensions = array(
432
- 'type' => FILE_ASN1_TYPE_SEQUENCE,
433
- 'min' => 1,
434
- // technically, it's MAX, but we'll assume anything < 0 is MAX
435
- 'max' => -1,
436
- // if 'children' isn't an array then 'min' and 'max' must be defined
437
- 'children' => $Extension
438
- );
439
-
440
- $SubjectPublicKeyInfo = array(
441
- 'type' => FILE_ASN1_TYPE_SEQUENCE,
442
- 'children' => array(
443
- 'algorithm' => $AlgorithmIdentifier,
444
- 'subjectPublicKey' => array('type' => FILE_ASN1_TYPE_BIT_STRING)
445
- )
446
- );
447
-
448
- $UniqueIdentifier = array('type' => FILE_ASN1_TYPE_BIT_STRING);
449
-
450
- $Time = array(
451
- 'type' => FILE_ASN1_TYPE_CHOICE,
452
- 'children' => array(
453
- 'utcTime' => array('type' => FILE_ASN1_TYPE_UTC_TIME),
454
- 'generalTime' => array('type' => FILE_ASN1_TYPE_GENERALIZED_TIME)
455
- )
456
- );
457
-
458
- // http://tools.ietf.org/html/rfc5280#section-4.1.2.5
459
- $Validity = array(
460
- 'type' => FILE_ASN1_TYPE_SEQUENCE,
461
- 'children' => array(
462
- 'notBefore' => $Time,
463
- 'notAfter' => $Time
464
- )
465
- );
466
-
467
- $CertificateSerialNumber = array('type' => FILE_ASN1_TYPE_INTEGER);
468
-
469
- $Version = array(
470
- 'type' => FILE_ASN1_TYPE_INTEGER,
471
- 'mapping' => array('v1', 'v2', 'v3')
472
- );
473
-
474
- // assert($TBSCertificate['children']['signature'] == $Certificate['children']['signatureAlgorithm'])
475
- $TBSCertificate = array(
476
- 'type' => FILE_ASN1_TYPE_SEQUENCE,
477
- 'children' => array(
478
- // technically, default implies optional, but we'll define it as being optional, none-the-less, just to
479
- // reenforce that fact
480
- 'version' => array(
481
- 'constant' => 0,
482
- 'optional' => true,
483
- 'explicit' => true,
484
- 'default' => 'v1'
485
- ) + $Version,
486
- 'serialNumber' => $CertificateSerialNumber,
487
- 'signature' => $AlgorithmIdentifier,
488
- 'issuer' => $this->Name,
489
- 'validity' => $Validity,
490
- 'subject' => $this->Name,
491
- 'subjectPublicKeyInfo' => $SubjectPublicKeyInfo,
492
- // implicit means that the T in the TLV structure is to be rewritten, regardless of the type
493
- 'issuerUniqueID' => array(
494
- 'constant' => 1,
495
- 'optional' => true,
496
- 'implicit' => true
497
- ) + $UniqueIdentifier,
498
- 'subjectUniqueID' => array(
499
- 'constant' => 2,
500
- 'optional' => true,
501
- 'implicit' => true
502
- ) + $UniqueIdentifier,
503
- // <http://tools.ietf.org/html/rfc2459#page-74> doesn't use the EXPLICIT keyword but if
504
- // it's not IMPLICIT, it's EXPLICIT
505
- 'extensions' => array(
506
- 'constant' => 3,
507
- 'optional' => true,
508
- 'explicit' => true
509
- ) + $this->Extensions
510
- )
511
- );
512
-
513
- $this->Certificate = array(
514
- 'type' => FILE_ASN1_TYPE_SEQUENCE,
515
- 'children' => array(
516
- 'tbsCertificate' => $TBSCertificate,
517
- 'signatureAlgorithm' => $AlgorithmIdentifier,
518
- 'signature' => array('type' => FILE_ASN1_TYPE_BIT_STRING)
519
- )
520
- );
521
-
522
- $this->KeyUsage = array(
523
- 'type' => FILE_ASN1_TYPE_BIT_STRING,
524
- 'mapping' => array(
525
- 'digitalSignature',
526
- 'nonRepudiation',
527
- 'keyEncipherment',
528
- 'dataEncipherment',
529
- 'keyAgreement',
530
- 'keyCertSign',
531
- 'cRLSign',
532
- 'encipherOnly',
533
- 'decipherOnly'
534
- )
535
- );
536
-
537
- $this->BasicConstraints = array(
538
- 'type' => FILE_ASN1_TYPE_SEQUENCE,
539
- 'children' => array(
540
- 'cA' => array(
541
- 'type' => FILE_ASN1_TYPE_BOOLEAN,
542
- 'optional' => true,
543
- 'default' => false
544
- ),
545
- 'pathLenConstraint' => array(
546
- 'type' => FILE_ASN1_TYPE_INTEGER,
547
- 'optional' => true
548
- )
549
- )
550
- );
551
-
552
- $this->KeyIdentifier = array('type' => FILE_ASN1_TYPE_OCTET_STRING);
553
-
554
- $OrganizationalUnitNames = array(
555
- 'type' => FILE_ASN1_TYPE_SEQUENCE,
556
- 'min' => 1,
557
- 'max' => 4, // ub-organizational-units
558
- 'children' => array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING)
559
- );
560
-
561
- $PersonalName = array(
562
- 'type' => FILE_ASN1_TYPE_SET,
563
- 'children' => array(
564
- 'surname' => array(
565
- 'type' => FILE_ASN1_TYPE_PRINTABLE_STRING,
566
- 'constant' => 0,
567
- 'optional' => true,
568
- 'implicit' => true
569
- ),
570
- 'given-name' => array(
571
- 'type' => FILE_ASN1_TYPE_PRINTABLE_STRING,
572
- 'constant' => 1,
573
- 'optional' => true,
574
- 'implicit' => true
575
- ),
576
- 'initials' => array(
577
- 'type' => FILE_ASN1_TYPE_PRINTABLE_STRING,
578
- 'constant' => 2,
579
- 'optional' => true,
580
- 'implicit' => true
581
- ),
582
- 'generation-qualifier' => array(
583
- 'type' => FILE_ASN1_TYPE_PRINTABLE_STRING,
584
- 'constant' => 3,
585
- 'optional' => true,
586
- 'implicit' => true
587
- )
588
- )
589
- );
590
-
591
- $NumericUserIdentifier = array('type' => FILE_ASN1_TYPE_NUMERIC_STRING);
592
-
593
- $OrganizationName = array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING);
594
-
595
- $PrivateDomainName = array(
596
- 'type' => FILE_ASN1_TYPE_CHOICE,
597
- 'children' => array(
598
- 'numeric' => array('type' => FILE_ASN1_TYPE_NUMERIC_STRING),
599
- 'printable' => array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING)
600
- )
601
- );
602
-
603
- $TerminalIdentifier = array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING);
604
-
605
- $NetworkAddress = array('type' => FILE_ASN1_TYPE_NUMERIC_STRING);
606
-
607
- $AdministrationDomainName = array(
608
- 'type' => FILE_ASN1_TYPE_CHOICE,
609
- // if class isn't present it's assumed to be FILE_ASN1_CLASS_UNIVERSAL or
610
- // (if constant is present) FILE_ASN1_CLASS_CONTEXT_SPECIFIC
611
- 'class' => FILE_ASN1_CLASS_APPLICATION,
612
- 'cast' => 2,
613
- 'children' => array(
614
- 'numeric' => array('type' => FILE_ASN1_TYPE_NUMERIC_STRING),
615
- 'printable' => array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING)
616
- )
617
- );
618
-
619
- $CountryName = array(
620
- 'type' => FILE_ASN1_TYPE_CHOICE,
621
- // if class isn't present it's assumed to be FILE_ASN1_CLASS_UNIVERSAL or
622
- // (if constant is present) FILE_ASN1_CLASS_CONTEXT_SPECIFIC
623
- 'class' => FILE_ASN1_CLASS_APPLICATION,
624
- 'cast' => 1,
625
- 'children' => array(
626
- 'x121-dcc-code' => array('type' => FILE_ASN1_TYPE_NUMERIC_STRING),
627
- 'iso-3166-alpha2-code' => array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING)
628
- )
629
- );
630
-
631
- $AnotherName = array(
632
- 'type' => FILE_ASN1_TYPE_SEQUENCE,
633
- 'children' => array(
634
- 'type-id' => array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER),
635
- 'value' => array(
636
- 'type' => FILE_ASN1_TYPE_ANY,
637
- 'constant' => 0,
638
- 'optional' => true,
639
- 'explicit' => true
640
- )
641
- )
642
- );
643
-
644
- $ExtensionAttribute = array(
645
- 'type' => FILE_ASN1_TYPE_SEQUENCE,
646
- 'children' => array(
647
- 'extension-attribute-type' => array(
648
- 'type' => FILE_ASN1_TYPE_PRINTABLE_STRING,
649
- 'constant' => 0,
650
- 'optional' => true,
651
- 'implicit' => true
652
- ),
653
- 'extension-attribute-value' => array(
654
- 'type' => FILE_ASN1_TYPE_ANY,
655
- 'constant' => 1,
656
- 'optional' => true,
657
- 'explicit' => true
658
- )
659
- )
660
- );
661
-
662
- $ExtensionAttributes = array(
663
- 'type' => FILE_ASN1_TYPE_SET,
664
- 'min' => 1,
665
- 'max' => 256, // ub-extension-attributes
666
- 'children' => $ExtensionAttribute
667
- );
668
-
669
- $BuiltInDomainDefinedAttribute = array(
670
- 'type' => FILE_ASN1_TYPE_SEQUENCE,
671
- 'children' => array(
672
- 'type' => array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING),
673
- 'value' => array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING)
674
- )
675
- );
676
-
677
- $BuiltInDomainDefinedAttributes = array(
678
- 'type' => FILE_ASN1_TYPE_SEQUENCE,
679
- 'min' => 1,
680
- 'max' => 4, // ub-domain-defined-attributes
681
- 'children' => $BuiltInDomainDefinedAttribute
682
- );
683
-
684
- $BuiltInStandardAttributes = array(
685
- 'type' => FILE_ASN1_TYPE_SEQUENCE,
686
- 'children' => array(
687
- 'country-name' => array('optional' => true) + $CountryName,
688
- 'administration-domain-name' => array('optional' => true) + $AdministrationDomainName,
689
- 'network-address' => array(
690
- 'constant' => 0,
691
- 'optional' => true,
692
- 'implicit' => true
693
- ) + $NetworkAddress,
694
- 'terminal-identifier' => array(
695
- 'constant' => 1,
696
- 'optional' => true,
697
- 'implicit' => true
698
- ) + $TerminalIdentifier,
699
- 'private-domain-name' => array(
700
- 'constant' => 2,
701
- 'optional' => true,
702
- 'explicit' => true
703
- ) + $PrivateDomainName,
704
- 'organization-name' => array(
705
- 'constant' => 3,
706
- 'optional' => true,
707
- 'implicit' => true
708
- ) + $OrganizationName,
709
- 'numeric-user-identifier' => array(
710
- 'constant' => 4,
711
- 'optional' => true,
712
- 'implicit' => true
713
- ) + $NumericUserIdentifier,
714
- 'personal-name' => array(
715
- 'constant' => 5,
716
- 'optional' => true,
717
- 'implicit' => true
718
- ) + $PersonalName,
719
- 'organizational-unit-names' => array(
720
- 'constant' => 6,
721
- 'optional' => true,
722
- 'implicit' => true
723
- ) + $OrganizationalUnitNames
724
- )
725
- );
726
-
727
- $ORAddress = array(
728
- 'type' => FILE_ASN1_TYPE_SEQUENCE,
729
- 'children' => array(
730
- 'built-in-standard-attributes' => $BuiltInStandardAttributes,
731
- 'built-in-domain-defined-attributes' => array('optional' => true) + $BuiltInDomainDefinedAttributes,
732
- 'extension-attributes' => array('optional' => true) + $ExtensionAttributes
733
- )
734
- );
735
-
736
- $EDIPartyName = array(
737
- 'type' => FILE_ASN1_TYPE_SEQUENCE,
738
- 'children' => array(
739
- 'nameAssigner' => array(
740
- 'constant' => 0,
741
- 'optional' => true,
742
- 'implicit' => true
743
- ) + $this->DirectoryString,
744
- // partyName is technically required but File_ASN1 doesn't currently support non-optional constants and
745
- // setting it to optional gets the job done in any event.
746
- 'partyName' => array(
747
- 'constant' => 1,
748
- 'optional' => true,
749
- 'implicit' => true
750
- ) + $this->DirectoryString
751
- )
752
- );
753
-
754
- $GeneralName = array(
755
- 'type' => FILE_ASN1_TYPE_CHOICE,
756
- 'children' => array(
757
- 'otherName' => array(
758
- 'constant' => 0,
759
- 'optional' => true,
760
- 'implicit' => true
761
- ) + $AnotherName,
762
- 'rfc822Name' => array(
763
- 'type' => FILE_ASN1_TYPE_IA5_STRING,
764
- 'constant' => 1,
765
- 'optional' => true,
766
- 'implicit' => true
767
- ),
768
- 'dNSName' => array(
769
- 'type' => FILE_ASN1_TYPE_IA5_STRING,
770
- 'constant' => 2,
771
- 'optional' => true,
772
- 'implicit' => true
773
- ),
774
- 'x400Address' => array(
775
- 'constant' => 3,
776
- 'optional' => true,
777
- 'implicit' => true
778
- ) + $ORAddress,
779
- 'directoryName' => array(
780
- 'constant' => 4,
781
- 'optional' => true,
782
- 'explicit' => true
783
- ) + $this->Name,
784
- 'ediPartyName' => array(
785
- 'constant' => 5,
786
- 'optional' => true,
787
- 'implicit' => true
788
- ) + $EDIPartyName,
789
- 'uniformResourceIdentifier' => array(
790
- 'type' => FILE_ASN1_TYPE_IA5_STRING,
791
- 'constant' => 6,
792
- 'optional' => true,
793
- 'implicit' => true
794
- ),
795
- 'iPAddress' => array(
796
- 'type' => FILE_ASN1_TYPE_OCTET_STRING,
797
- 'constant' => 7,
798
- 'optional' => true,
799
- 'implicit' => true
800
- ),
801
- 'registeredID' => array(
802
- 'type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER,
803
- 'constant' => 8,
804
- 'optional' => true,
805
- 'implicit' => true
806
- )
807
- )
808
- );
809
-
810
- $GeneralNames = array(
811
- 'type' => FILE_ASN1_TYPE_SEQUENCE,
812
- 'min' => 1,
813
- 'max' => -1,
814
- 'children' => $GeneralName
815
- );
816
-
817
- $this->IssuerAltName = $GeneralNames;
818
-
819
- $ReasonFlags = array(
820
- 'type' => FILE_ASN1_TYPE_BIT_STRING,
821
- 'mapping' => array(
822
- 'unused',
823
- 'keyCompromise',
824
- 'cACompromise',
825
- 'affiliationChanged',
826
- 'superseded',
827
- 'cessationOfOperation',
828
- 'certificateHold',
829
- 'privilegeWithdrawn',
830
- 'aACompromise'
831
- )
832
- );
833
-
834
- $DistributionPointName = array(
835
- 'type' => FILE_ASN1_TYPE_CHOICE,
836
- 'children' => array(
837
- 'fullName' => array(
838
- 'constant' => 0,
839
- 'optional' => true,
840
- 'implicit' => true
841
- ) + $GeneralNames,
842
- 'nameRelativeToCRLIssuer' => array(
843
- 'constant' => 1,
844
- 'optional' => true,
845
- 'implicit' => true
846
- ) + $this->RelativeDistinguishedName
847
- )
848
- );
849
-
850
- $DistributionPoint = array(
851
- 'type' => FILE_ASN1_TYPE_SEQUENCE,
852
- 'children' => array(
853
- 'distributionPoint' => array(
854
- 'constant' => 0,
855
- 'optional' => true,
856
- 'explicit' => true
857
- ) + $DistributionPointName,
858
- 'reasons' => array(
859
- 'constant' => 1,
860
- 'optional' => true,
861
- 'implicit' => true
862
- ) + $ReasonFlags,
863
- 'cRLIssuer' => array(
864
- 'constant' => 2,
865
- 'optional' => true,
866
- 'implicit' => true
867
- ) + $GeneralNames
868
- )
869
- );
870
-
871
- $this->CRLDistributionPoints = array(
872
- 'type' => FILE_ASN1_TYPE_SEQUENCE,
873
- 'min' => 1,
874
- 'max' => -1,
875
- 'children' => $DistributionPoint
876
- );
877
-
878
- $this->AuthorityKeyIdentifier = array(
879
- 'type' => FILE_ASN1_TYPE_SEQUENCE,
880
- 'children' => array(
881
- 'keyIdentifier' => array(
882
- 'constant' => 0,
883
- 'optional' => true,
884
- 'implicit' => true
885
- ) + $this->KeyIdentifier,
886
- 'authorityCertIssuer' => array(
887
- 'constant' => 1,
888
- 'optional' => true,
889
- 'implicit' => true
890
- ) + $GeneralNames,
891
- 'authorityCertSerialNumber' => array(
892
- 'constant' => 2,
893
- 'optional' => true,
894
- 'implicit' => true
895
- ) + $CertificateSerialNumber
896
- )
897
- );
898
-
899
- $PolicyQualifierId = array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER);
900
-
901
- $PolicyQualifierInfo = array(
902
- 'type' => FILE_ASN1_TYPE_SEQUENCE,
903
- 'children' => array(
904
- 'policyQualifierId' => $PolicyQualifierId,
905
- 'qualifier' => array('type' => FILE_ASN1_TYPE_ANY)
906
- )
907
- );
908
-
909
- $CertPolicyId = array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER);
910
-
911
- $PolicyInformation = array(
912
- 'type' => FILE_ASN1_TYPE_SEQUENCE,
913
- 'children' => array(
914
- 'policyIdentifier' => $CertPolicyId,
915
- 'policyQualifiers' => array(
916
- 'type' => FILE_ASN1_TYPE_SEQUENCE,
917
- 'min' => 0,
918
- 'max' => -1,
919
- 'optional' => true,
920
- 'children' => $PolicyQualifierInfo
921
- )
922
- )
923
- );
924
-
925
- $this->CertificatePolicies = array(
926
- 'type' => FILE_ASN1_TYPE_SEQUENCE,
927
- 'min' => 1,
928
- 'max' => -1,
929
- 'children' => $PolicyInformation
930
- );
931
-
932
- $this->PolicyMappings = array(
933
- 'type' => FILE_ASN1_TYPE_SEQUENCE,
934
- 'min' => 1,
935
- 'max' => -1,
936
- 'children' => array(
937
- 'type' => FILE_ASN1_TYPE_SEQUENCE,
938
- 'children' => array(
939
- 'issuerDomainPolicy' => $CertPolicyId,
940
- 'subjectDomainPolicy' => $CertPolicyId
941
- )
942
- )
943
- );
944
-
945
- $KeyPurposeId = array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER);
946
-
947
- $this->ExtKeyUsageSyntax = array(
948
- 'type' => FILE_ASN1_TYPE_SEQUENCE,
949
- 'min' => 1,
950
- 'max' => -1,
951
- 'children' => $KeyPurposeId
952
- );
953
-
954
- $AccessDescription = array(
955
- 'type' => FILE_ASN1_TYPE_SEQUENCE,
956
- 'children' => array(
957
- 'accessMethod' => array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER),
958
- 'accessLocation' => $GeneralName
959
- )
960
- );
961
-
962
- $this->AuthorityInfoAccessSyntax = array(
963
- 'type' => FILE_ASN1_TYPE_SEQUENCE,
964
- 'min' => 1,
965
- 'max' => -1,
966
- 'children' => $AccessDescription
967
- );
968
-
969
- $this->SubjectAltName = $GeneralNames;
970
-
971
- $this->PrivateKeyUsagePeriod = array(
972
- 'type' => FILE_ASN1_TYPE_SEQUENCE,
973
- 'children' => array(
974
- 'notBefore' => array(
975
- 'constant' => 0,
976
- 'optional' => true,
977
- 'implicit' => true,
978
- 'type' => FILE_ASN1_TYPE_GENERALIZED_TIME),
979
- 'notAfter' => array(
980
- 'constant' => 1,
981
- 'optional' => true,
982
- 'implicit' => true,
983
- 'type' => FILE_ASN1_TYPE_GENERALIZED_TIME)
984
- )
985
- );
986
-
987
- $BaseDistance = array('type' => FILE_ASN1_TYPE_INTEGER);
988
-
989
- $GeneralSubtree = array(
990
- 'type' => FILE_ASN1_TYPE_SEQUENCE,
991
- 'children' => array(
992
- 'base' => $GeneralName,
993
- 'minimum' => array(
994
- 'constant' => 0,
995
- 'optional' => true,
996
- 'implicit' => true,
997
- 'default' => new Math_BigInteger(0)
998
- ) + $BaseDistance,
999
- 'maximum' => array(
1000
- 'constant' => 1,
1001
- 'optional' => true,
1002
- 'implicit' => true,
1003
- ) + $BaseDistance
1004
- )
1005
- );
1006
-
1007
- $GeneralSubtrees = array(
1008
- 'type' => FILE_ASN1_TYPE_SEQUENCE,
1009
- 'min' => 1,
1010
- 'max' => -1,
1011
- 'children' => $GeneralSubtree
1012
- );
1013
-
1014
- $this->NameConstraints = array(
1015
- 'type' => FILE_ASN1_TYPE_SEQUENCE,
1016
- 'children' => array(
1017
- 'permittedSubtrees' => array(
1018
- 'constant' => 0,
1019
- 'optional' => true,
1020
- 'implicit' => true
1021
- ) + $GeneralSubtrees,
1022
- 'excludedSubtrees' => array(
1023
- 'constant' => 1,
1024
- 'optional' => true,
1025
- 'implicit' => true
1026
- ) + $GeneralSubtrees
1027
- )
1028
- );
1029
-
1030
- $this->CPSuri = array('type' => FILE_ASN1_TYPE_IA5_STRING);
1031
-
1032
- $DisplayText = array(
1033
- 'type' => FILE_ASN1_TYPE_CHOICE,
1034
- 'children' => array(
1035
- 'ia5String' => array('type' => FILE_ASN1_TYPE_IA5_STRING),
1036
- 'visibleString' => array('type' => FILE_ASN1_TYPE_VISIBLE_STRING),
1037
- 'bmpString' => array('type' => FILE_ASN1_TYPE_BMP_STRING),
1038
- 'utf8String' => array('type' => FILE_ASN1_TYPE_UTF8_STRING)
1039
- )
1040
- );
1041
-
1042
- $NoticeReference = array(
1043
- 'type' => FILE_ASN1_TYPE_SEQUENCE,
1044
- 'children' => array(
1045
- 'organization' => $DisplayText,
1046
- 'noticeNumbers' => array(
1047
- 'type' => FILE_ASN1_TYPE_SEQUENCE,
1048
- 'min' => 1,
1049
- 'max' => 200,
1050
- 'children' => array('type' => FILE_ASN1_TYPE_INTEGER)
1051
- )
1052
- )
1053
- );
1054
-
1055
- $this->UserNotice = array(
1056
- 'type' => FILE_ASN1_TYPE_SEQUENCE,
1057
- 'children' => array(
1058
- 'noticeRef' => array(
1059
- 'optional' => true,
1060
- 'implicit' => true
1061
- ) + $NoticeReference,
1062
- 'explicitText' => array(
1063
- 'optional' => true,
1064
- 'implicit' => true
1065
- ) + $DisplayText
1066
- )
1067
- );
1068
-
1069
- // mapping is from <http://www.mozilla.org/projects/security/pki/nss/tech-notes/tn3.html>
1070
- $this->netscape_cert_type = array(
1071
- 'type' => FILE_ASN1_TYPE_BIT_STRING,
1072
- 'mapping' => array(
1073
- 'SSLClient',
1074
- 'SSLServer',
1075
- 'Email',
1076
- 'ObjectSigning',
1077
- 'Reserved',
1078
- 'SSLCA',
1079
- 'EmailCA',
1080
- 'ObjectSigningCA'
1081
- )
1082
- );
1083
-
1084
- $this->netscape_comment = array('type' => FILE_ASN1_TYPE_IA5_STRING);
1085
- $this->netscape_ca_policy_url = array('type' => FILE_ASN1_TYPE_IA5_STRING);
1086
-
1087
- // attribute is used in RFC2986 but we're using the RFC5280 definition
1088
-
1089
- $Attribute = array(
1090
- 'type' => FILE_ASN1_TYPE_SEQUENCE,
1091
- 'children' => array(
1092
- 'type' => $AttributeType,
1093
- 'value'=> array(
1094
- 'type' => FILE_ASN1_TYPE_SET,
1095
- 'min' => 1,
1096
- 'max' => -1,
1097
- 'children' => $this->AttributeValue
1098
- )
1099
- )
1100
- );
1101
-
1102
- $this->SubjectDirectoryAttributes = array(
1103
- 'type' => FILE_ASN1_TYPE_SEQUENCE,
1104
- 'min' => 1,
1105
- 'max' => -1,
1106
- 'children' => $Attribute
1107
- );
1108
-
1109
- // adapted from <http://tools.ietf.org/html/rfc2986>
1110
-
1111
- $Attributes = array(
1112
- 'type' => FILE_ASN1_TYPE_SET,
1113
- 'min' => 1,
1114
- 'max' => -1,
1115
- 'children' => $Attribute
1116
- );
1117
-
1118
- $CertificationRequestInfo = array(
1119
- 'type' => FILE_ASN1_TYPE_SEQUENCE,
1120
- 'children' => array(
1121
- 'version' => array(
1122
- 'type' => FILE_ASN1_TYPE_INTEGER,
1123
- 'mapping' => array('v1')
1124
- ),
1125
- 'subject' => $this->Name,
1126
- 'subjectPKInfo' => $SubjectPublicKeyInfo,
1127
- 'attributes' => array(
1128
- 'constant' => 0,
1129
- 'optional' => true,
1130
- 'implicit' => true
1131
- ) + $Attributes,
1132
- )
1133
- );
1134
-
1135
- $this->CertificationRequest = array(
1136
- 'type' => FILE_ASN1_TYPE_SEQUENCE,
1137
- 'children' => array(
1138
- 'certificationRequestInfo' => $CertificationRequestInfo,
1139
- 'signatureAlgorithm' => $AlgorithmIdentifier,
1140
- 'signature' => array('type' => FILE_ASN1_TYPE_BIT_STRING)
1141
- )
1142
- );
1143
-
1144
- $RevokedCertificate = array(
1145
- 'type' => FILE_ASN1_TYPE_SEQUENCE,
1146
- 'children' => array(
1147
- 'userCertificate' => $CertificateSerialNumber,
1148
- 'revocationDate' => $Time,
1149
- 'crlEntryExtensions' => array(
1150
- 'optional' => true
1151
- ) + $this->Extensions
1152
- )
1153
- );
1154
-
1155
- $TBSCertList = array(
1156
- 'type' => FILE_ASN1_TYPE_SEQUENCE,
1157
- 'children' => array(
1158
- 'version' => array(
1159
- 'optional' => true,
1160
- 'default' => 'v1'
1161
- ) + $Version,
1162
- 'signature' => $AlgorithmIdentifier,
1163
- 'issuer' => $this->Name,
1164
- 'thisUpdate' => $Time,
1165
- 'nextUpdate' => array(
1166
- 'optional' => true
1167
- ) + $Time,
1168
- 'revokedCertificates' => array(
1169
- 'type' => FILE_ASN1_TYPE_SEQUENCE,
1170
- 'optional' => true,
1171
- 'min' => 0,
1172
- 'max' => -1,
1173
- 'children' => $RevokedCertificate
1174
- ),
1175
- 'crlExtensions' => array(
1176
- 'constant' => 0,
1177
- 'optional' => true,
1178
- 'explicit' => true
1179
- ) + $this->Extensions
1180
- )
1181
- );
1182
-
1183
- $this->CertificateList = array(
1184
- 'type' => FILE_ASN1_TYPE_SEQUENCE,
1185
- 'children' => array(
1186
- 'tbsCertList' => $TBSCertList,
1187
- 'signatureAlgorithm' => $AlgorithmIdentifier,
1188
- 'signature' => array('type' => FILE_ASN1_TYPE_BIT_STRING)
1189
- )
1190
- );
1191
-
1192
- $this->CRLNumber = array('type' => FILE_ASN1_TYPE_INTEGER);
1193
-
1194
- $this->CRLReason = array('type' => FILE_ASN1_TYPE_ENUMERATED,
1195
- 'mapping' => array(
1196
- 'unspecified',
1197
- 'keyCompromise',
1198
- 'cACompromise',
1199
- 'affiliationChanged',
1200
- 'superseded',
1201
- 'cessationOfOperation',
1202
- 'certificateHold',
1203
- // Value 7 is not used.
1204
- 8 => 'removeFromCRL',
1205
- 'privilegeWithdrawn',
1206
- 'aACompromise'
1207
- )
1208
- );
1209
-
1210
- $this->IssuingDistributionPoint = array('type' => FILE_ASN1_TYPE_SEQUENCE,
1211
- 'children' => array(
1212
- 'distributionPoint' => array(
1213
- 'constant' => 0,
1214
- 'optional' => true,
1215
- 'explicit' => true
1216
- ) + $DistributionPointName,
1217
- 'onlyContainsUserCerts' => array(
1218
- 'type' => FILE_ASN1_TYPE_BOOLEAN,
1219
- 'constant' => 1,
1220
- 'optional' => true,
1221
- 'default' => false,
1222
- 'implicit' => true
1223
- ),
1224
- 'onlyContainsCACerts' => array(
1225
- 'type' => FILE_ASN1_TYPE_BOOLEAN,
1226
- 'constant' => 2,
1227
- 'optional' => true,
1228
- 'default' => false,
1229
- 'implicit' => true
1230
- ),
1231
- 'onlySomeReasons' => array(
1232
- 'constant' => 3,
1233
- 'optional' => true,
1234
- 'implicit' => true
1235
- ) + $ReasonFlags,
1236
- 'indirectCRL' => array(
1237
- 'type' => FILE_ASN1_TYPE_BOOLEAN,
1238
- 'constant' => 4,
1239
- 'optional' => true,
1240
- 'default' => false,
1241
- 'implicit' => true
1242
- ),
1243
- 'onlyContainsAttributeCerts' => array(
1244
- 'type' => FILE_ASN1_TYPE_BOOLEAN,
1245
- 'constant' => 5,
1246
- 'optional' => true,
1247
- 'default' => false,
1248
- 'implicit' => true
1249
- )
1250
- )
1251
- );
1252
-
1253
- $this->InvalidityDate = array('type' => FILE_ASN1_TYPE_GENERALIZED_TIME);
1254
-
1255
- $this->CertificateIssuer = $GeneralNames;
1256
-
1257
- $this->HoldInstructionCode = array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER);
1258
-
1259
- $PublicKeyAndChallenge = array(
1260
- 'type' => FILE_ASN1_TYPE_SEQUENCE,
1261
- 'children' => array(
1262
- 'spki' => $SubjectPublicKeyInfo,
1263
- 'challenge' => array('type' => FILE_ASN1_TYPE_IA5_STRING)
1264
- )
1265
- );
1266
-
1267
- $this->SignedPublicKeyAndChallenge = array(
1268
- 'type' => FILE_ASN1_TYPE_SEQUENCE,
1269
- 'children' => array(
1270
- 'publicKeyAndChallenge' => $PublicKeyAndChallenge,
1271
- 'signatureAlgorithm' => $AlgorithmIdentifier,
1272
- 'signature' => array('type' => FILE_ASN1_TYPE_BIT_STRING)
1273
- )
1274
- );
1275
-
1276
- $this->PostalAddress = array(
1277
- 'type' => FILE_ASN1_TYPE_SEQUENCE,
1278
- 'optional' => true,
1279
- 'min' => 1,
1280
- 'max' => -1,
1281
- 'children' => $this->DirectoryString
1282
- );
1283
-
1284
- // OIDs from RFC5280 and those RFCs mentioned in RFC5280#section-4.1.1.2
1285
- $this->oids = array(
1286
- '1.3.6.1.5.5.7' => 'id-pkix',
1287
- '1.3.6.1.5.5.7.1' => 'id-pe',
1288
- '1.3.6.1.5.5.7.2' => 'id-qt',
1289
- '1.3.6.1.5.5.7.3' => 'id-kp',
1290
- '1.3.6.1.5.5.7.48' => 'id-ad',
1291
- '1.3.6.1.5.5.7.2.1' => 'id-qt-cps',
1292
- '1.3.6.1.5.5.7.2.2' => 'id-qt-unotice',
1293
- '1.3.6.1.5.5.7.48.1' =>'id-ad-ocsp',
1294
- '1.3.6.1.5.5.7.48.2' => 'id-ad-caIssuers',
1295
- '1.3.6.1.5.5.7.48.3' => 'id-ad-timeStamping',
1296
- '1.3.6.1.5.5.7.48.5' => 'id-ad-caRepository',
1297
- '2.5.4' => 'id-at',
1298
- '2.5.4.41' => 'id-at-name',
1299
- '2.5.4.4' => 'id-at-surname',
1300
- '2.5.4.42' => 'id-at-givenName',
1301
- '2.5.4.43' => 'id-at-initials',
1302
- '2.5.4.44' => 'id-at-generationQualifier',
1303
- '2.5.4.3' => 'id-at-commonName',
1304
- '2.5.4.7' => 'id-at-localityName',
1305
- '2.5.4.8' => 'id-at-stateOrProvinceName',
1306
- '2.5.4.10' => 'id-at-organizationName',
1307
- '2.5.4.11' => 'id-at-organizationalUnitName',
1308
- '2.5.4.12' => 'id-at-title',
1309
- '2.5.4.13' => 'id-at-description',
1310
- '2.5.4.46' => 'id-at-dnQualifier',
1311
- '2.5.4.6' => 'id-at-countryName',
1312
- '2.5.4.5' => 'id-at-serialNumber',
1313
- '2.5.4.65' => 'id-at-pseudonym',
1314
- '2.5.4.17' => 'id-at-postalCode',
1315
- '2.5.4.9' => 'id-at-streetAddress',
1316
- '2.5.4.45' => 'id-at-uniqueIdentifier',
1317
- '2.5.4.72' => 'id-at-role',
1318
- '2.5.4.16' => 'id-at-postalAddress',
1319
-
1320
- '0.9.2342.19200300.100.1.25' => 'id-domainComponent',
1321
- '1.2.840.113549.1.9' => 'pkcs-9',
1322
- '1.2.840.113549.1.9.1' => 'pkcs-9-at-emailAddress',
1323
- '2.5.29' => 'id-ce',
1324
- '2.5.29.35' => 'id-ce-authorityKeyIdentifier',
1325
- '2.5.29.14' => 'id-ce-subjectKeyIdentifier',
1326
- '2.5.29.15' => 'id-ce-keyUsage',
1327
- '2.5.29.16' => 'id-ce-privateKeyUsagePeriod',
1328
- '2.5.29.32' => 'id-ce-certificatePolicies',
1329
- '2.5.29.32.0' => 'anyPolicy',
1330
-
1331
- '2.5.29.33' => 'id-ce-policyMappings',
1332
- '2.5.29.17' => 'id-ce-subjectAltName',
1333
- '2.5.29.18' => 'id-ce-issuerAltName',
1334
- '2.5.29.9' => 'id-ce-subjectDirectoryAttributes',
1335
- '2.5.29.19' => 'id-ce-basicConstraints',
1336
- '2.5.29.30' => 'id-ce-nameConstraints',
1337
- '2.5.29.36' => 'id-ce-policyConstraints',
1338
- '2.5.29.31' => 'id-ce-cRLDistributionPoints',
1339
- '2.5.29.37' => 'id-ce-extKeyUsage',
1340
- '2.5.29.37.0' => 'anyExtendedKeyUsage',
1341
- '1.3.6.1.5.5.7.3.1' => 'id-kp-serverAuth',
1342
- '1.3.6.1.5.5.7.3.2' => 'id-kp-clientAuth',
1343
- '1.3.6.1.5.5.7.3.3' => 'id-kp-codeSigning',
1344
- '1.3.6.1.5.5.7.3.4' => 'id-kp-emailProtection',
1345
- '1.3.6.1.5.5.7.3.8' => 'id-kp-timeStamping',
1346
- '1.3.6.1.5.5.7.3.9' => 'id-kp-OCSPSigning',
1347
- '2.5.29.54' => 'id-ce-inhibitAnyPolicy',
1348
- '2.5.29.46' => 'id-ce-freshestCRL',
1349
- '1.3.6.1.5.5.7.1.1' => 'id-pe-authorityInfoAccess',
1350
- '1.3.6.1.5.5.7.1.11' => 'id-pe-subjectInfoAccess',
1351
- '2.5.29.20' => 'id-ce-cRLNumber',
1352
- '2.5.29.28' => 'id-ce-issuingDistributionPoint',
1353
- '2.5.29.27' => 'id-ce-deltaCRLIndicator',
1354
- '2.5.29.21' => 'id-ce-cRLReasons',
1355
- '2.5.29.29' => 'id-ce-certificateIssuer',
1356
- '2.5.29.23' => 'id-ce-holdInstructionCode',
1357
- '1.2.840.10040.2' => 'holdInstruction',
1358
- '1.2.840.10040.2.1' => 'id-holdinstruction-none',
1359
- '1.2.840.10040.2.2' => 'id-holdinstruction-callissuer',
1360
- '1.2.840.10040.2.3' => 'id-holdinstruction-reject',
1361
- '2.5.29.24' => 'id-ce-invalidityDate',
1362
-
1363
- '1.2.840.113549.2.2' => 'md2',
1364
- '1.2.840.113549.2.5' => 'md5',
1365
- '1.3.14.3.2.26' => 'id-sha1',
1366
- '1.2.840.10040.4.1' => 'id-dsa',
1367
- '1.2.840.10040.4.3' => 'id-dsa-with-sha1',
1368
- '1.2.840.113549.1.1' => 'pkcs-1',
1369
- '1.2.840.113549.1.1.1' => 'rsaEncryption',
1370
- '1.2.840.113549.1.1.2' => 'md2WithRSAEncryption',
1371
- '1.2.840.113549.1.1.4' => 'md5WithRSAEncryption',
1372
- '1.2.840.113549.1.1.5' => 'sha1WithRSAEncryption',
1373
- '1.2.840.10046.2.1' => 'dhpublicnumber',
1374
- '2.16.840.1.101.2.1.1.22' => 'id-keyExchangeAlgorithm',
1375
- '1.2.840.10045' => 'ansi-X9-62',
1376
- '1.2.840.10045.4' => 'id-ecSigType',
1377
- '1.2.840.10045.4.1' => 'ecdsa-with-SHA1',
1378
- '1.2.840.10045.1' => 'id-fieldType',
1379
- '1.2.840.10045.1.1' => 'prime-field',
1380
- '1.2.840.10045.1.2' => 'characteristic-two-field',
1381
- '1.2.840.10045.1.2.3' => 'id-characteristic-two-basis',
1382
- '1.2.840.10045.1.2.3.1' => 'gnBasis',
1383
- '1.2.840.10045.1.2.3.2' => 'tpBasis',
1384
- '1.2.840.10045.1.2.3.3' => 'ppBasis',
1385
- '1.2.840.10045.2' => 'id-publicKeyType',
1386
- '1.2.840.10045.2.1' => 'id-ecPublicKey',
1387
- '1.2.840.10045.3' => 'ellipticCurve',
1388
- '1.2.840.10045.3.0' => 'c-TwoCurve',
1389
- '1.2.840.10045.3.0.1' => 'c2pnb163v1',
1390
- '1.2.840.10045.3.0.2' => 'c2pnb163v2',
1391
- '1.2.840.10045.3.0.3' => 'c2pnb163v3',
1392
- '1.2.840.10045.3.0.4' => 'c2pnb176w1',
1393
- '1.2.840.10045.3.0.5' => 'c2pnb191v1',
1394
- '1.2.840.10045.3.0.6' => 'c2pnb191v2',
1395
- '1.2.840.10045.3.0.7' => 'c2pnb191v3',
1396
- '1.2.840.10045.3.0.8' => 'c2pnb191v4',
1397
- '1.2.840.10045.3.0.9' => 'c2pnb191v5',
1398
- '1.2.840.10045.3.0.10' => 'c2pnb208w1',
1399
- '1.2.840.10045.3.0.11' => 'c2pnb239v1',
1400
- '1.2.840.10045.3.0.12' => 'c2pnb239v2',
1401
- '1.2.840.10045.3.0.13' => 'c2pnb239v3',
1402
- '1.2.840.10045.3.0.14' => 'c2pnb239v4',
1403
- '1.2.840.10045.3.0.15' => 'c2pnb239v5',
1404
- '1.2.840.10045.3.0.16' => 'c2pnb272w1',
1405
- '1.2.840.10045.3.0.17' => 'c2pnb304w1',
1406
- '1.2.840.10045.3.0.18' => 'c2pnb359v1',
1407
- '1.2.840.10045.3.0.19' => 'c2pnb368w1',
1408
- '1.2.840.10045.3.0.20' => 'c2pnb431r1',
1409
- '1.2.840.10045.3.1' => 'primeCurve',
1410
- '1.2.840.10045.3.1.1' => 'prime192v1',
1411
- '1.2.840.10045.3.1.2' => 'prime192v2',
1412
- '1.2.840.10045.3.1.3' => 'prime192v3',
1413
- '1.2.840.10045.3.1.4' => 'prime239v1',
1414
- '1.2.840.10045.3.1.5' => 'prime239v2',
1415
- '1.2.840.10045.3.1.6' => 'prime239v3',
1416
- '1.2.840.10045.3.1.7' => 'prime256v1',
1417
- '1.2.840.113549.1.1.7' => 'id-RSAES-OAEP',
1418
- '1.2.840.113549.1.1.9' => 'id-pSpecified',
1419
- '1.2.840.113549.1.1.10' => 'id-RSASSA-PSS',
1420
- '1.2.840.113549.1.1.8' => 'id-mgf1',
1421
- '1.2.840.113549.1.1.14' => 'sha224WithRSAEncryption',
1422
- '1.2.840.113549.1.1.11' => 'sha256WithRSAEncryption',
1423
- '1.2.840.113549.1.1.12' => 'sha384WithRSAEncryption',
1424
- '1.2.840.113549.1.1.13' => 'sha512WithRSAEncryption',
1425
- '2.16.840.1.101.3.4.2.4' => 'id-sha224',
1426
- '2.16.840.1.101.3.4.2.1' => 'id-sha256',
1427
- '2.16.840.1.101.3.4.2.2' => 'id-sha384',
1428
- '2.16.840.1.101.3.4.2.3' => 'id-sha512',
1429
- '1.2.643.2.2.4' => 'id-GostR3411-94-with-GostR3410-94',
1430
- '1.2.643.2.2.3' => 'id-GostR3411-94-with-GostR3410-2001',
1431
- '1.2.643.2.2.20' => 'id-GostR3410-2001',
1432
- '1.2.643.2.2.19' => 'id-GostR3410-94',
1433
- // Netscape Object Identifiers from "Netscape Certificate Extensions"
1434
- '2.16.840.1.113730' => 'netscape',
1435
- '2.16.840.1.113730.1' => 'netscape-cert-extension',
1436
- '2.16.840.1.113730.1.1' => 'netscape-cert-type',
1437
- '2.16.840.1.113730.1.13' => 'netscape-comment',
1438
- '2.16.840.1.113730.1.8' => 'netscape-ca-policy-url',
1439
- // the following are X.509 extensions not supported by phpseclib
1440
- '1.3.6.1.5.5.7.1.12' => 'id-pe-logotype',
1441
- '1.2.840.113533.7.65.0' => 'entrustVersInfo',
1442
- '2.16.840.1.113733.1.6.9' => 'verisignPrivate',
1443
- // for Certificate Signing Requests
1444
- // see http://tools.ietf.org/html/rfc2985
1445
- '1.2.840.113549.1.9.2' => 'pkcs-9-at-unstructuredName', // PKCS #9 unstructured name
1446
- '1.2.840.113549.1.9.7' => 'pkcs-9-at-challengePassword', // Challenge password for certificate revocations
1447
- '1.2.840.113549.1.9.14' => 'pkcs-9-at-extensionRequest' // Certificate extension request
1448
- );
1449
- }
1450
-
1451
- /**
1452
- * PHP4 compatible Default Constructor.
1453
- *
1454
- * @see self::__construct()
1455
- * @access public
1456
- */
1457
- function File_X509()
1458
- {
1459
- $this->__construct();
1460
- }
1461
-
1462
- /**
1463
- * Load X.509 certificate
1464
- *
1465
- * Returns an associative array describing the X.509 cert or a false if the cert failed to load
1466
- *
1467
- * @param string $cert
1468
- * @param int $mode
1469
- * @access public
1470
- * @return mixed
1471
- */
1472
- function loadX509($cert, $mode = FILE_X509_FORMAT_AUTO_DETECT)
1473
- {
1474
- if (is_array($cert) && isset($cert['tbsCertificate'])) {
1475
- unset($this->currentCert);
1476
- unset($this->currentKeyIdentifier);
1477
- $this->dn = $cert['tbsCertificate']['subject'];
1478
- if (!isset($this->dn)) {
1479
- return false;
1480
- }
1481
- $this->currentCert = $cert;
1482
-
1483
- $currentKeyIdentifier = $this->getExtension('id-ce-subjectKeyIdentifier');
1484
- $this->currentKeyIdentifier = is_string($currentKeyIdentifier) ? $currentKeyIdentifier : null;
1485
-
1486
- unset($this->signatureSubject);
1487
-
1488
- return $cert;
1489
- }
1490
-
1491
- $asn1 = new File_ASN1();
1492
-
1493
- if ($mode != FILE_X509_FORMAT_DER) {
1494
- $newcert = $this->_extractBER($cert);
1495
- if ($mode == FILE_X509_FORMAT_PEM && $cert == $newcert) {
1496
- return false;
1497
- }
1498
- $cert = $newcert;
1499
- }
1500
-
1501
- if ($cert === false) {
1502
- $this->currentCert = false;
1503
- return false;
1504
- }
1505
-
1506
- $asn1->loadOIDs($this->oids);
1507
- $decoded = $asn1->decodeBER($cert);
1508
-
1509
- if (!empty($decoded)) {
1510
- $x509 = $asn1->asn1map($decoded[0], $this->Certificate);
1511
- }
1512
- if (!isset($x509) || $x509 === false) {
1513
- $this->currentCert = false;
1514
- return false;
1515
- }
1516
-
1517
- $this->signatureSubject = substr($cert, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']);
1518
-
1519
- if ($this->_isSubArrayValid($x509, 'tbsCertificate/extensions')) {
1520
- $this->_mapInExtensions($x509, 'tbsCertificate/extensions', $asn1);
1521
- }
1522
- $this->_mapInDNs($x509, 'tbsCertificate/issuer/rdnSequence', $asn1);
1523
- $this->_mapInDNs($x509, 'tbsCertificate/subject/rdnSequence', $asn1);
1524
-
1525
- $key = &$x509['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'];
1526
- $key = $this->_reformatKey($x509['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['algorithm'], $key);
1527
-
1528
- $this->currentCert = $x509;
1529
- $this->dn = $x509['tbsCertificate']['subject'];
1530
-
1531
- $currentKeyIdentifier = $this->getExtension('id-ce-subjectKeyIdentifier');
1532
- $this->currentKeyIdentifier = is_string($currentKeyIdentifier) ? $currentKeyIdentifier : null;
1533
-
1534
- return $x509;
1535
- }
1536
-
1537
- /**
1538
- * Save X.509 certificate
1539
- *
1540
- * @param array $cert
1541
- * @param int $format optional
1542
- * @access public
1543
- * @return string
1544
- */
1545
- function saveX509($cert, $format = FILE_X509_FORMAT_PEM)
1546
- {
1547
- if (!is_array($cert) || !isset($cert['tbsCertificate'])) {
1548
- return false;
1549
- }
1550
-
1551
- switch (true) {
1552
- // "case !$a: case !$b: break; default: whatever();" is the same thing as "if ($a && $b) whatever()"
1553
- case !($algorithm = $this->_subArray($cert, 'tbsCertificate/subjectPublicKeyInfo/algorithm/algorithm')):
1554
- case is_object($cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey']):
1555
- break;
1556
- default:
1557
- switch ($algorithm) {
1558
- case 'rsaEncryption':
1559
- $cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey']
1560
- = base64_encode("\0" . base64_decode(preg_replace('#-.+-|[\r\n]#', '', $cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'])));
1561
- /* "[For RSA keys] the parameters field MUST have ASN.1 type NULL for this algorithm identifier."
1562
- -- https://tools.ietf.org/html/rfc3279#section-2.3.1
1563
-
1564
- given that and the fact that RSA keys appear ot be the only key type for which the parameters field can be blank,
1565
- it seems like perhaps the ASN.1 description ought not say the parameters field is OPTIONAL, but whatever.
1566
- */
1567
- $cert['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['parameters'] = null;
1568
- // https://tools.ietf.org/html/rfc3279#section-2.2.1
1569
- $cert['signatureAlgorithm']['parameters'] = null;
1570
- $cert['tbsCertificate']['signature']['parameters'] = null;
1571
- }
1572
- }
1573
-
1574
- $asn1 = new File_ASN1();
1575
- $asn1->loadOIDs($this->oids);
1576
-
1577
- $filters = array();
1578
- $type_utf8_string = array('type' => FILE_ASN1_TYPE_UTF8_STRING);
1579
- $filters['tbsCertificate']['signature']['parameters'] = $type_utf8_string;
1580
- $filters['tbsCertificate']['signature']['issuer']['rdnSequence']['value'] = $type_utf8_string;
1581
- $filters['tbsCertificate']['issuer']['rdnSequence']['value'] = $type_utf8_string;
1582
- $filters['tbsCertificate']['subject']['rdnSequence']['value'] = $type_utf8_string;
1583
- $filters['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['parameters'] = $type_utf8_string;
1584
- $filters['signatureAlgorithm']['parameters'] = $type_utf8_string;
1585
- $filters['authorityCertIssuer']['directoryName']['rdnSequence']['value'] = $type_utf8_string;
1586
- //$filters['policyQualifiers']['qualifier'] = $type_utf8_string;
1587
- $filters['distributionPoint']['fullName']['directoryName']['rdnSequence']['value'] = $type_utf8_string;
1588
- $filters['directoryName']['rdnSequence']['value'] = $type_utf8_string;
1589
-
1590
- /* in the case of policyQualifiers/qualifier, the type has to be FILE_ASN1_TYPE_IA5_STRING.
1591
- FILE_ASN1_TYPE_PRINTABLE_STRING will cause OpenSSL's X.509 parser to spit out random
1592
- characters.
1593
- */
1594
- $filters['policyQualifiers']['qualifier']
1595
- = array('type' => FILE_ASN1_TYPE_IA5_STRING);
1596
-
1597
- $asn1->loadFilters($filters);
1598
-
1599
- $this->_mapOutExtensions($cert, 'tbsCertificate/extensions', $asn1);
1600
- $this->_mapOutDNs($cert, 'tbsCertificate/issuer/rdnSequence', $asn1);
1601
- $this->_mapOutDNs($cert, 'tbsCertificate/subject/rdnSequence', $asn1);
1602
-
1603
- $cert = $asn1->encodeDER($cert, $this->Certificate);
1604
-
1605
- switch ($format) {
1606
- case FILE_X509_FORMAT_DER:
1607
- return $cert;
1608
- // case FILE_X509_FORMAT_PEM:
1609
- default:
1610
- return "-----BEGIN CERTIFICATE-----\r\n" . chunk_split(base64_encode($cert), 64) . '-----END CERTIFICATE-----';
1611
- }
1612
- }
1613
-
1614
- /**
1615
- * Map extension values from octet string to extension-specific internal
1616
- * format.
1617
- *
1618
- * @param array ref $root
1619
- * @param string $path
1620
- * @param object $asn1
1621
- * @access private
1622
- */
1623
- function _mapInExtensions(&$root, $path, $asn1)
1624
- {
1625
- $extensions = &$this->_subArrayUnchecked($root, $path);
1626
-
1627
- if ($extensions) {
1628
- for ($i = 0; $i < count($extensions); $i++) {
1629
- $id = $extensions[$i]['extnId'];
1630
- $value = &$extensions[$i]['extnValue'];
1631
- $value = base64_decode($value);
1632
- $decoded = $asn1->decodeBER($value);
1633
- /* [extnValue] contains the DER encoding of an ASN.1 value
1634
- corresponding to the extension type identified by extnID */
1635
- $map = $this->_getMapping($id);
1636
- if (!is_bool($map)) {
1637
- $mapped = $asn1->asn1map($decoded[0], $map, array('iPAddress' => array($this, '_decodeIP')));
1638
- $value = $mapped === false ? $decoded[0] : $mapped;
1639
-
1640
- if ($id == 'id-ce-certificatePolicies') {
1641
- for ($j = 0; $j < count($value); $j++) {
1642
- if (!isset($value[$j]['policyQualifiers'])) {
1643
- continue;
1644
- }
1645
- for ($k = 0; $k < count($value[$j]['policyQualifiers']); $k++) {
1646
- $subid = $value[$j]['policyQualifiers'][$k]['policyQualifierId'];
1647
- $map = $this->_getMapping($subid);
1648
- $subvalue = &$value[$j]['policyQualifiers'][$k]['qualifier'];
1649
- if ($map !== false) {
1650
- $decoded = $asn1->decodeBER($subvalue);
1651
- $mapped = $asn1->asn1map($decoded[0], $map);
1652
- $subvalue = $mapped === false ? $decoded[0] : $mapped;
1653
- }
1654
- }
1655
- }
1656
- }
1657
- } else {
1658
- $value = base64_encode($value);
1659
- }
1660
- }
1661
- }
1662
- }
1663
-
1664
- /**
1665
- * Map extension values from extension-specific internal format to
1666
- * octet string.
1667
- *
1668
- * @param array ref $root
1669
- * @param string $path
1670
- * @param object $asn1
1671
- * @access private
1672
- */
1673
- function _mapOutExtensions(&$root, $path, $asn1)
1674
- {
1675
- $extensions = &$this->_subArray($root, $path);
1676
-
1677
- if (is_array($extensions)) {
1678
- $size = count($extensions);
1679
- for ($i = 0; $i < $size; $i++) {
1680
- if (is_object($extensions[$i]) && strtolower(get_class($extensions[$i])) == 'file_asn1_element') {
1681
- continue;
1682
- }
1683
-
1684
- $id = $extensions[$i]['extnId'];
1685
- $value = &$extensions[$i]['extnValue'];
1686
-
1687
- switch ($id) {
1688
- case 'id-ce-certificatePolicies':
1689
- for ($j = 0; $j < count($value); $j++) {
1690
- if (!isset($value[$j]['policyQualifiers'])) {
1691
- continue;
1692
- }
1693
- for ($k = 0; $k < count($value[$j]['policyQualifiers']); $k++) {
1694
- $subid = $value[$j]['policyQualifiers'][$k]['policyQualifierId'];
1695
- $map = $this->_getMapping($subid);
1696
- $subvalue = &$value[$j]['policyQualifiers'][$k]['qualifier'];
1697
- if ($map !== false) {
1698
- // by default File_ASN1 will try to render qualifier as a FILE_ASN1_TYPE_IA5_STRING since it's
1699
- // actual type is FILE_ASN1_TYPE_ANY
1700
- $subvalue = new File_ASN1_Element($asn1->encodeDER($subvalue, $map));
1701
- }
1702
- }
1703
- }
1704
- break;
1705
- case 'id-ce-authorityKeyIdentifier': // use 00 as the serial number instead of an empty string
1706
- if (isset($value['authorityCertSerialNumber'])) {
1707
- if ($value['authorityCertSerialNumber']->toBytes() == '') {
1708
- $temp = chr((FILE_ASN1_CLASS_CONTEXT_SPECIFIC << 6) | 2) . "\1\0";
1709
- $value['authorityCertSerialNumber'] = new File_ASN1_Element($temp);
1710
- }
1711
- }
1712
- }
1713
-
1714
- /* [extnValue] contains the DER encoding of an ASN.1 value
1715
- corresponding to the extension type identified by extnID */
1716
- $map = $this->_getMapping($id);
1717
- if (is_bool($map)) {
1718
- if (!$map) {
1719
- user_error($id . ' is not a currently supported extension');
1720
- unset($extensions[$i]);
1721
- }
1722
- } else {
1723
- $temp = $asn1->encodeDER($value, $map, array('iPAddress' => array($this, '_encodeIP')));
1724
- $value = base64_encode($temp);
1725
- }
1726
- }
1727
- }
1728
- }
1729
-
1730
- /**
1731
- * Map attribute values from ANY type to attribute-specific internal
1732
- * format.
1733
- *
1734
- * @param array ref $root
1735
- * @param string $path
1736
- * @param object $asn1
1737
- * @access private
1738
- */
1739
- function _mapInAttributes(&$root, $path, $asn1)
1740
- {
1741
- $attributes = &$this->_subArray($root, $path);
1742
-
1743
- if (is_array($attributes)) {
1744
- for ($i = 0; $i < count($attributes); $i++) {
1745
- $id = $attributes[$i]['type'];
1746
- /* $value contains the DER encoding of an ASN.1 value
1747
- corresponding to the attribute type identified by type */
1748
- $map = $this->_getMapping($id);
1749
- if (is_array($attributes[$i]['value'])) {
1750
- $values = &$attributes[$i]['value'];
1751
- for ($j = 0; $j < count($values); $j++) {
1752
- $value = $asn1->encodeDER($values[$j], $this->AttributeValue);
1753
- $decoded = $asn1->decodeBER($value);
1754
- if (!is_bool($map)) {
1755
- $mapped = $asn1->asn1map($decoded[0], $map);
1756
- if ($mapped !== false) {
1757
- $values[$j] = $mapped;
1758
- }
1759
- if ($id == 'pkcs-9-at-extensionRequest' && $this->_isSubArrayValid($values, $j)) {
1760
- $this->_mapInExtensions($values, $j, $asn1);
1761
- }
1762
- } elseif ($map) {
1763
- $values[$j] = base64_encode($value);
1764
- }
1765
- }
1766
- }
1767
- }
1768
- }
1769
- }
1770
-
1771
- /**
1772
- * Map attribute values from attribute-specific internal format to
1773
- * ANY type.
1774
- *
1775
- * @param array ref $root
1776
- * @param string $path
1777
- * @param object $asn1
1778
- * @access private
1779
- */
1780
- function _mapOutAttributes(&$root, $path, $asn1)
1781
- {
1782
- $attributes = &$this->_subArray($root, $path);
1783
-
1784
- if (is_array($attributes)) {
1785
- $size = count($attributes);
1786
- for ($i = 0; $i < $size; $i++) {
1787
- /* [value] contains the DER encoding of an ASN.1 value
1788
- corresponding to the attribute type identified by type */
1789
- $id = $attributes[$i]['type'];
1790
- $map = $this->_getMapping($id);
1791
- if ($map === false) {
1792
- user_error($id . ' is not a currently supported attribute', E_USER_NOTICE);
1793
- unset($attributes[$i]);
1794
- } elseif (is_array($attributes[$i]['value'])) {
1795
- $values = &$attributes[$i]['value'];
1796
- for ($j = 0; $j < count($values); $j++) {
1797
- switch ($id) {
1798
- case 'pkcs-9-at-extensionRequest':
1799
- $this->_mapOutExtensions($values, $j, $asn1);
1800
- break;
1801
- }
1802
-
1803
- if (!is_bool($map)) {
1804
- $temp = $asn1->encodeDER($values[$j], $map);
1805
- $decoded = $asn1->decodeBER($temp);
1806
- $values[$j] = $asn1->asn1map($decoded[0], $this->AttributeValue);
1807
- }
1808
- }
1809
- }
1810
- }
1811
- }
1812
- }
1813
-
1814
- /**
1815
- * Map DN values from ANY type to DN-specific internal
1816
- * format.
1817
- *
1818
- * @param array ref $root
1819
- * @param string $path
1820
- * @param object $asn1
1821
- * @access private
1822
- */
1823
- function _mapInDNs(&$root, $path, $asn1)
1824
- {
1825
- $dns = &$this->_subArray($root, $path);
1826
-
1827
- if (is_array($dns)) {
1828
- for ($i = 0; $i < count($dns); $i++) {
1829
- for ($j = 0; $j < count($dns[$i]); $j++) {
1830
- $type = $dns[$i][$j]['type'];
1831
- $value = &$dns[$i][$j]['value'];
1832
- if (is_object($value) && strtolower(get_class($value)) == 'file_asn1_element') {
1833
- $map = $this->_getMapping($type);
1834
- if (!is_bool($map)) {
1835
- $decoded = $asn1->decodeBER($value);
1836
- $value = $asn1->asn1map($decoded[0], $map);
1837
- }
1838
- }
1839
- }
1840
- }
1841
- }
1842
- }
1843
-
1844
- /**
1845
- * Map DN values from DN-specific internal format to
1846
- * ANY type.
1847
- *
1848
- * @param array ref $root
1849
- * @param string $path
1850
- * @param object $asn1
1851
- * @access private
1852
- */
1853
- function _mapOutDNs(&$root, $path, $asn1)
1854
- {
1855
- $dns = &$this->_subArray($root, $path);
1856
-
1857
- if (is_array($dns)) {
1858
- $size = count($dns);
1859
- for ($i = 0; $i < $size; $i++) {
1860
- for ($j = 0; $j < count($dns[$i]); $j++) {
1861
- $type = $dns[$i][$j]['type'];
1862
- $value = &$dns[$i][$j]['value'];
1863
- if (is_object($value) && strtolower(get_class($value)) == 'file_asn1_element') {
1864
- continue;
1865
- }
1866
-
1867
- $map = $this->_getMapping($type);
1868
- if (!is_bool($map)) {
1869
- $value = new File_ASN1_Element($asn1->encodeDER($value, $map));
1870
- }
1871
- }
1872
- }
1873
- }
1874
- }
1875
-
1876
- /**
1877
- * Associate an extension ID to an extension mapping
1878
- *
1879
- * @param string $extnId
1880
- * @access private
1881
- * @return mixed
1882
- */
1883
- function _getMapping($extnId)
1884
- {
1885
- if (!is_string($extnId)) { // eg. if it's a File_ASN1_Element object
1886
- return true;
1887
- }
1888
-
1889
- switch ($extnId) {
1890
- case 'id-ce-keyUsage':
1891
- return $this->KeyUsage;
1892
- case 'id-ce-basicConstraints':
1893
- return $this->BasicConstraints;
1894
- case 'id-ce-subjectKeyIdentifier':
1895
- return $this->KeyIdentifier;
1896
- case 'id-ce-cRLDistributionPoints':
1897
- return $this->CRLDistributionPoints;
1898
- case 'id-ce-authorityKeyIdentifier':
1899
- return $this->AuthorityKeyIdentifier;
1900
- case 'id-ce-certificatePolicies':
1901
- return $this->CertificatePolicies;
1902
- case 'id-ce-extKeyUsage':
1903
- return $this->ExtKeyUsageSyntax;
1904
- case 'id-pe-authorityInfoAccess':
1905
- return $this->AuthorityInfoAccessSyntax;
1906
- case 'id-ce-subjectAltName':
1907
- return $this->SubjectAltName;
1908
- case 'id-ce-subjectDirectoryAttributes':
1909
- return $this->SubjectDirectoryAttributes;
1910
- case 'id-ce-privateKeyUsagePeriod':
1911
- return $this->PrivateKeyUsagePeriod;
1912
- case 'id-ce-issuerAltName':
1913
- return $this->IssuerAltName;
1914
- case 'id-ce-policyMappings':
1915
- return $this->PolicyMappings;
1916
- case 'id-ce-nameConstraints':
1917
- return $this->NameConstraints;
1918
-
1919
- case 'netscape-cert-type':
1920
- return $this->netscape_cert_type;
1921
- case 'netscape-comment':
1922
- return $this->netscape_comment;
1923
- case 'netscape-ca-policy-url':
1924
- return $this->netscape_ca_policy_url;
1925
-
1926
- // since id-qt-cps isn't a constructed type it will have already been decoded as a string by the time it gets
1927
- // back around to asn1map() and we don't want it decoded again.
1928
- //case 'id-qt-cps':
1929
- // return $this->CPSuri;
1930
- case 'id-qt-unotice':
1931
- return $this->UserNotice;
1932
-
1933
- // the following OIDs are unsupported but we don't want them to give notices when calling saveX509().
1934
- case 'id-pe-logotype': // http://www.ietf.org/rfc/rfc3709.txt
1935
- case 'entrustVersInfo':
1936
- // http://support.microsoft.com/kb/287547
1937
- case '1.3.6.1.4.1.311.20.2': // szOID_ENROLL_CERTTYPE_EXTENSION
1938
- case '1.3.6.1.4.1.311.21.1': // szOID_CERTSRV_CA_VERSION
1939
- // "SET Secure Electronic Transaction Specification"
1940
- // http://www.maithean.com/docs/set_bk3.pdf
1941
- case '2.23.42.7.0': // id-set-hashedRootKey
1942
- return true;
1943
-
1944
- // CSR attributes
1945
- case 'pkcs-9-at-unstructuredName':
1946
- return $this->PKCS9String;
1947
- case 'pkcs-9-at-challengePassword':
1948
- return $this->DirectoryString;
1949
- case 'pkcs-9-at-extensionRequest':
1950
- return $this->Extensions;
1951
-
1952
- // CRL extensions.
1953
- case 'id-ce-cRLNumber':
1954
- return $this->CRLNumber;
1955
- case 'id-ce-deltaCRLIndicator':
1956
- return $this->CRLNumber;
1957
- case 'id-ce-issuingDistributionPoint':
1958
- return $this->IssuingDistributionPoint;
1959
- case 'id-ce-freshestCRL':
1960
- return $this->CRLDistributionPoints;
1961
- case 'id-ce-cRLReasons':
1962
- return $this->CRLReason;
1963
- case 'id-ce-invalidityDate':
1964
- return $this->InvalidityDate;
1965
- case 'id-ce-certificateIssuer':
1966
- return $this->CertificateIssuer;
1967
- case 'id-ce-holdInstructionCode':
1968
- return $this->HoldInstructionCode;
1969
- case 'id-at-postalAddress':
1970
- return $this->PostalAddress;
1971
- }
1972
-
1973
- return false;
1974
- }
1975
-
1976
- /**
1977
- * Load an X.509 certificate as a certificate authority
1978
- *
1979
- * @param string $cert
1980
- * @access public
1981
- * @return bool
1982
- */
1983
- function loadCA($cert)
1984
- {
1985
- $olddn = $this->dn;
1986
- $oldcert = $this->currentCert;
1987
- $oldsigsubj = $this->signatureSubject;
1988
- $oldkeyid = $this->currentKeyIdentifier;
1989
-
1990
- $cert = $this->loadX509($cert);
1991
- if (!$cert) {
1992
- $this->dn = $olddn;
1993
- $this->currentCert = $oldcert;
1994
- $this->signatureSubject = $oldsigsubj;
1995
- $this->currentKeyIdentifier = $oldkeyid;
1996
-
1997
- return false;
1998
- }
1999
-
2000
- /* From RFC5280 "PKIX Certificate and CRL Profile":
2001
-
2002
- If the keyUsage extension is present, then the subject public key
2003
- MUST NOT be used to verify signatures on certificates or CRLs unless
2004
- the corresponding keyCertSign or cRLSign bit is set. */
2005
- //$keyUsage = $this->getExtension('id-ce-keyUsage');
2006
- //if ($keyUsage && !in_array('keyCertSign', $keyUsage)) {
2007
- // return false;
2008
- //}
2009
-
2010
- /* From RFC5280 "PKIX Certificate and CRL Profile":
2011
-
2012
- The cA boolean indicates whether the certified public key may be used
2013
- to verify certificate signatures. If the cA boolean is not asserted,
2014
- then the keyCertSign bit in the key usage extension MUST NOT be
2015
- asserted. If the basic constraints extension is not present in a
2016
- version 3 certificate, or the extension is present but the cA boolean
2017
- is not asserted, then the certified public key MUST NOT be used to
2018
- verify certificate signatures. */
2019
- //$basicConstraints = $this->getExtension('id-ce-basicConstraints');
2020
- //if (!$basicConstraints || !$basicConstraints['cA']) {
2021
- // return false;
2022
- //}
2023
-
2024
- $this->CAs[] = $cert;
2025
-
2026
- $this->dn = $olddn;
2027
- $this->currentCert = $oldcert;
2028
- $this->signatureSubject = $oldsigsubj;
2029
-
2030
- return true;
2031
- }
2032
-
2033
- /**
2034
- * Validate an X.509 certificate against a URL
2035
- *
2036
- * From RFC2818 "HTTP over TLS":
2037
- *
2038
- * Matching is performed using the matching rules specified by
2039
- * [RFC2459]. If more than one identity of a given type is present in
2040
- * the certificate (e.g., more than one dNSName name, a match in any one
2041
- * of the set is considered acceptable.) Names may contain the wildcard
2042
- * character * which is considered to match any single domain name
2043
- * component or component fragment. E.g., *.a.com matches foo.a.com but
2044
- * not bar.foo.a.com. f*.com matches foo.com but not bar.com.
2045
- *
2046
- * @param string $url
2047
- * @access public
2048
- * @return bool
2049
- */
2050
- function validateURL($url)
2051
- {
2052
- if (!is_array($this->currentCert) || !isset($this->currentCert['tbsCertificate'])) {
2053
- return false;
2054
- }
2055
-
2056
- $components = parse_url($url);
2057
- if (!isset($components['host'])) {
2058
- return false;
2059
- }
2060
-
2061
- if ($names = $this->getExtension('id-ce-subjectAltName')) {
2062
- foreach ($names as $key => $value) {
2063
- $value = str_replace(array('.', '*'), array('\.', '[^.]*'), $value);
2064
- switch ($key) {
2065
- case 'dNSName':
2066
- /* From RFC2818 "HTTP over TLS":
2067
-
2068
- If a subjectAltName extension of type dNSName is present, that MUST
2069
- be used as the identity. Otherwise, the (most specific) Common Name
2070
- field in the Subject field of the certificate MUST be used. Although
2071
- the use of the Common Name is existing practice, it is deprecated and
2072
- Certification Authorities are encouraged to use the dNSName instead. */
2073
- if (preg_match('#^' . $value . '$#', $components['host'])) {
2074
- return true;
2075
- }
2076
- break;
2077
- case 'iPAddress':
2078
- /* From RFC2818 "HTTP over TLS":
2079
-
2080
- In some cases, the URI is specified as an IP address rather than a
2081
- hostname. In this case, the iPAddress subjectAltName must be present
2082
- in the certificate and must exactly match the IP in the URI. */
2083
- if (preg_match('#(?:\d{1-3}\.){4}#', $components['host'] . '.') && preg_match('#^' . $value . '$#', $components['host'])) {
2084
- return true;
2085
- }
2086
- }
2087
- }
2088
- return false;
2089
- }
2090
-
2091
- if ($value = $this->getDNProp('id-at-commonName')) {
2092
- $value = str_replace(array('.', '*'), array('\.', '[^.]*'), $value[0]);
2093
- return preg_match('#^' . $value . '$#', $components['host']);
2094
- }
2095
-
2096
- return false;
2097
- }
2098
-
2099
- /**
2100
- * Validate a date
2101
- *
2102
- * If $date isn't defined it is assumed to be the current date.
2103
- *
2104
- * @param int $date optional
2105
- * @access public
2106
- */
2107
- function validateDate($date = null)
2108
- {
2109
- if (!is_array($this->currentCert) || !isset($this->currentCert['tbsCertificate'])) {
2110
- return false;
2111
- }
2112
-
2113
- if (!isset($date)) {
2114
- $date = time();
2115
- }
2116
-
2117
- $notBefore = $this->currentCert['tbsCertificate']['validity']['notBefore'];
2118
- $notBefore = isset($notBefore['generalTime']) ? $notBefore['generalTime'] : $notBefore['utcTime'];
2119
-
2120
- $notAfter = $this->currentCert['tbsCertificate']['validity']['notAfter'];
2121
- $notAfter = isset($notAfter['generalTime']) ? $notAfter['generalTime'] : $notAfter['utcTime'];
2122
-
2123
- switch (true) {
2124
- case $date < @strtotime($notBefore):
2125
- case $date > @strtotime($notAfter):
2126
- return false;
2127
- }
2128
-
2129
- return true;
2130
- }
2131
-
2132
- /**
2133
- * Validate a signature
2134
- *
2135
- * Works on X.509 certs, CSR's and CRL's.
2136
- * Returns true if the signature is verified, false if it is not correct or null on error
2137
- *
2138
- * By default returns false for self-signed certs. Call validateSignature(false) to make this support
2139
- * self-signed.
2140
- *
2141
- * The behavior of this function is inspired by {@link http://php.net/openssl-verify openssl_verify}.
2142
- *
2143
- * @param bool $caonly optional
2144
- * @access public
2145
- * @return mixed
2146
- */
2147
- function validateSignature($caonly = true)
2148
- {
2149
- if (!is_array($this->currentCert) || !isset($this->signatureSubject)) {
2150
- return null;
2151
- }
2152
-
2153
- /* TODO:
2154
- "emailAddress attribute values are not case-sensitive (e.g., "subscriber@example.com" is the same as "SUBSCRIBER@EXAMPLE.COM")."
2155
- -- http://tools.ietf.org/html/rfc5280#section-4.1.2.6
2156
-
2157
- implement pathLenConstraint in the id-ce-basicConstraints extension */
2158
-
2159
- switch (true) {
2160
- case isset($this->currentCert['tbsCertificate']):
2161
- // self-signed cert
2162
- switch (true) {
2163
- case !defined('FILE_X509_IGNORE_TYPE') && $this->currentCert['tbsCertificate']['issuer'] === $this->currentCert['tbsCertificate']['subject']:
2164
- case defined('FILE_X509_IGNORE_TYPE') && $this->getIssuerDN(FILE_X509_DN_STRING) === $this->getDN(FILE_X509_DN_STRING):
2165
- $authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier');
2166
- $subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier');
2167
- switch (true) {
2168
- case !is_array($authorityKey):
2169
- case is_array($authorityKey) && isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
2170
- $signingCert = $this->currentCert; // working cert
2171
- }
2172
- }
2173
-
2174
- if (!empty($this->CAs)) {
2175
- for ($i = 0; $i < count($this->CAs); $i++) {
2176
- // even if the cert is a self-signed one we still want to see if it's a CA;
2177
- // if not, we'll conditionally return an error
2178
- $ca = $this->CAs[$i];
2179
- switch (true) {
2180
- case !defined('FILE_X509_IGNORE_TYPE') && $this->currentCert['tbsCertificate']['issuer'] === $ca['tbsCertificate']['subject']:
2181
- case defined('FILE_X509_IGNORE_TYPE') && $this->getDN(FILE_X509_DN_STRING, $this->currentCert['tbsCertificate']['issuer']) === $this->getDN(FILE_X509_DN_STRING, $ca['tbsCertificate']['subject']):
2182
- $authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier');
2183
- $subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier', $ca);
2184
- switch (true) {
2185
- case !is_array($authorityKey):
2186
- case is_array($authorityKey) && isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
2187
- $signingCert = $ca; // working cert
2188
- break 3;
2189
- }
2190
- }
2191
- }
2192
- if (count($this->CAs) == $i && $caonly) {
2193
- return false;
2194
- }
2195
- } elseif (!isset($signingCert) || $caonly) {
2196
- return false;
2197
- }
2198
- return $this->_validateSignature(
2199
- $signingCert['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['algorithm'],
2200
- $signingCert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'],
2201
- $this->currentCert['signatureAlgorithm']['algorithm'],
2202
- substr(base64_decode($this->currentCert['signature']), 1),
2203
- $this->signatureSubject
2204
- );
2205
- case isset($this->currentCert['certificationRequestInfo']):
2206
- return $this->_validateSignature(
2207
- $this->currentCert['certificationRequestInfo']['subjectPKInfo']['algorithm']['algorithm'],
2208
- $this->currentCert['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'],
2209
- $this->currentCert['signatureAlgorithm']['algorithm'],
2210
- substr(base64_decode($this->currentCert['signature']), 1),
2211
- $this->signatureSubject
2212
- );
2213
- case isset($this->currentCert['publicKeyAndChallenge']):
2214
- return $this->_validateSignature(
2215
- $this->currentCert['publicKeyAndChallenge']['spki']['algorithm']['algorithm'],
2216
- $this->currentCert['publicKeyAndChallenge']['spki']['subjectPublicKey'],
2217
- $this->currentCert['signatureAlgorithm']['algorithm'],
2218
- substr(base64_decode($this->currentCert['signature']), 1),
2219
- $this->signatureSubject
2220
- );
2221
- case isset($this->currentCert['tbsCertList']):
2222
- if (!empty($this->CAs)) {
2223
- for ($i = 0; $i < count($this->CAs); $i++) {
2224
- $ca = $this->CAs[$i];
2225
- switch (true) {
2226
- case !defined('FILE_X509_IGNORE_TYPE') && $this->currentCert['tbsCertList']['issuer'] === $ca['tbsCertificate']['subject']:
2227
- case defined('FILE_X509_IGNORE_TYPE') && $this->getDN(FILE_X509_DN_STRING, $this->currentCert['tbsCertList']['issuer']) === $this->getDN(FILE_X509_DN_STRING, $ca['tbsCertificate']['subject']):
2228
- $authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier');
2229
- $subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier', $ca);
2230
- switch (true) {
2231
- case !is_array($authorityKey):
2232
- case is_array($authorityKey) && isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
2233
- $signingCert = $ca; // working cert
2234
- break 3;
2235
- }
2236
- }
2237
- }
2238
- }
2239
- if (!isset($signingCert)) {
2240
- return false;
2241
- }
2242
- return $this->_validateSignature(
2243
- $signingCert['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['algorithm'],
2244
- $signingCert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'],
2245
- $this->currentCert['signatureAlgorithm']['algorithm'],
2246
- substr(base64_decode($this->currentCert['signature']), 1),
2247
- $this->signatureSubject
2248
- );
2249
- default:
2250
- return false;
2251
- }
2252
- }
2253
-
2254
- /**
2255
- * Validates a signature
2256
- *
2257
- * Returns true if the signature is verified, false if it is not correct or null on error
2258
- *
2259
- * @param string $publicKeyAlgorithm
2260
- * @param string $publicKey
2261
- * @param string $signatureAlgorithm
2262
- * @param string $signature
2263
- * @param string $signatureSubject
2264
- * @access private
2265
- * @return int
2266
- */
2267
- function _validateSignature($publicKeyAlgorithm, $publicKey, $signatureAlgorithm, $signature, $signatureSubject)
2268
- {
2269
- switch ($publicKeyAlgorithm) {
2270
- case 'rsaEncryption':
2271
- if (!class_exists('Crypt_RSA')) {
2272
- include_once 'Crypt/RSA.php';
2273
- }
2274
- $rsa = new Crypt_RSA();
2275
- $rsa->loadKey($publicKey);
2276
-
2277
- switch ($signatureAlgorithm) {
2278
- case 'md2WithRSAEncryption':
2279
- case 'md5WithRSAEncryption':
2280
- case 'sha1WithRSAEncryption':
2281
- case 'sha224WithRSAEncryption':
2282
- case 'sha256WithRSAEncryption':
2283
- case 'sha384WithRSAEncryption':
2284
- case 'sha512WithRSAEncryption':
2285
- $rsa->setHash(preg_replace('#WithRSAEncryption$#', '', $signatureAlgorithm));
2286
- $rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);
2287
- if (!@$rsa->verify($signatureSubject, $signature)) {
2288
- return false;
2289
- }
2290
- break;
2291
- default:
2292
- return null;
2293
- }
2294
- break;
2295
- default:
2296
- return null;
2297
- }
2298
-
2299
- return true;
2300
- }
2301
-
2302
- /**
2303
- * Reformat public keys
2304
- *
2305
- * Reformats a public key to a format supported by phpseclib (if applicable)
2306
- *
2307
- * @param string $algorithm
2308
- * @param string $key
2309
- * @access private
2310
- * @return string
2311
- */
2312
- function _reformatKey($algorithm, $key)
2313
- {
2314
- switch ($algorithm) {
2315
- case 'rsaEncryption':
2316
- return
2317
- "-----BEGIN RSA PUBLIC KEY-----\r\n" .
2318
- // subjectPublicKey is stored as a bit string in X.509 certs. the first byte of a bit string represents how many bits
2319
- // in the last byte should be ignored. the following only supports non-zero stuff but as none of the X.509 certs Firefox
2320
- // uses as a cert authority actually use a non-zero bit I think it's safe to assume that none do.
2321
- chunk_split(base64_encode(substr(base64_decode($key), 1)), 64) .
2322
- '-----END RSA PUBLIC KEY-----';
2323
- default:
2324
- return $key;
2325
- }
2326
- }
2327
-
2328
- /**
2329
- * Decodes an IP address
2330
- *
2331
- * Takes in a base64 encoded "blob" and returns a human readable IP address
2332
- *
2333
- * @param string $ip
2334
- * @access private
2335
- * @return string
2336
- */
2337
- function _decodeIP($ip)
2338
- {
2339
- $ip = base64_decode($ip);
2340
- list(, $ip) = unpack('N', $ip);
2341
- return long2ip($ip);
2342
- }
2343
-
2344
- /**
2345
- * Encodes an IP address
2346
- *
2347
- * Takes a human readable IP address into a base64-encoded "blob"
2348
- *
2349
- * @param string $ip
2350
- * @access private
2351
- * @return string
2352
- */
2353
- function _encodeIP($ip)
2354
- {
2355
- return base64_encode(pack('N', ip2long($ip)));
2356
- }
2357
-
2358
- /**
2359
- * "Normalizes" a Distinguished Name property
2360
- *
2361
- * @param string $propName
2362
- * @access private
2363
- * @return mixed
2364
- */
2365
- function _translateDNProp($propName)
2366
- {
2367
- switch (strtolower($propName)) {
2368
- case 'id-at-countryname':
2369
- case 'countryname':
2370
- case 'c':
2371
- return 'id-at-countryName';
2372
- case 'id-at-organizationname':
2373
- case 'organizationname':
2374
- case 'o':
2375
- return 'id-at-organizationName';
2376
- case 'id-at-dnqualifier':
2377
- case 'dnqualifier':
2378
- return 'id-at-dnQualifier';
2379
- case 'id-at-commonname':
2380
- case 'commonname':
2381
- case 'cn':
2382
- return 'id-at-commonName';
2383
- case 'id-at-stateorprovincename':
2384
- case 'stateorprovincename':
2385
- case 'state':
2386
- case 'province':
2387
- case 'provincename':
2388
- case 'st':
2389
- return 'id-at-stateOrProvinceName';
2390
- case 'id-at-localityname':
2391
- case 'localityname':
2392
- case 'l':
2393
- return 'id-at-localityName';
2394
- case 'id-emailaddress':
2395
- case 'emailaddress':
2396
- return 'pkcs-9-at-emailAddress';
2397
- case 'id-at-serialnumber':
2398
- case 'serialnumber':
2399
- return 'id-at-serialNumber';
2400
- case 'id-at-postalcode':
2401
- case 'postalcode':
2402
- return 'id-at-postalCode';
2403
- case 'id-at-streetaddress':
2404
- case 'streetaddress':
2405
- return 'id-at-streetAddress';
2406
- case 'id-at-name':
2407
- case 'name':
2408
- return 'id-at-name';
2409
- case 'id-at-givenname':
2410
- case 'givenname':
2411
- return 'id-at-givenName';
2412
- case 'id-at-surname':
2413
- case 'surname':
2414
- case 'sn':
2415
- return 'id-at-surname';
2416
- case 'id-at-initials':
2417
- case 'initials':
2418
- return 'id-at-initials';
2419
- case 'id-at-generationqualifier':
2420
- case 'generationqualifier':
2421
- return 'id-at-generationQualifier';
2422
- case 'id-at-organizationalunitname':
2423
- case 'organizationalunitname':
2424
- case 'ou':
2425
- return 'id-at-organizationalUnitName';
2426
- case 'id-at-pseudonym':
2427
- case 'pseudonym':
2428
- return 'id-at-pseudonym';
2429
- case 'id-at-title':
2430
- case 'title':
2431
- return 'id-at-title';
2432
- case 'id-at-description':
2433
- case 'description':
2434
- return 'id-at-description';
2435
- case 'id-at-role':
2436
- case 'role':
2437
- return 'id-at-role';
2438
- case 'id-at-uniqueidentifier':
2439
- case 'uniqueidentifier':
2440
- case 'x500uniqueidentifier':
2441
- return 'id-at-uniqueIdentifier';
2442
- case 'postaladdress':
2443
- case 'id-at-postaladdress':
2444
- return 'id-at-postalAddress';
2445
- default:
2446
- return false;
2447
- }
2448
- }
2449
-
2450
- /**
2451
- * Set a Distinguished Name property
2452
- *
2453
- * @param string $propName
2454
- * @param mixed $propValue
2455
- * @param string $type optional
2456
- * @access public
2457
- * @return bool
2458
- */
2459
- function setDNProp($propName, $propValue, $type = 'utf8String')
2460
- {
2461
- if (empty($this->dn)) {
2462
- $this->dn = array('rdnSequence' => array());
2463
- }
2464
-
2465
- if (($propName = $this->_translateDNProp($propName)) === false) {
2466
- return false;
2467
- }
2468
-
2469
- foreach ((array) $propValue as $v) {
2470
- if (!is_array($v) && isset($type)) {
2471
- $v = array($type => $v);
2472
- }
2473
- $this->dn['rdnSequence'][] = array(
2474
- array(
2475
- 'type' => $propName,
2476
- 'value'=> $v
2477
- )
2478
- );
2479
- }
2480
-
2481
- return true;
2482
- }
2483
-
2484
- /**
2485
- * Remove Distinguished Name properties
2486
- *
2487
- * @param string $propName
2488
- * @access public
2489
- */
2490
- function removeDNProp($propName)
2491
- {
2492
- if (empty($this->dn)) {
2493
- return;
2494
- }
2495
-
2496
- if (($propName = $this->_translateDNProp($propName)) === false) {
2497
- return;
2498
- }
2499
-
2500
- $dn = &$this->dn['rdnSequence'];
2501
- $size = count($dn);
2502
- for ($i = 0; $i < $size; $i++) {
2503
- if ($dn[$i][0]['type'] == $propName) {
2504
- unset($dn[$i]);
2505
- }
2506
- }
2507
-
2508
- $dn = array_values($dn);
2509
- }
2510
-
2511
- /**
2512
- * Get Distinguished Name properties
2513
- *
2514
- * @param string $propName
2515
- * @param array $dn optional
2516
- * @param bool $withType optional
2517
- * @return mixed
2518
- * @access public
2519
- */
2520
- function getDNProp($propName, $dn = null, $withType = false)
2521
- {
2522
- if (!isset($dn)) {
2523
- $dn = $this->dn;
2524
- }
2525
-
2526
- if (empty($dn)) {
2527
- return false;
2528
- }
2529
-
2530
- if (($propName = $this->_translateDNProp($propName)) === false) {
2531
- return false;
2532
- }
2533
-
2534
- $asn1 = new File_ASN1();
2535
- $asn1->loadOIDs($this->oids);
2536
- $filters = array();
2537
- $filters['value'] = array('type' => FILE_ASN1_TYPE_UTF8_STRING);
2538
- $asn1->loadFilters($filters);
2539
- $this->_mapOutDNs($dn, 'rdnSequence', $asn1);
2540
- $dn = $dn['rdnSequence'];
2541
- $result = array();
2542
- for ($i = 0; $i < count($dn); $i++) {
2543
- if ($dn[$i][0]['type'] == $propName) {
2544
- $v = $dn[$i][0]['value'];
2545
- if (!$withType) {
2546
- if (is_array($v)) {
2547
- foreach ($v as $type => $s) {
2548
- $type = array_search($type, $asn1->ANYmap, true);
2549
- if ($type !== false && isset($asn1->stringTypeSize[$type])) {
2550
- $s = $asn1->convert($s, $type);
2551
- if ($s !== false) {
2552
- $v = $s;
2553
- break;
2554
- }
2555
- }
2556
- }
2557
- if (is_array($v)) {
2558
- $v = array_pop($v); // Always strip data type.
2559
- }
2560
- } elseif (is_object($v) && strtolower(get_class($v)) == 'file_asn1_element') {
2561
- $map = $this->_getMapping($propName);
2562
- if (!is_bool($map)) {
2563
- $decoded = $asn1->decodeBER($v);
2564
- $v = $asn1->asn1map($decoded[0], $map);
2565
- }
2566
- }
2567
- }
2568
- $result[] = $v;
2569
- }
2570
- }
2571
-
2572
- return $result;
2573
- }
2574
-
2575
- /**
2576
- * Set a Distinguished Name
2577
- *
2578
- * @param mixed $dn
2579
- * @param bool $merge optional
2580
- * @param string $type optional
2581
- * @access public
2582
- * @return bool
2583
- */
2584
- function setDN($dn, $merge = false, $type = 'utf8String')
2585
- {
2586
- if (!$merge) {
2587
- $this->dn = null;
2588
- }
2589
-
2590
- if (is_array($dn)) {
2591
- if (isset($dn['rdnSequence'])) {
2592
- $this->dn = $dn; // No merge here.
2593
- return true;
2594
- }
2595
-
2596
- // handles stuff generated by openssl_x509_parse()
2597
- foreach ($dn as $prop => $value) {
2598
- if (!$this->setDNProp($prop, $value, $type)) {
2599
- return false;
2600
- }
2601
- }
2602
- return true;
2603
- }
2604
-
2605
- // handles everything else
2606
- $results = preg_split('#((?:^|, *|/)(?:C=|O=|OU=|CN=|L=|ST=|SN=|postalCode=|streetAddress=|emailAddress=|serialNumber=|organizationalUnitName=|title=|description=|role=|x500UniqueIdentifier=|postalAddress=))#', $dn, -1, PREG_SPLIT_DELIM_CAPTURE);
2607
- for ($i = 1; $i < count($results); $i+=2) {
2608
- $prop = trim($results[$i], ', =/');
2609
- $value = $results[$i + 1];
2610
- if (!$this->setDNProp($prop, $value, $type)) {
2611
- return false;
2612
- }
2613
- }
2614
-
2615
- return true;
2616
- }
2617
-
2618
- /**
2619
- * Get the Distinguished Name for a certificates subject
2620
- *
2621
- * @param mixed $format optional
2622
- * @param array $dn optional
2623
- * @access public
2624
- * @return bool
2625
- */
2626
- function getDN($format = FILE_X509_DN_ARRAY, $dn = null)
2627
- {
2628
- if (!isset($dn)) {
2629
- $dn = isset($this->currentCert['tbsCertList']) ? $this->currentCert['tbsCertList']['issuer'] : $this->dn;
2630
- }
2631
-
2632
- switch ((int) $format) {
2633
- case FILE_X509_DN_ARRAY:
2634
- return $dn;
2635
- case FILE_X509_DN_ASN1:
2636
- $asn1 = new File_ASN1();
2637
- $asn1->loadOIDs($this->oids);
2638
- $filters = array();
2639
- $filters['rdnSequence']['value'] = array('type' => FILE_ASN1_TYPE_UTF8_STRING);
2640
- $asn1->loadFilters($filters);
2641
- $this->_mapOutDNs($dn, 'rdnSequence', $asn1);
2642
- return $asn1->encodeDER($dn, $this->Name);
2643
- case FILE_X509_DN_CANON:
2644
- // No SEQUENCE around RDNs and all string values normalized as
2645
- // trimmed lowercase UTF-8 with all spacing as one blank.
2646
- // constructed RDNs will not be canonicalized
2647
- $asn1 = new File_ASN1();
2648
- $asn1->loadOIDs($this->oids);
2649
- $filters = array();
2650
- $filters['value'] = array('type' => FILE_ASN1_TYPE_UTF8_STRING);
2651
- $asn1->loadFilters($filters);
2652
- $result = '';
2653
- $this->_mapOutDNs($dn, 'rdnSequence', $asn1);
2654
- foreach ($dn['rdnSequence'] as $rdn) {
2655
- foreach ($rdn as $i => $attr) {
2656
- $attr = &$rdn[$i];
2657
- if (is_array($attr['value'])) {
2658
- foreach ($attr['value'] as $type => $v) {
2659
- $type = array_search($type, $asn1->ANYmap, true);
2660
- if ($type !== false && isset($asn1->stringTypeSize[$type])) {
2661
- $v = $asn1->convert($v, $type);
2662
- if ($v !== false) {
2663
- $v = preg_replace('/\s+/', ' ', $v);
2664
- $attr['value'] = strtolower(trim($v));
2665
- break;
2666
- }
2667
- }
2668
- }
2669
- }
2670
- }
2671
- $result .= $asn1->encodeDER($rdn, $this->RelativeDistinguishedName);
2672
- }
2673
- return $result;
2674
- case FILE_X509_DN_HASH:
2675
- $dn = $this->getDN(FILE_X509_DN_CANON, $dn);
2676
- if (!class_exists('Crypt_Hash')) {
2677
- include_once 'Crypt/Hash.php';
2678
- }
2679
- $hash = new Crypt_Hash('sha1');
2680
- $hash = $hash->hash($dn);
2681
- extract(unpack('Vhash', $hash));
2682
- return strtolower(bin2hex(pack('N', $hash)));
2683
- }
2684
-
2685
- // Default is to return a string.
2686
- $start = true;
2687
- $output = '';
2688
- $result = array();
2689
- $asn1 = new File_ASN1();
2690
- $asn1->loadOIDs($this->oids);
2691
- $filters = array();
2692
- $filters['rdnSequence']['value'] = array('type' => FILE_ASN1_TYPE_UTF8_STRING);
2693
- $asn1->loadFilters($filters);
2694
- $this->_mapOutDNs($dn, 'rdnSequence', $asn1);
2695
- foreach ($dn['rdnSequence'] as $field) {
2696
- $prop = $field[0]['type'];
2697
- $value = $field[0]['value'];
2698
-
2699
- $delim = ', ';
2700
- switch ($prop) {
2701
- case 'id-at-countryName':
2702
- $desc = 'C';
2703
- break;
2704
- case 'id-at-stateOrProvinceName':
2705
- $desc = 'ST';
2706
- break;
2707
- case 'id-at-organizationName':
2708
- $desc = 'O';
2709
- break;
2710
- case 'id-at-organizationalUnitName':
2711
- $desc = 'OU';
2712
- break;
2713
- case 'id-at-commonName':
2714
- $desc = 'CN';
2715
- break;
2716
- case 'id-at-localityName':
2717
- $desc = 'L';
2718
- break;
2719
- case 'id-at-surname':
2720
- $desc = 'SN';
2721
- break;
2722
- case 'id-at-uniqueIdentifier':
2723
- $delim = '/';
2724
- $desc = 'x500UniqueIdentifier';
2725
- break;
2726
- case 'id-at-postalAddress':
2727
- $delim = '/';
2728
- $desc = 'postalAddress';
2729
- break;
2730
- default:
2731
- $delim = '/';
2732
- $desc = preg_replace('#.+-([^-]+)$#', '$1', $prop);
2733
- }
2734
-
2735
- if (!$start) {
2736
- $output.= $delim;
2737
- }
2738
- if (is_array($value)) {
2739
- foreach ($value as $type => $v) {
2740
- $type = array_search($type, $asn1->ANYmap, true);
2741
- if ($type !== false && isset($asn1->stringTypeSize[$type])) {
2742
- $v = $asn1->convert($v, $type);
2743
- if ($v !== false) {
2744
- $value = $v;
2745
- break;
2746
- }
2747
- }
2748
- }
2749
- if (is_array($value)) {
2750
- $value = array_pop($value); // Always strip data type.
2751
- }
2752
- } elseif (is_object($value) && strtolower(get_class($value)) == 'file_asn1_element') {
2753
- $callback = create_function('$x', 'return "\x" . bin2hex($x[0]);');
2754
- $value = strtoupper(preg_replace_callback('#[^\x20-\x7E]#', $callback, $value->element));
2755
- }
2756
- $output.= $desc . '=' . $value;
2757
- $result[$desc] = isset($result[$desc]) ?
2758
- array_merge((array) $dn[$prop], array($value)) :
2759
- $value;
2760
- $start = false;
2761
- }
2762
-
2763
- return $format == FILE_X509_DN_OPENSSL ? $result : $output;
2764
- }
2765
-
2766
- /**
2767
- * Get the Distinguished Name for a certificate/crl issuer
2768
- *
2769
- * @param int $format optional
2770
- * @access public
2771
- * @return mixed
2772
- */
2773
- function getIssuerDN($format = FILE_X509_DN_ARRAY)
2774
- {
2775
- switch (true) {
2776
- case !isset($this->currentCert) || !is_array($this->currentCert):
2777
- break;
2778
- case isset($this->currentCert['tbsCertificate']):
2779
- return $this->getDN($format, $this->currentCert['tbsCertificate']['issuer']);
2780
- case isset($this->currentCert['tbsCertList']):
2781
- return $this->getDN($format, $this->currentCert['tbsCertList']['issuer']);
2782
- }
2783
-
2784
- return false;
2785
- }
2786
-
2787
- /**
2788
- * Get the Distinguished Name for a certificate/csr subject
2789
- * Alias of getDN()
2790
- *
2791
- * @param int $format optional
2792
- * @access public
2793
- * @return mixed
2794
- */
2795
- function getSubjectDN($format = FILE_X509_DN_ARRAY)
2796
- {
2797
- switch (true) {
2798
- case !empty($this->dn):
2799
- return $this->getDN($format);
2800
- case !isset($this->currentCert) || !is_array($this->currentCert):
2801
- break;
2802
- case isset($this->currentCert['tbsCertificate']):
2803
- return $this->getDN($format, $this->currentCert['tbsCertificate']['subject']);
2804
- case isset($this->currentCert['certificationRequestInfo']):
2805
- return $this->getDN($format, $this->currentCert['certificationRequestInfo']['subject']);
2806
- }
2807
-
2808
- return false;
2809
- }
2810
-
2811
- /**
2812
- * Get an individual Distinguished Name property for a certificate/crl issuer
2813
- *
2814
- * @param string $propName
2815
- * @param bool $withType optional
2816
- * @access public
2817
- * @return mixed
2818
- */
2819
- function getIssuerDNProp($propName, $withType = false)
2820
- {
2821
- switch (true) {
2822
- case !isset($this->currentCert) || !is_array($this->currentCert):
2823
- break;
2824
- case isset($this->currentCert['tbsCertificate']):
2825
- return $this->getDNProp($propName, $this->currentCert['tbsCertificate']['issuer'], $withType);
2826
- case isset($this->currentCert['tbsCertList']):
2827
- return $this->getDNProp($propName, $this->currentCert['tbsCertList']['issuer'], $withType);
2828
- }
2829
-
2830
- return false;
2831
- }
2832
-
2833
- /**
2834
- * Get an individual Distinguished Name property for a certificate/csr subject
2835
- *
2836
- * @param string $propName
2837
- * @param bool $withType optional
2838
- * @access public
2839
- * @return mixed
2840
- */
2841
- function getSubjectDNProp($propName, $withType = false)
2842
- {
2843
- switch (true) {
2844
- case !empty($this->dn):
2845
- return $this->getDNProp($propName, null, $withType);
2846
- case !isset($this->currentCert) || !is_array($this->currentCert):
2847
- break;
2848
- case isset($this->currentCert['tbsCertificate']):
2849
- return $this->getDNProp($propName, $this->currentCert['tbsCertificate']['subject'], $withType);
2850
- case isset($this->currentCert['certificationRequestInfo']):
2851
- return $this->getDNProp($propName, $this->currentCert['certificationRequestInfo']['subject'], $withType);
2852
- }
2853
-
2854
- return false;
2855
- }
2856
-
2857
- /**
2858
- * Get the certificate chain for the current cert
2859
- *
2860
- * @access public
2861
- * @return mixed
2862
- */
2863
- function getChain()
2864
- {
2865
- $chain = array($this->currentCert);
2866
-
2867
- if (!is_array($this->currentCert) || !isset($this->currentCert['tbsCertificate'])) {
2868
- return false;
2869
- }
2870
- if (empty($this->CAs)) {
2871
- return $chain;
2872
- }
2873
- while (true) {
2874
- $currentCert = $chain[count($chain) - 1];
2875
- for ($i = 0; $i < count($this->CAs); $i++) {
2876
- $ca = $this->CAs[$i];
2877
- if ($currentCert['tbsCertificate']['issuer'] === $ca['tbsCertificate']['subject']) {
2878
- $authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier', $currentCert);
2879
- $subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier', $ca);
2880
- switch (true) {
2881
- case !is_array($authorityKey):
2882
- case is_array($authorityKey) && isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
2883
- if ($currentCert === $ca) {
2884
- break 3;
2885
- }
2886
- $chain[] = $ca;
2887
- break 2;
2888
- }
2889
- }
2890
- }
2891
- if ($i == count($this->CAs)) {
2892
- break;
2893
- }
2894
- }
2895
- foreach ($chain as $key => $value) {
2896
- $chain[$key] = new File_X509();
2897
- $chain[$key]->loadX509($value);
2898
- }
2899
- return $chain;
2900
- }
2901
-
2902
- /**
2903
- * Set public key
2904
- *
2905
- * Key needs to be a Crypt_RSA object
2906
- *
2907
- * @param object $key
2908
- * @access public
2909
- * @return bool
2910
- */
2911
- function setPublicKey($key)
2912
- {
2913
- $key->setPublicKey();
2914
- $this->publicKey = $key;
2915
- }
2916
-
2917
- /**
2918
- * Set private key
2919
- *
2920
- * Key needs to be a Crypt_RSA object
2921
- *
2922
- * @param object $key
2923
- * @access public
2924
- */
2925
- function setPrivateKey($key)
2926
- {
2927
- $this->privateKey = $key;
2928
- }
2929
-
2930
- /**
2931
- * Set challenge
2932
- *
2933
- * Used for SPKAC CSR's
2934
- *
2935
- * @param string $challenge
2936
- * @access public
2937
- */
2938
- function setChallenge($challenge)
2939
- {
2940
- $this->challenge = $challenge;
2941
- }
2942
-
2943
- /**
2944
- * Gets the public key
2945
- *
2946
- * Returns a Crypt_RSA object or a false.
2947
- *
2948
- * @access public
2949
- * @return mixed
2950
- */
2951
- function getPublicKey()
2952
- {
2953
- if (isset($this->publicKey)) {
2954
- return $this->publicKey;
2955
- }
2956
-
2957
- if (isset($this->currentCert) && is_array($this->currentCert)) {
2958
- foreach (array('tbsCertificate/subjectPublicKeyInfo', 'certificationRequestInfo/subjectPKInfo') as $path) {
2959
- $keyinfo = $this->_subArray($this->currentCert, $path);
2960
- if (!empty($keyinfo)) {
2961
- break;
2962
- }
2963
- }
2964
- }
2965
- if (empty($keyinfo)) {
2966
- return false;
2967
- }
2968
-
2969
- $key = $keyinfo['subjectPublicKey'];
2970
-
2971
- switch ($keyinfo['algorithm']['algorithm']) {
2972
- case 'rsaEncryption':
2973
- if (!class_exists('Crypt_RSA')) {
2974
- include_once 'Crypt/RSA.php';
2975
- }
2976
- $publicKey = new Crypt_RSA();
2977
- $publicKey->loadKey($key);
2978
- $publicKey->setPublicKey();
2979
- break;
2980
- default:
2981
- return false;
2982
- }
2983
-
2984
- return $publicKey;
2985
- }
2986
-
2987
- /**
2988
- * Load a Certificate Signing Request
2989
- *
2990
- * @param string $csr
2991
- * @access public
2992
- * @return mixed
2993
- */
2994
- function loadCSR($csr, $mode = FILE_X509_FORMAT_AUTO_DETECT)
2995
- {
2996
- if (is_array($csr) && isset($csr['certificationRequestInfo'])) {
2997
- unset($this->currentCert);
2998
- unset($this->currentKeyIdentifier);
2999
- unset($this->signatureSubject);
3000
- $this->dn = $csr['certificationRequestInfo']['subject'];
3001
- if (!isset($this->dn)) {
3002
- return false;
3003
- }
3004
-
3005
- $this->currentCert = $csr;
3006
- return $csr;
3007
- }
3008
-
3009
- // see http://tools.ietf.org/html/rfc2986
3010
-
3011
- $asn1 = new File_ASN1();
3012
-
3013
- if ($mode != FILE_X509_FORMAT_DER) {
3014
- $newcsr = $this->_extractBER($csr);
3015
- if ($mode == FILE_X509_FORMAT_PEM && $csr == $newcsr) {
3016
- return false;
3017
- }
3018
- $csr = $newcsr;
3019
- }
3020
- $orig = $csr;
3021
-
3022
- if ($csr === false) {
3023
- $this->currentCert = false;
3024
- return false;
3025
- }
3026
-
3027
- $asn1->loadOIDs($this->oids);
3028
- $decoded = $asn1->decodeBER($csr);
3029
-
3030
- if (empty($decoded)) {
3031
- $this->currentCert = false;
3032
- return false;
3033
- }
3034
-
3035
- $csr = $asn1->asn1map($decoded[0], $this->CertificationRequest);
3036
- if (!isset($csr) || $csr === false) {
3037
- $this->currentCert = false;
3038
- return false;
3039
- }
3040
-
3041
- $this->_mapInAttributes($csr, 'certificationRequestInfo/attributes', $asn1);
3042
- $this->_mapInDNs($csr, 'certificationRequestInfo/subject/rdnSequence', $asn1);
3043
-
3044
- $this->dn = $csr['certificationRequestInfo']['subject'];
3045
-
3046
- $this->signatureSubject = substr($orig, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']);
3047
-
3048
- $algorithm = &$csr['certificationRequestInfo']['subjectPKInfo']['algorithm']['algorithm'];
3049
- $key = &$csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'];
3050
- $key = $this->_reformatKey($algorithm, $key);
3051
-
3052
- switch ($algorithm) {
3053
- case 'rsaEncryption':
3054
- if (!class_exists('Crypt_RSA')) {
3055
- include_once 'Crypt/RSA.php';
3056
- }
3057
- $this->publicKey = new Crypt_RSA();
3058
- $this->publicKey->loadKey($key);
3059
- $this->publicKey->setPublicKey();
3060
- break;
3061
- default:
3062
- $this->publicKey = null;
3063
- }
3064
-
3065
- $this->currentKeyIdentifier = null;
3066
- $this->currentCert = $csr;
3067
-
3068
- return $csr;
3069
- }
3070
-
3071
- /**
3072
- * Save CSR request
3073
- *
3074
- * @param array $csr
3075
- * @param int $format optional
3076
- * @access public
3077
- * @return string
3078
- */
3079
- function saveCSR($csr, $format = FILE_X509_FORMAT_PEM)
3080
- {
3081
- if (!is_array($csr) || !isset($csr['certificationRequestInfo'])) {
3082
- return false;
3083
- }
3084
-
3085
- switch (true) {
3086
- case !($algorithm = $this->_subArray($csr, 'certificationRequestInfo/subjectPKInfo/algorithm/algorithm')):
3087
- case is_object($csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey']):
3088
- break;
3089
- default:
3090
- switch ($algorithm) {
3091
- case 'rsaEncryption':
3092
- $csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey']
3093
- = base64_encode("\0" . base64_decode(preg_replace('#-.+-|[\r\n]#', '', $csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'])));
3094
- $csr['certificationRequestInfo']['subjectPKInfo']['algorithm']['parameters'] = null;
3095
- $csr['signatureAlgorithm']['parameters'] = null;
3096
- $csr['certificationRequestInfo']['signature']['parameters'] = null;
3097
- }
3098
- }
3099
-
3100
- $asn1 = new File_ASN1();
3101
-
3102
- $asn1->loadOIDs($this->oids);
3103
-
3104
- $filters = array();
3105
- $filters['certificationRequestInfo']['subject']['rdnSequence']['value']
3106
- = array('type' => FILE_ASN1_TYPE_UTF8_STRING);
3107
-
3108
- $asn1->loadFilters($filters);
3109
-
3110
- $this->_mapOutDNs($csr, 'certificationRequestInfo/subject/rdnSequence', $asn1);
3111
- $this->_mapOutAttributes($csr, 'certificationRequestInfo/attributes', $asn1);
3112
- $csr = $asn1->encodeDER($csr, $this->CertificationRequest);
3113
-
3114
- switch ($format) {
3115
- case FILE_X509_FORMAT_DER:
3116
- return $csr;
3117
- // case FILE_X509_FORMAT_PEM:
3118
- default:
3119
- return "-----BEGIN CERTIFICATE REQUEST-----\r\n" . chunk_split(base64_encode($csr), 64) . '-----END CERTIFICATE REQUEST-----';
3120
- }
3121
- }
3122
-
3123
- /**
3124
- * Load a SPKAC CSR
3125
- *
3126
- * SPKAC's are produced by the HTML5 keygen element:
3127
- *
3128
- * https://developer.mozilla.org/en-US/docs/HTML/Element/keygen
3129
- *
3130
- * @param string $csr
3131
- * @access public
3132
- * @return mixed
3133
- */
3134
- function loadSPKAC($spkac)
3135
- {
3136
- if (is_array($spkac) && isset($spkac['publicKeyAndChallenge'])) {
3137
- unset($this->currentCert);
3138
- unset($this->currentKeyIdentifier);
3139
- unset($this->signatureSubject);
3140
- $this->currentCert = $spkac;
3141
- return $spkac;
3142
- }
3143
-
3144
- // see http://www.w3.org/html/wg/drafts/html/master/forms.html#signedpublickeyandchallenge
3145
-
3146
- $asn1 = new File_ASN1();
3147
-
3148
- // OpenSSL produces SPKAC's that are preceded by the string SPKAC=
3149
- $temp = preg_replace('#(?:SPKAC=)|[ \r\n\\\]#', '', $spkac);
3150
- $temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? base64_decode($temp) : false;
3151
- if ($temp != false) {
3152
- $spkac = $temp;
3153
- }
3154
- $orig = $spkac;
3155
-
3156
- if ($spkac === false) {
3157
- $this->currentCert = false;
3158
- return false;
3159
- }
3160
-
3161
- $asn1->loadOIDs($this->oids);
3162
- $decoded = $asn1->decodeBER($spkac);
3163
-
3164
- if (empty($decoded)) {
3165
- $this->currentCert = false;
3166
- return false;
3167
- }
3168
-
3169
- $spkac = $asn1->asn1map($decoded[0], $this->SignedPublicKeyAndChallenge);
3170
-
3171
- if (!isset($spkac) || $spkac === false) {
3172
- $this->currentCert = false;
3173
- return false;
3174
- }
3175
-
3176
- $this->signatureSubject = substr($orig, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']);
3177
-
3178
- $algorithm = &$spkac['publicKeyAndChallenge']['spki']['algorithm']['algorithm'];
3179
- $key = &$spkac['publicKeyAndChallenge']['spki']['subjectPublicKey'];
3180
- $key = $this->_reformatKey($algorithm, $key);
3181
-
3182
- switch ($algorithm) {
3183
- case 'rsaEncryption':
3184
- if (!class_exists('Crypt_RSA')) {
3185
- include_once 'Crypt/RSA.php';
3186
- }
3187
- $this->publicKey = new Crypt_RSA();
3188
- $this->publicKey->loadKey($key);
3189
- $this->publicKey->setPublicKey();
3190
- break;
3191
- default:
3192
- $this->publicKey = null;
3193
- }
3194
-
3195
- $this->currentKeyIdentifier = null;
3196
- $this->currentCert = $spkac;
3197
-
3198
- return $spkac;
3199
- }
3200
-
3201
- /**
3202
- * Save a SPKAC CSR request
3203
- *
3204
- * @param array $csr
3205
- * @param int $format optional
3206
- * @access public
3207
- * @return string
3208
- */
3209
- function saveSPKAC($spkac, $format = FILE_X509_FORMAT_PEM)
3210
- {
3211
- if (!is_array($spkac) || !isset($spkac['publicKeyAndChallenge'])) {
3212
- return false;
3213
- }
3214
-
3215
- $algorithm = $this->_subArray($spkac, 'publicKeyAndChallenge/spki/algorithm/algorithm');
3216
- switch (true) {
3217
- case !$algorithm:
3218
- case is_object($spkac['publicKeyAndChallenge']['spki']['subjectPublicKey']):
3219
- break;
3220
- default:
3221
- switch ($algorithm) {
3222
- case 'rsaEncryption':
3223
- $spkac['publicKeyAndChallenge']['spki']['subjectPublicKey']
3224
- = base64_encode("\0" . base64_decode(preg_replace('#-.+-|[\r\n]#', '', $spkac['publicKeyAndChallenge']['spki']['subjectPublicKey'])));
3225
- }
3226
- }
3227
-
3228
- $asn1 = new File_ASN1();
3229
-
3230
- $asn1->loadOIDs($this->oids);
3231
- $spkac = $asn1->encodeDER($spkac, $this->SignedPublicKeyAndChallenge);
3232
-
3233
- switch ($format) {
3234
- case FILE_X509_FORMAT_DER:
3235
- return $spkac;
3236
- // case FILE_X509_FORMAT_PEM:
3237
- default:
3238
- // OpenSSL's implementation of SPKAC requires the SPKAC be preceded by SPKAC= and since there are pretty much
3239
- // no other SPKAC decoders phpseclib will use that same format
3240
- return 'SPKAC=' . base64_encode($spkac);
3241
- }
3242
- }
3243
-
3244
- /**
3245
- * Load a Certificate Revocation List
3246
- *
3247
- * @param string $crl
3248
- * @access public
3249
- * @return mixed
3250
- */
3251
- function loadCRL($crl, $mode = FILE_X509_FORMAT_AUTO_DETECT)
3252
- {
3253
- if (is_array($crl) && isset($crl['tbsCertList'])) {
3254
- $this->currentCert = $crl;
3255
- unset($this->signatureSubject);
3256
- return $crl;
3257
- }
3258
-
3259
- $asn1 = new File_ASN1();
3260
-
3261
- if ($mode != FILE_X509_FORMAT_DER) {
3262
- $newcrl = $this->_extractBER($crl);
3263
- if ($mode == FILE_X509_FORMAT_PEM && $crl == $newcrl) {
3264
- return false;
3265
- }
3266
- $crl = $newcrl;
3267
- }
3268
- $orig = $crl;
3269
-
3270
- if ($crl === false) {
3271
- $this->currentCert = false;
3272
- return false;
3273
- }
3274
-
3275
- $asn1->loadOIDs($this->oids);
3276
- $decoded = $asn1->decodeBER($crl);
3277
-
3278
- if (empty($decoded)) {
3279
- $this->currentCert = false;
3280
- return false;
3281
- }
3282
-
3283
- $crl = $asn1->asn1map($decoded[0], $this->CertificateList);
3284
- if (!isset($crl) || $crl === false) {
3285
- $this->currentCert = false;
3286
- return false;
3287
- }
3288
-
3289
- $this->signatureSubject = substr($orig, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']);
3290
-
3291
- $this->_mapInDNs($crl, 'tbsCertList/issuer/rdnSequence', $asn1);
3292
- if ($this->_isSubArrayValid($crl, 'tbsCertList/crlExtensions')) {
3293
- $this->_mapInExtensions($crl, 'tbsCertList/crlExtensions', $asn1);
3294
- }
3295
- if ($this->_isSubArrayValid($crl, 'tbsCertList/revokedCertificates')) {
3296
- $rclist_ref = &$this->_subArrayUnchecked($crl, 'tbsCertList/revokedCertificates');
3297
- if ($rclist_ref) {
3298
- $rclist = $crl['tbsCertList']['revokedCertificates'];
3299
- foreach ($rclist as $i => $extension) {
3300
- if ($this->_isSubArrayValid($rclist, "$i/crlEntryExtensions", $asn1)) {
3301
- $this->_mapInExtensions($rclist_ref, "$i/crlEntryExtensions", $asn1);
3302
- }
3303
- }
3304
- }
3305
- }
3306
-
3307
- $this->currentKeyIdentifier = null;
3308
- $this->currentCert = $crl;
3309
-
3310
- return $crl;
3311
- }
3312
-
3313
- /**
3314
- * Save Certificate Revocation List.
3315
- *
3316
- * @param array $crl
3317
- * @param int $format optional
3318
- * @access public
3319
- * @return string
3320
- */
3321
- function saveCRL($crl, $format = FILE_X509_FORMAT_PEM)
3322
- {
3323
- if (!is_array($crl) || !isset($crl['tbsCertList'])) {
3324
- return false;
3325
- }
3326
-
3327
- $asn1 = new File_ASN1();
3328
-
3329
- $asn1->loadOIDs($this->oids);
3330
-
3331
- $filters = array();
3332
- $filters['tbsCertList']['issuer']['rdnSequence']['value']
3333
- = array('type' => FILE_ASN1_TYPE_UTF8_STRING);
3334
- $filters['tbsCertList']['signature']['parameters']
3335
- = array('type' => FILE_ASN1_TYPE_UTF8_STRING);
3336
- $filters['signatureAlgorithm']['parameters']
3337
- = array('type' => FILE_ASN1_TYPE_UTF8_STRING);
3338
-
3339
- if (empty($crl['tbsCertList']['signature']['parameters'])) {
3340
- $filters['tbsCertList']['signature']['parameters']
3341
- = array('type' => FILE_ASN1_TYPE_NULL);
3342
- }
3343
-
3344
- if (empty($crl['signatureAlgorithm']['parameters'])) {
3345
- $filters['signatureAlgorithm']['parameters']
3346
- = array('type' => FILE_ASN1_TYPE_NULL);
3347
- }
3348
-
3349
- $asn1->loadFilters($filters);
3350
-
3351
- $this->_mapOutDNs($crl, 'tbsCertList/issuer/rdnSequence', $asn1);
3352
- $this->_mapOutExtensions($crl, 'tbsCertList/crlExtensions', $asn1);
3353
- $rclist = &$this->_subArray($crl, 'tbsCertList/revokedCertificates');
3354
- if (is_array($rclist)) {
3355
- foreach ($rclist as $i => $extension) {
3356
- $this->_mapOutExtensions($rclist, "$i/crlEntryExtensions", $asn1);
3357
- }
3358
- }
3359
-
3360
- $crl = $asn1->encodeDER($crl, $this->CertificateList);
3361
-
3362
- switch ($format) {
3363
- case FILE_X509_FORMAT_DER:
3364
- return $crl;
3365
- // case FILE_X509_FORMAT_PEM:
3366
- default:
3367
- return "-----BEGIN X509 CRL-----\r\n" . chunk_split(base64_encode($crl), 64) . '-----END X509 CRL-----';
3368
- }
3369
- }
3370
-
3371
- /**
3372
- * Helper function to build a time field according to RFC 3280 section
3373
- * - 4.1.2.5 Validity
3374
- * - 5.1.2.4 This Update
3375
- * - 5.1.2.5 Next Update
3376
- * - 5.1.2.6 Revoked Certificates
3377
- * by choosing utcTime iff year of date given is before 2050 and generalTime else.
3378
- *
3379
- * @param string $date in format date('D, d M Y H:i:s O')
3380
- * @access private
3381
- * @return array
3382
- */
3383
- function _timeField($date)
3384
- {
3385
- $year = @gmdate("Y", @strtotime($date)); // the same way ASN1.php parses this
3386
- if ($year < 2050) {
3387
- return array('utcTime' => $date);
3388
- } else {
3389
- return array('generalTime' => $date);
3390
- }
3391
- }
3392
-
3393
- /**
3394
- * Sign an X.509 certificate
3395
- *
3396
- * $issuer's private key needs to be loaded.
3397
- * $subject can be either an existing X.509 cert (if you want to resign it),
3398
- * a CSR or something with the DN and public key explicitly set.
3399
- *
3400
- * @param File_X509 $issuer
3401
- * @param File_X509 $subject
3402
- * @param string $signatureAlgorithm optional
3403
- * @access public
3404
- * @return mixed
3405
- */
3406
- function sign($issuer, $subject, $signatureAlgorithm = 'sha1WithRSAEncryption')
3407
- {
3408
- if (!is_object($issuer->privateKey) || empty($issuer->dn)) {
3409
- return false;
3410
- }
3411
-
3412
- if (isset($subject->publicKey) && !($subjectPublicKey = $subject->_formatSubjectPublicKey())) {
3413
- return false;
3414
- }
3415
-
3416
- $currentCert = isset($this->currentCert) ? $this->currentCert : null;
3417
- $signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject: null;
3418
-
3419
- if (isset($subject->currentCert) && is_array($subject->currentCert) && isset($subject->currentCert['tbsCertificate'])) {
3420
- $this->currentCert = $subject->currentCert;
3421
- $this->currentCert['tbsCertificate']['signature']['algorithm'] = $signatureAlgorithm;
3422
- $this->currentCert['signatureAlgorithm']['algorithm'] = $signatureAlgorithm;
3423
-
3424
- if (!empty($this->startDate)) {
3425
- $this->currentCert['tbsCertificate']['validity']['notBefore'] = $this->_timeField($this->startDate);
3426
- }
3427
- if (!empty($this->endDate)) {
3428
- $this->currentCert['tbsCertificate']['validity']['notAfter'] = $this->_timeField($this->endDate);
3429
- }
3430
- if (!empty($this->serialNumber)) {
3431
- $this->currentCert['tbsCertificate']['serialNumber'] = $this->serialNumber;
3432
- }
3433
- if (!empty($subject->dn)) {
3434
- $this->currentCert['tbsCertificate']['subject'] = $subject->dn;
3435
- }
3436
- if (!empty($subject->publicKey)) {
3437
- $this->currentCert['tbsCertificate']['subjectPublicKeyInfo'] = $subjectPublicKey;
3438
- }
3439
- $this->removeExtension('id-ce-authorityKeyIdentifier');
3440
- if (isset($subject->domains)) {
3441
- $this->removeExtension('id-ce-subjectAltName');
3442
- }
3443
- } elseif (isset($subject->currentCert) && is_array($subject->currentCert) && isset($subject->currentCert['tbsCertList'])) {
3444
- return false;
3445
- } else {
3446
- if (!isset($subject->publicKey)) {
3447
- return false;
3448
- }
3449
-
3450
- $startDate = !empty($this->startDate) ? $this->startDate : @date('D, d M Y H:i:s O');
3451
- $endDate = !empty($this->endDate) ? $this->endDate : @date('D, d M Y H:i:s O', strtotime('+1 year'));
3452
- if (!empty($this->serialNumber)) {
3453
- $serialNumber = $this->serialNumber;
3454
- } else {
3455
- if (!function_exists('crypt_random_string')) {
3456
- include_once 'Crypt/Random.php';
3457
- }
3458
- /* "The serial number MUST be a positive integer"
3459
- "Conforming CAs MUST NOT use serialNumber values longer than 20 octets."
3460
- -- https://tools.ietf.org/html/rfc5280#section-4.1.2.2
3461
-
3462
- for the integer to be positive the leading bit needs to be 0 hence the
3463
- application of a bitmap
3464
- */
3465
- $serialNumber = new Math_BigInteger(crypt_random_string(20) & ("\x7F" . str_repeat("\xFF", 19)), 256);
3466
- }
3467
-
3468
- $this->currentCert = array(
3469
- 'tbsCertificate' =>
3470
- array(
3471
- 'version' => 'v3',
3472
- 'serialNumber' => $serialNumber, // $this->setserialNumber()
3473
- 'signature' => array('algorithm' => $signatureAlgorithm),
3474
- 'issuer' => false, // this is going to be overwritten later
3475
- 'validity' => array(
3476
- 'notBefore' => $this->_timeField($startDate), // $this->setStartDate()
3477
- 'notAfter' => $this->_timeField($endDate) // $this->setEndDate()
3478
- ),
3479
- 'subject' => $subject->dn,
3480
- 'subjectPublicKeyInfo' => $subjectPublicKey
3481
- ),
3482
- 'signatureAlgorithm' => array('algorithm' => $signatureAlgorithm),
3483
- 'signature' => false // this is going to be overwritten later
3484
- );
3485
-
3486
- // Copy extensions from CSR.
3487
- $csrexts = $subject->getAttribute('pkcs-9-at-extensionRequest', 0);
3488
-
3489
- if (!empty($csrexts)) {
3490
- $this->currentCert['tbsCertificate']['extensions'] = $csrexts;
3491
- }
3492
- }
3493
-
3494
- $this->currentCert['tbsCertificate']['issuer'] = $issuer->dn;
3495
-
3496
- if (isset($issuer->currentKeyIdentifier)) {
3497
- $this->setExtension('id-ce-authorityKeyIdentifier', array(
3498
- //'authorityCertIssuer' => array(
3499
- // array(
3500
- // 'directoryName' => $issuer->dn
3501
- // )
3502
- //),
3503
- 'keyIdentifier' => $issuer->currentKeyIdentifier
3504
- ));
3505
- //$extensions = &$this->currentCert['tbsCertificate']['extensions'];
3506
- //if (isset($issuer->serialNumber)) {
3507
- // $extensions[count($extensions) - 1]['authorityCertSerialNumber'] = $issuer->serialNumber;
3508
- //}
3509
- //unset($extensions);
3510
- }
3511
-
3512
- if (isset($subject->currentKeyIdentifier)) {
3513
- $this->setExtension('id-ce-subjectKeyIdentifier', $subject->currentKeyIdentifier);
3514
- }
3515
-
3516
- $altName = array();
3517
-
3518
- if (isset($subject->domains) && count($subject->domains) > 1) {
3519
- $altName = array_map(array('File_X509', '_dnsName'), $subject->domains);
3520
- }
3521
-
3522
- if (isset($subject->ipAddresses) && count($subject->ipAddresses)) {
3523
- // should an IP address appear as the CN if no domain name is specified? idk
3524
- //$ips = count($subject->domains) ? $subject->ipAddresses : array_slice($subject->ipAddresses, 1);
3525
- $ipAddresses = array();
3526
- foreach ($subject->ipAddresses as $ipAddress) {
3527
- $encoded = $subject->_ipAddress($ipAddress);
3528
- if ($encoded !== false) {
3529
- $ipAddresses[] = $encoded;
3530
- }
3531
- }
3532
- if (count($ipAddresses)) {
3533
- $altName = array_merge($altName, $ipAddresses);
3534
- }
3535
- }
3536
-
3537
- if (!empty($altName)) {
3538
- $this->setExtension('id-ce-subjectAltName', $altName);
3539
- }
3540
-
3541
- if ($this->caFlag) {
3542
- $keyUsage = $this->getExtension('id-ce-keyUsage');
3543
- if (!$keyUsage) {
3544
- $keyUsage = array();
3545
- }
3546
-
3547
- $this->setExtension(
3548
- 'id-ce-keyUsage',
3549
- array_values(array_unique(array_merge($keyUsage, array('cRLSign', 'keyCertSign'))))
3550
- );
3551
-
3552
- $basicConstraints = $this->getExtension('id-ce-basicConstraints');
3553
- if (!$basicConstraints) {
3554
- $basicConstraints = array();
3555
- }
3556
-
3557
- $this->setExtension(
3558
- 'id-ce-basicConstraints',
3559
- array_unique(array_merge(array('cA' => true), $basicConstraints)),
3560
- true
3561
- );
3562
-
3563
- if (!isset($subject->currentKeyIdentifier)) {
3564
- $this->setExtension('id-ce-subjectKeyIdentifier', base64_encode($this->computeKeyIdentifier($this->currentCert)), false, false);
3565
- }
3566
- }
3567
-
3568
- // resync $this->signatureSubject
3569
- // save $tbsCertificate in case there are any File_ASN1_Element objects in it
3570
- $tbsCertificate = $this->currentCert['tbsCertificate'];
3571
- $this->loadX509($this->saveX509($this->currentCert));
3572
-
3573
- $result = $this->_sign($issuer->privateKey, $signatureAlgorithm);
3574
- $result['tbsCertificate'] = $tbsCertificate;
3575
-
3576
- $this->currentCert = $currentCert;
3577
- $this->signatureSubject = $signatureSubject;
3578
-
3579
- return $result;
3580
- }
3581
-
3582
- /**
3583
- * Sign a CSR
3584
- *
3585
- * @access public
3586
- * @return mixed
3587
- */
3588
- function signCSR($signatureAlgorithm = 'sha1WithRSAEncryption')
3589
- {
3590
- if (!is_object($this->privateKey) || empty($this->dn)) {
3591
- return false;
3592
- }
3593
-
3594
- $origPublicKey = $this->publicKey;
3595
- $class = get_class($this->privateKey);
3596
- $this->publicKey = new $class();
3597
- $this->publicKey->loadKey($this->privateKey->getPublicKey());
3598
- $this->publicKey->setPublicKey();
3599
- if (!($publicKey = $this->_formatSubjectPublicKey())) {
3600
- return false;
3601
- }
3602
- $this->publicKey = $origPublicKey;
3603
-
3604
- $currentCert = isset($this->currentCert) ? $this->currentCert : null;
3605
- $signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject: null;
3606
-
3607
- if (isset($this->currentCert) && is_array($this->currentCert) && isset($this->currentCert['certificationRequestInfo'])) {
3608
- $this->currentCert['signatureAlgorithm']['algorithm'] = $signatureAlgorithm;
3609
- if (!empty($this->dn)) {
3610
- $this->currentCert['certificationRequestInfo']['subject'] = $this->dn;
3611
- }
3612
- $this->currentCert['certificationRequestInfo']['subjectPKInfo'] = $publicKey;
3613
- } else {
3614
- $this->currentCert = array(
3615
- 'certificationRequestInfo' =>
3616
- array(
3617
- 'version' => 'v1',
3618
- 'subject' => $this->dn,
3619
- 'subjectPKInfo' => $publicKey
3620
- ),
3621
- 'signatureAlgorithm' => array('algorithm' => $signatureAlgorithm),
3622
- 'signature' => false // this is going to be overwritten later
3623
- );
3624
- }
3625
-
3626
- // resync $this->signatureSubject
3627
- // save $certificationRequestInfo in case there are any File_ASN1_Element objects in it
3628
- $certificationRequestInfo = $this->currentCert['certificationRequestInfo'];
3629
- $this->loadCSR($this->saveCSR($this->currentCert));
3630
-
3631
- $result = $this->_sign($this->privateKey, $signatureAlgorithm);
3632
- $result['certificationRequestInfo'] = $certificationRequestInfo;
3633
-
3634
- $this->currentCert = $currentCert;
3635
- $this->signatureSubject = $signatureSubject;
3636
-
3637
- return $result;
3638
- }
3639
-
3640
- /**
3641
- * Sign a SPKAC
3642
- *
3643
- * @access public
3644
- * @return mixed
3645
- */
3646
- function signSPKAC($signatureAlgorithm = 'sha1WithRSAEncryption')
3647
- {
3648
- if (!is_object($this->privateKey)) {
3649
- return false;
3650
- }
3651
-
3652
- $origPublicKey = $this->publicKey;
3653
- $class = get_class($this->privateKey);
3654
- $this->publicKey = new $class();
3655
- $this->publicKey->loadKey($this->privateKey->getPublicKey());
3656
- $this->publicKey->setPublicKey();
3657
- $publicKey = $this->_formatSubjectPublicKey();
3658
- if (!$publicKey) {
3659
- return false;
3660
- }
3661
- $this->publicKey = $origPublicKey;
3662
-
3663
- $currentCert = isset($this->currentCert) ? $this->currentCert : null;
3664
- $signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject: null;
3665
-
3666
- // re-signing a SPKAC seems silly but since everything else supports re-signing why not?
3667
- if (isset($this->currentCert) && is_array($this->currentCert) && isset($this->currentCert['publicKeyAndChallenge'])) {
3668
- $this->currentCert['signatureAlgorithm']['algorithm'] = $signatureAlgorithm;
3669
- $this->currentCert['publicKeyAndChallenge']['spki'] = $publicKey;
3670
- if (!empty($this->challenge)) {
3671
- // the bitwise AND ensures that the output is a valid IA5String
3672
- $this->currentCert['publicKeyAndChallenge']['challenge'] = $this->challenge & str_repeat("\x7F", strlen($this->challenge));
3673
- }
3674
- } else {
3675
- $this->currentCert = array(
3676
- 'publicKeyAndChallenge' =>
3677
- array(
3678
- 'spki' => $publicKey,
3679
- // quoting <https://developer.mozilla.org/en-US/docs/Web/HTML/Element/keygen>,
3680
- // "A challenge string that is submitted along with the public key. Defaults to an empty string if not specified."
3681
- // both Firefox and OpenSSL ("openssl spkac -key private.key") behave this way
3682
- // we could alternatively do this instead if we ignored the specs:
3683
- // crypt_random_string(8) & str_repeat("\x7F", 8)
3684
- 'challenge' => !empty($this->challenge) ? $this->challenge : ''
3685
- ),
3686
- 'signatureAlgorithm' => array('algorithm' => $signatureAlgorithm),
3687
- 'signature' => false // this is going to be overwritten later
3688
- );
3689
- }
3690
-
3691
- // resync $this->signatureSubject
3692
- // save $publicKeyAndChallenge in case there are any File_ASN1_Element objects in it
3693
- $publicKeyAndChallenge = $this->currentCert['publicKeyAndChallenge'];
3694
- $this->loadSPKAC($this->saveSPKAC($this->currentCert));
3695
-
3696
- $result = $this->_sign($this->privateKey, $signatureAlgorithm);
3697
- $result['publicKeyAndChallenge'] = $publicKeyAndChallenge;
3698
-
3699
- $this->currentCert = $currentCert;
3700
- $this->signatureSubject = $signatureSubject;
3701
-
3702
- return $result;
3703
- }
3704
-
3705
- /**
3706
- * Sign a CRL
3707
- *
3708
- * $issuer's private key needs to be loaded.
3709
- *
3710
- * @param File_X509 $issuer
3711
- * @param File_X509 $crl
3712
- * @param string $signatureAlgorithm optional
3713
- * @access public
3714
- * @return mixed
3715
- */
3716
- function signCRL($issuer, $crl, $signatureAlgorithm = 'sha1WithRSAEncryption')
3717
- {
3718
- if (!is_object($issuer->privateKey) || empty($issuer->dn)) {
3719
- return false;
3720
- }
3721
-
3722
- $currentCert = isset($this->currentCert) ? $this->currentCert : null;
3723
- $signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject : null;
3724
- $thisUpdate = !empty($this->startDate) ? $this->startDate : @date('D, d M Y H:i:s O');
3725
-
3726
- if (isset($crl->currentCert) && is_array($crl->currentCert) && isset($crl->currentCert['tbsCertList'])) {
3727
- $this->currentCert = $crl->currentCert;
3728
- $this->currentCert['tbsCertList']['signature']['algorithm'] = $signatureAlgorithm;
3729
- $this->currentCert['signatureAlgorithm']['algorithm'] = $signatureAlgorithm;
3730
- } else {
3731
- $this->currentCert = array(
3732
- 'tbsCertList' =>
3733
- array(
3734
- 'version' => 'v2',
3735
- 'signature' => array('algorithm' => $signatureAlgorithm),
3736
- 'issuer' => false, // this is going to be overwritten later
3737
- 'thisUpdate' => $this->_timeField($thisUpdate) // $this->setStartDate()
3738
- ),
3739
- 'signatureAlgorithm' => array('algorithm' => $signatureAlgorithm),
3740
- 'signature' => false // this is going to be overwritten later
3741
- );
3742
- }
3743
-
3744
- $tbsCertList = &$this->currentCert['tbsCertList'];
3745
- $tbsCertList['issuer'] = $issuer->dn;
3746
- $tbsCertList['thisUpdate'] = $this->_timeField($thisUpdate);
3747
-
3748
- if (!empty($this->endDate)) {
3749
- $tbsCertList['nextUpdate'] = $this->_timeField($this->endDate); // $this->setEndDate()
3750
- } else {
3751
- unset($tbsCertList['nextUpdate']);
3752
- }
3753
-
3754
- if (!empty($this->serialNumber)) {
3755
- $crlNumber = $this->serialNumber;
3756
- } else {
3757
- $crlNumber = $this->getExtension('id-ce-cRLNumber');
3758
- // "The CRL number is a non-critical CRL extension that conveys a
3759
- // monotonically increasing sequence number for a given CRL scope and
3760
- // CRL issuer. This extension allows users to easily determine when a
3761
- // particular CRL supersedes another CRL."
3762
- // -- https://tools.ietf.org/html/rfc5280#section-5.2.3
3763
- $crlNumber = $crlNumber !== false ? $crlNumber->add(new Math_BigInteger(1)) : null;
3764
- }
3765
-
3766
- $this->removeExtension('id-ce-authorityKeyIdentifier');
3767
- $this->removeExtension('id-ce-issuerAltName');
3768
-
3769
- // Be sure version >= v2 if some extension found.
3770
- $version = isset($tbsCertList['version']) ? $tbsCertList['version'] : 0;
3771
- if (!$version) {
3772
- if (!empty($tbsCertList['crlExtensions'])) {
3773
- $version = 1; // v2.
3774
- } elseif (!empty($tbsCertList['revokedCertificates'])) {
3775
- foreach ($tbsCertList['revokedCertificates'] as $cert) {
3776
- if (!empty($cert['crlEntryExtensions'])) {
3777
- $version = 1; // v2.
3778
- }
3779
- }
3780
- }
3781
-
3782
- if ($version) {
3783
- $tbsCertList['version'] = $version;
3784
- }
3785
- }
3786
-
3787
- // Store additional extensions.
3788
- if (!empty($tbsCertList['version'])) { // At least v2.
3789
- if (!empty($crlNumber)) {
3790
- $this->setExtension('id-ce-cRLNumber', $crlNumber);
3791
- }
3792
-
3793
- if (isset($issuer->currentKeyIdentifier)) {
3794
- $this->setExtension('id-ce-authorityKeyIdentifier', array(
3795
- //'authorityCertIssuer' => array(
3796
- // array(
3797
- // 'directoryName' => $issuer->dn
3798
- // )
3799
- //),
3800
- 'keyIdentifier' => $issuer->currentKeyIdentifier
3801
- ));
3802
- //$extensions = &$tbsCertList['crlExtensions'];
3803
- //if (isset($issuer->serialNumber)) {
3804
- // $extensions[count($extensions) - 1]['authorityCertSerialNumber'] = $issuer->serialNumber;
3805
- //}
3806
- //unset($extensions);
3807
- }
3808
-
3809
- $issuerAltName = $this->getExtension('id-ce-subjectAltName', $issuer->currentCert);
3810
-
3811
- if ($issuerAltName !== false) {
3812
- $this->setExtension('id-ce-issuerAltName', $issuerAltName);
3813
- }
3814
- }
3815
-
3816
- if (empty($tbsCertList['revokedCertificates'])) {
3817
- unset($tbsCertList['revokedCertificates']);
3818
- }
3819
-
3820
- unset($tbsCertList);
3821
-
3822
- // resync $this->signatureSubject
3823
- // save $tbsCertList in case there are any File_ASN1_Element objects in it
3824
- $tbsCertList = $this->currentCert['tbsCertList'];
3825
- $this->loadCRL($this->saveCRL($this->currentCert));
3826
-
3827
- $result = $this->_sign($issuer->privateKey, $signatureAlgorithm);
3828
- $result['tbsCertList'] = $tbsCertList;
3829
-
3830
- $this->currentCert = $currentCert;
3831
- $this->signatureSubject = $signatureSubject;
3832
-
3833
- return $result;
3834
- }
3835
-
3836
- /**
3837
- * X.509 certificate signing helper function.
3838
- *
3839
- * @param object $key
3840
- * @param File_X509 $subject
3841
- * @param string $signatureAlgorithm
3842
- * @access public
3843
- * @return mixed
3844
- */
3845
- function _sign($key, $signatureAlgorithm)
3846
- {
3847
- switch (strtolower(get_class($key))) {
3848
- case 'crypt_rsa':
3849
- switch ($signatureAlgorithm) {
3850
- case 'md2WithRSAEncryption':
3851
- case 'md5WithRSAEncryption':
3852
- case 'sha1WithRSAEncryption':
3853
- case 'sha224WithRSAEncryption':
3854
- case 'sha256WithRSAEncryption':
3855
- case 'sha384WithRSAEncryption':
3856
- case 'sha512WithRSAEncryption':
3857
- $key->setHash(preg_replace('#WithRSAEncryption$#', '', $signatureAlgorithm));
3858
- $key->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);
3859
-
3860
- $this->currentCert['signature'] = base64_encode("\0" . $key->sign($this->signatureSubject));
3861
- return $this->currentCert;
3862
- }
3863
- default:
3864
- return false;
3865
- }
3866
- }
3867
-
3868
- /**
3869
- * Set certificate start date
3870
- *
3871
- * @param string $date
3872
- * @access public
3873
- */
3874
- function setStartDate($date)
3875
- {
3876
- $this->startDate = @date('D, d M Y H:i:s O', @strtotime($date));
3877
- }
3878
-
3879
- /**
3880
- * Set certificate end date
3881
- *
3882
- * @param string $date
3883
- * @access public
3884
- */
3885
- function setEndDate($date)
3886
- {
3887
- /*
3888
- To indicate that a certificate has no well-defined expiration date,
3889
- the notAfter SHOULD be assigned the GeneralizedTime value of
3890
- 99991231235959Z.
3891
-
3892
- -- http://tools.ietf.org/html/rfc5280#section-4.1.2.5
3893
- */
3894
- if (strtolower($date) == 'lifetime') {
3895
- $temp = '99991231235959Z';
3896
- $asn1 = new File_ASN1();
3897
- $temp = chr(FILE_ASN1_TYPE_GENERALIZED_TIME) . $asn1->_encodeLength(strlen($temp)) . $temp;
3898
- $this->endDate = new File_ASN1_Element($temp);
3899
- } else {
3900
- $this->endDate = @date('D, d M Y H:i:s O', @strtotime($date));
3901
- }
3902
- }
3903
-
3904
- /**
3905
- * Set Serial Number
3906
- *
3907
- * @param string $serial
3908
- * @param $base optional
3909
- * @access public
3910
- */
3911
- function setSerialNumber($serial, $base = -256)
3912
- {
3913
- $this->serialNumber = new Math_BigInteger($serial, $base);
3914
- }
3915
-
3916
- /**
3917
- * Turns the certificate into a certificate authority
3918
- *
3919
- * @access public
3920
- */
3921
- function makeCA()
3922
- {
3923
- $this->caFlag = true;
3924
- }
3925
-
3926
- /**
3927
- * Check for validity of subarray
3928
- *
3929
- * This is intended for use in conjunction with _subArrayUnchecked(),
3930
- * implementing the checks included in _subArray() but without copying
3931
- * a potentially large array by passing its reference by-value to is_array().
3932
- *
3933
- * @param array $root
3934
- * @param string $path
3935
- * @return boolean
3936
- * @access private
3937
- */
3938
- function _isSubArrayValid($root, $path)
3939
- {
3940
- if (!is_array($root)) {
3941
- return false;
3942
- }
3943
-
3944
- foreach (explode('/', $path) as $i) {
3945
- if (!is_array($root)) {
3946
- return false;
3947
- }
3948
-
3949
- if (!isset($root[$i])) {
3950
- return true;
3951
- }
3952
-
3953
- $root = $root[$i];
3954
- }
3955
-
3956
- return true;
3957
- }
3958
-
3959
- /**
3960
- * Get a reference to a subarray
3961
- *
3962
- * This variant of _subArray() does no is_array() checking,
3963
- * so $root should be checked with _isSubArrayValid() first.
3964
- *
3965
- * This is here for performance reasons:
3966
- * Passing a reference (i.e. $root) by-value (i.e. to is_array())
3967
- * creates a copy. If $root is an especially large array, this is expensive.
3968
- *
3969
- * @param array $root
3970
- * @param string $path absolute path with / as component separator
3971
- * @param bool $create optional
3972
- * @access private
3973
- * @return array|false
3974
- */
3975
- function &_subArrayUnchecked(&$root, $path, $create = false)
3976
- {
3977
- $false = false;
3978
-
3979
- foreach (explode('/', $path) as $i) {
3980
- if (!isset($root[$i])) {
3981
- if (!$create) {
3982
- return $false;
3983
- }
3984
-
3985
- $root[$i] = array();
3986
- }
3987
-
3988
- $root = &$root[$i];
3989
- }
3990
-
3991
- return $root;
3992
- }
3993
-
3994
- /**
3995
- * Get a reference to a subarray
3996
- *
3997
- * @param array $root
3998
- * @param string $path absolute path with / as component separator
3999
- * @param bool $create optional
4000
- * @access private
4001
- * @return array|false
4002
- */
4003
- function &_subArray(&$root, $path, $create = false)
4004
- {
4005
- $false = false;
4006
-
4007
- if (!is_array($root)) {
4008
- return $false;
4009
- }
4010
-
4011
- foreach (explode('/', $path) as $i) {
4012
- if (!is_array($root)) {
4013
- return $false;
4014
- }
4015
-
4016
- if (!isset($root[$i])) {
4017
- if (!$create) {
4018
- return $false;
4019
- }
4020
-
4021
- $root[$i] = array();
4022
- }
4023
-
4024
- $root = &$root[$i];
4025
- }
4026
-
4027
- return $root;
4028
- }
4029
-
4030
- /**
4031
- * Get a reference to an extension subarray
4032
- *
4033
- * @param array $root
4034
- * @param string $path optional absolute path with / as component separator
4035
- * @param bool $create optional
4036
- * @access private
4037
- * @return array|false
4038
- */
4039
- function &_extensions(&$root, $path = null, $create = false)
4040
- {
4041
- if (!isset($root)) {
4042
- $root = $this->currentCert;
4043
- }
4044
-
4045
- switch (true) {
4046
- case !empty($path):
4047
- case !is_array($root):
4048
- break;
4049
- case isset($root['tbsCertificate']):
4050
- $path = 'tbsCertificate/extensions';
4051
- break;
4052
- case isset($root['tbsCertList']):
4053
- $path = 'tbsCertList/crlExtensions';
4054
- break;
4055
- case isset($root['certificationRequestInfo']):
4056
- $pth = 'certificationRequestInfo/attributes';
4057
- $attributes = &$this->_subArray($root, $pth, $create);
4058
-
4059
- if (is_array($attributes)) {
4060
- foreach ($attributes as $key => $value) {
4061
- if ($value['type'] == 'pkcs-9-at-extensionRequest') {
4062
- $path = "$pth/$key/value/0";
4063
- break 2;
4064
- }
4065
- }
4066
- if ($create) {
4067
- $key = count($attributes);
4068
- $attributes[] = array('type' => 'pkcs-9-at-extensionRequest', 'value' => array());
4069
- $path = "$pth/$key/value/0";
4070
- }
4071
- }
4072
- break;
4073
- }
4074
-
4075
- $extensions = &$this->_subArray($root, $path, $create);
4076
-
4077
- if (!is_array($extensions)) {
4078
- $false = false;
4079
- return $false;
4080
- }
4081
-
4082
- return $extensions;
4083
- }
4084
-
4085
- /**
4086
- * Remove an Extension
4087
- *
4088
- * @param string $id
4089
- * @param string $path optional
4090
- * @access private
4091
- * @return bool
4092
- */
4093
- function _removeExtension($id, $path = null)
4094
- {
4095
- $extensions = &$this->_extensions($this->currentCert, $path);
4096
-
4097
- if (!is_array($extensions)) {
4098
- return false;
4099
- }
4100
-
4101
- $result = false;
4102
- foreach ($extensions as $key => $value) {
4103
- if ($value['extnId'] == $id) {
4104
- unset($extensions[$key]);
4105
- $result = true;
4106
- }
4107
- }
4108
-
4109
- $extensions = array_values($extensions);
4110
- return $result;
4111
- }
4112
-
4113
- /**
4114
- * Get an Extension
4115
- *
4116
- * Returns the extension if it exists and false if not
4117
- *
4118
- * @param string $id
4119
- * @param array $cert optional
4120
- * @param string $path optional
4121
- * @access private
4122
- * @return mixed
4123
- */
4124
- function _getExtension($id, $cert = null, $path = null)
4125
- {
4126
- $extensions = $this->_extensions($cert, $path);
4127
-
4128
- if (!is_array($extensions)) {
4129
- return false;
4130
- }
4131
-
4132
- foreach ($extensions as $key => $value) {
4133
- if ($value['extnId'] == $id) {
4134
- return $value['extnValue'];
4135
- }
4136
- }
4137
-
4138
- return false;
4139
- }
4140
-
4141
- /**
4142
- * Returns a list of all extensions in use
4143
- *
4144
- * @param array $cert optional
4145
- * @param string $path optional
4146
- * @access private
4147
- * @return array
4148
- */
4149
- function _getExtensions($cert = null, $path = null)
4150
- {
4151
- $exts = $this->_extensions($cert, $path);
4152
- $extensions = array();
4153
-
4154
- if (is_array($exts)) {
4155
- foreach ($exts as $extension) {
4156
- $extensions[] = $extension['extnId'];
4157
- }
4158
- }
4159
-
4160
- return $extensions;
4161
- }
4162
-
4163
- /**
4164
- * Set an Extension
4165
- *
4166
- * @param string $id
4167
- * @param mixed $value
4168
- * @param bool $critical optional
4169
- * @param bool $replace optional
4170
- * @param string $path optional
4171
- * @access private
4172
- * @return bool
4173
- */
4174
- function _setExtension($id, $value, $critical = false, $replace = true, $path = null)
4175
- {
4176
- $extensions = &$this->_extensions($this->currentCert, $path, true);
4177
-
4178
- if (!is_array($extensions)) {
4179
- return false;
4180
- }
4181
-
4182
- $newext = array('extnId' => $id, 'critical' => $critical, 'extnValue' => $value);
4183
-
4184
- foreach ($extensions as $key => $value) {
4185
- if ($value['extnId'] == $id) {
4186
- if (!$replace) {
4187
- return false;
4188
- }
4189
-
4190
- $extensions[$key] = $newext;
4191
- return true;
4192
- }
4193
- }
4194
-
4195
- $extensions[] = $newext;
4196
- return true;
4197
- }
4198
-
4199
- /**
4200
- * Remove a certificate, CSR or CRL Extension
4201
- *
4202
- * @param string $id
4203
- * @access public
4204
- * @return bool
4205
- */
4206
- function removeExtension($id)
4207
- {
4208
- return $this->_removeExtension($id);
4209
- }
4210
-
4211
- /**
4212
- * Get a certificate, CSR or CRL Extension
4213
- *
4214
- * Returns the extension if it exists and false if not
4215
- *
4216
- * @param string $id
4217
- * @param array $cert optional
4218
- * @access public
4219
- * @return mixed
4220
- */
4221
- function getExtension($id, $cert = null)
4222
- {
4223
- return $this->_getExtension($id, $cert);
4224
- }
4225
-
4226
- /**
4227
- * Returns a list of all extensions in use in certificate, CSR or CRL
4228
- *
4229
- * @param array $cert optional
4230
- * @access public
4231
- * @return array
4232
- */
4233
- function getExtensions($cert = null)
4234
- {
4235
- return $this->_getExtensions($cert);
4236
- }
4237
-
4238
- /**
4239
- * Set a certificate, CSR or CRL Extension
4240
- *
4241
- * @param string $id
4242
- * @param mixed $value
4243
- * @param bool $critical optional
4244
- * @param bool $replace optional
4245
- * @access public
4246
- * @return bool
4247
- */
4248
- function setExtension($id, $value, $critical = false, $replace = true)
4249
- {
4250
- return $this->_setExtension($id, $value, $critical, $replace);
4251
- }
4252
-
4253
- /**
4254
- * Remove a CSR attribute.
4255
- *
4256
- * @param string $id
4257
- * @param int $disposition optional
4258
- * @access public
4259
- * @return bool
4260
- */
4261
- function removeAttribute($id, $disposition = FILE_X509_ATTR_ALL)
4262
- {
4263
- $attributes = &$this->_subArray($this->currentCert, 'certificationRequestInfo/attributes');
4264
-
4265
- if (!is_array($attributes)) {
4266
- return false;
4267
- }
4268
-
4269
- $result = false;
4270
- foreach ($attributes as $key => $attribute) {
4271
- if ($attribute['type'] == $id) {
4272
- $n = count($attribute['value']);
4273
- switch (true) {
4274
- case $disposition == FILE_X509_ATTR_APPEND:
4275
- case $disposition == FILE_X509_ATTR_REPLACE:
4276
- return false;
4277
- case $disposition >= $n:
4278
- $disposition -= $n;
4279
- break;
4280
- case $disposition == FILE_X509_ATTR_ALL:
4281
- case $n == 1:
4282
- unset($attributes[$key]);
4283
- $result = true;
4284
- break;
4285
- default:
4286
- unset($attributes[$key]['value'][$disposition]);
4287
- $attributes[$key]['value'] = array_values($attributes[$key]['value']);
4288
- $result = true;
4289
- break;
4290
- }
4291
- if ($result && $disposition != FILE_X509_ATTR_ALL) {
4292
- break;
4293
- }
4294
- }
4295
- }
4296
-
4297
- $attributes = array_values($attributes);
4298
- return $result;
4299
- }
4300
-
4301
- /**
4302
- * Get a CSR attribute
4303
- *
4304
- * Returns the attribute if it exists and false if not
4305
- *
4306
- * @param string $id
4307
- * @param int $disposition optional
4308
- * @param array $csr optional
4309
- * @access public
4310
- * @return mixed
4311
- */
4312
- function getAttribute($id, $disposition = FILE_X509_ATTR_ALL, $csr = null)
4313
- {
4314
- if (empty($csr)) {
4315
- $csr = $this->currentCert;
4316
- }
4317
-
4318
- $attributes = $this->_subArray($csr, 'certificationRequestInfo/attributes');
4319
-
4320
- if (!is_array($attributes)) {
4321
- return false;
4322
- }
4323
-
4324
- foreach ($attributes as $key => $attribute) {
4325
- if ($attribute['type'] == $id) {
4326
- $n = count($attribute['value']);
4327
- switch (true) {
4328
- case $disposition == FILE_X509_ATTR_APPEND:
4329
- case $disposition == FILE_X509_ATTR_REPLACE:
4330
- return false;
4331
- case $disposition == FILE_X509_ATTR_ALL:
4332
- return $attribute['value'];
4333
- case $disposition >= $n:
4334
- $disposition -= $n;
4335
- break;
4336
- default:
4337
- return $attribute['value'][$disposition];
4338
- }
4339
- }
4340
- }
4341
-
4342
- return false;
4343
- }
4344
-
4345
- /**
4346
- * Returns a list of all CSR attributes in use
4347
- *
4348
- * @param array $csr optional
4349
- * @access public
4350
- * @return array
4351
- */
4352
- function getAttributes($csr = null)
4353
- {
4354
- if (empty($csr)) {
4355
- $csr = $this->currentCert;
4356
- }
4357
-
4358
- $attributes = $this->_subArray($csr, 'certificationRequestInfo/attributes');
4359
- $attrs = array();
4360
-
4361
- if (is_array($attributes)) {
4362
- foreach ($attributes as $attribute) {
4363
- $attrs[] = $attribute['type'];
4364
- }
4365
- }
4366
-
4367
- return $attrs;
4368
- }
4369
-
4370
- /**
4371
- * Set a CSR attribute
4372
- *
4373
- * @param string $id
4374
- * @param mixed $value
4375
- * @param bool $disposition optional
4376
- * @access public
4377
- * @return bool
4378
- */
4379
- function setAttribute($id, $value, $disposition = FILE_X509_ATTR_ALL)
4380
- {
4381
- $attributes = &$this->_subArray($this->currentCert, 'certificationRequestInfo/attributes', true);
4382
-
4383
- if (!is_array($attributes)) {
4384
- return false;
4385
- }
4386
-
4387
- switch ($disposition) {
4388
- case FILE_X509_ATTR_REPLACE:
4389
- $disposition = FILE_X509_ATTR_APPEND;
4390
- case FILE_X509_ATTR_ALL:
4391
- $this->removeAttribute($id);
4392
- break;
4393
- }
4394
-
4395
- foreach ($attributes as $key => $attribute) {
4396
- if ($attribute['type'] == $id) {
4397
- $n = count($attribute['value']);
4398
- switch (true) {
4399
- case $disposition == FILE_X509_ATTR_APPEND:
4400
- $last = $key;
4401
- break;
4402
- case $disposition >= $n:
4403
- $disposition -= $n;
4404
- break;
4405
- default:
4406
- $attributes[$key]['value'][$disposition] = $value;
4407
- return true;
4408
- }
4409
- }
4410
- }
4411
-
4412
- switch (true) {
4413
- case $disposition >= 0:
4414
- return false;
4415
- case isset($last):
4416
- $attributes[$last]['value'][] = $value;
4417
- break;
4418
- default:
4419
- $attributes[] = array('type' => $id, 'value' => $disposition == FILE_X509_ATTR_ALL ? $value: array($value));
4420
- break;
4421
- }
4422
-
4423
- return true;
4424
- }
4425
-
4426
- /**
4427
- * Sets the subject key identifier
4428
- *
4429
- * This is used by the id-ce-authorityKeyIdentifier and the id-ce-subjectKeyIdentifier extensions.
4430
- *
4431
- * @param string $value
4432
- * @access public
4433
- */
4434
- function setKeyIdentifier($value)
4435
- {
4436
- if (empty($value)) {
4437
- unset($this->currentKeyIdentifier);
4438
- } else {
4439
- $this->currentKeyIdentifier = base64_encode($value);
4440
- }
4441
- }
4442
-
4443
- /**
4444
- * Compute a public key identifier.
4445
- *
4446
- * Although key identifiers may be set to any unique value, this function
4447
- * computes key identifiers from public key according to the two
4448
- * recommended methods (4.2.1.2 RFC 3280).
4449
- * Highly polymorphic: try to accept all possible forms of key:
4450
- * - Key object
4451
- * - File_X509 object with public or private key defined
4452
- * - Certificate or CSR array
4453
- * - File_ASN1_Element object
4454
- * - PEM or DER string
4455
- *
4456
- * @param mixed $key optional
4457
- * @param int $method optional
4458
- * @access public
4459
- * @return string binary key identifier
4460
- */
4461
- function computeKeyIdentifier($key = null, $method = 1)
4462
- {
4463
- if (is_null($key)) {
4464
- $key = $this;
4465
- }
4466
-
4467
- switch (true) {
4468
- case is_string($key):
4469
- break;
4470
- case is_array($key) && isset($key['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey']):
4471
- return $this->computeKeyIdentifier($key['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'], $method);
4472
- case is_array($key) && isset($key['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey']):
4473
- return $this->computeKeyIdentifier($key['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'], $method);
4474
- case !is_object($key):
4475
- return false;
4476
- case strtolower(get_class($key)) == 'file_asn1_element':
4477
- // Assume the element is a bitstring-packed key.
4478
- $asn1 = new File_ASN1();
4479
- $decoded = $asn1->decodeBER($key->element);
4480
- if (empty($decoded)) {
4481
- return false;
4482
- }
4483
- $raw = $asn1->asn1map($decoded[0], array('type' => FILE_ASN1_TYPE_BIT_STRING));
4484
- if (empty($raw)) {
4485
- return false;
4486
- }
4487
- $raw = base64_decode($raw);
4488
- // If the key is private, compute identifier from its corresponding public key.
4489
- if (!class_exists('Crypt_RSA')) {
4490
- include_once 'Crypt/RSA.php';
4491
- }
4492
- $key = new Crypt_RSA();
4493
- if (!$key->loadKey($raw)) {
4494
- return false; // Not an unencrypted RSA key.
4495
- }
4496
- if ($key->getPrivateKey() !== false) { // If private.
4497
- return $this->computeKeyIdentifier($key, $method);
4498
- }
4499
- $key = $raw; // Is a public key.
4500
- break;
4501
- case strtolower(get_class($key)) == 'file_x509':
4502
- if (isset($key->publicKey)) {
4503
- return $this->computeKeyIdentifier($key->publicKey, $method);
4504
- }
4505
- if (isset($key->privateKey)) {
4506
- return $this->computeKeyIdentifier($key->privateKey, $method);
4507
- }
4508
- if (isset($key->currentCert['tbsCertificate']) || isset($key->currentCert['certificationRequestInfo'])) {
4509
- return $this->computeKeyIdentifier($key->currentCert, $method);
4510
- }
4511
- return false;
4512
- default: // Should be a key object (i.e.: Crypt_RSA).
4513
- $key = $key->getPublicKey(CRYPT_RSA_PUBLIC_FORMAT_PKCS1);
4514
- break;
4515
- }
4516
-
4517
- // If in PEM format, convert to binary.
4518
- $key = $this->_extractBER($key);
4519
-
4520
- // Now we have the key string: compute its sha-1 sum.
4521
- if (!class_exists('Crypt_Hash')) {
4522
- include_once 'Crypt/Hash.php';
4523
- }
4524
- $hash = new Crypt_Hash('sha1');
4525
- $hash = $hash->hash($key);
4526
-
4527
- if ($method == 2) {
4528
- $hash = substr($hash, -8);
4529
- $hash[0] = chr((ord($hash[0]) & 0x0F) | 0x40);
4530
- }
4531
-
4532
- return $hash;
4533
- }
4534
-
4535
- /**
4536
- * Format a public key as appropriate
4537
- *
4538
- * @access private
4539
- * @return array
4540
- */
4541
- function _formatSubjectPublicKey()
4542
- {
4543
- if (!isset($this->publicKey) || !is_object($this->publicKey)) {
4544
- return false;
4545
- }
4546
-
4547
- switch (strtolower(get_class($this->publicKey))) {
4548
- case 'crypt_rsa':
4549
- // the following two return statements do the same thing. i dunno.. i just prefer the later for some reason.
4550
- // the former is a good example of how to do fuzzing on the public key
4551
- //return new File_ASN1_Element(base64_decode(preg_replace('#-.+-|[\r\n]#', '', $this->publicKey->getPublicKey())));
4552
- return array(
4553
- 'algorithm' => array('algorithm' => 'rsaEncryption'),
4554
- 'subjectPublicKey' => $this->publicKey->getPublicKey(CRYPT_RSA_PUBLIC_FORMAT_PKCS1)
4555
- );
4556
- default:
4557
- return false;
4558
- }
4559
- }
4560
-
4561
- /**
4562
- * Set the domain name's which the cert is to be valid for
4563
- *
4564
- * @access public
4565
- * @return array
4566
- */
4567
- function setDomain()
4568
- {
4569
- $this->domains = func_get_args();
4570
- $this->removeDNProp('id-at-commonName');
4571
- $this->setDNProp('id-at-commonName', $this->domains[0]);
4572
- }
4573
-
4574
- /**
4575
- * Set the IP Addresses's which the cert is to be valid for
4576
- *
4577
- * @access public
4578
- * @param string $ipAddress optional
4579
- */
4580
- function setIPAddress()
4581
- {
4582
- $this->ipAddresses = func_get_args();
4583
- /*
4584
- if (!isset($this->domains)) {
4585
- $this->removeDNProp('id-at-commonName');
4586
- $this->setDNProp('id-at-commonName', $this->ipAddresses[0]);
4587
- }
4588
- */
4589
- }
4590
-
4591
- /**
4592
- * Helper function to build domain array
4593
- *
4594
- * @access private
4595
- * @param string $domain
4596
- * @return array
4597
- */
4598
- function _dnsName($domain)
4599
- {
4600
- return array('dNSName' => $domain);
4601
- }
4602
-
4603
- /**
4604
- * Helper function to build IP Address array
4605
- *
4606
- * (IPv6 is not currently supported)
4607
- *
4608
- * @access private
4609
- * @param string $address
4610
- * @return array
4611
- */
4612
- function _iPAddress($address)
4613
- {
4614
- return array('iPAddress' => $address);
4615
- }
4616
-
4617
- /**
4618
- * Get the index of a revoked certificate.
4619
- *
4620
- * @param array $rclist
4621
- * @param string $serial
4622
- * @param bool $create optional
4623
- * @access private
4624
- * @return int|false
4625
- */
4626
- function _revokedCertificate(&$rclist, $serial, $create = false)
4627
- {
4628
- $serial = new Math_BigInteger($serial);
4629
-
4630
- foreach ($rclist as $i => $rc) {
4631
- if (!($serial->compare($rc['userCertificate']))) {
4632
- return $i;
4633
- }
4634
- }
4635
-
4636
- if (!$create) {
4637
- return false;
4638
- }
4639
-
4640
- $i = count($rclist);
4641
- $rclist[] = array('userCertificate' => $serial,
4642
- 'revocationDate' => $this->_timeField(@date('D, d M Y H:i:s O')));
4643
- return $i;
4644
- }
4645
-
4646
- /**
4647
- * Revoke a certificate.
4648
- *
4649
- * @param string $serial
4650
- * @param string $date optional
4651
- * @access public
4652
- * @return bool
4653
- */
4654
- function revoke($serial, $date = null)
4655
- {
4656
- if (isset($this->currentCert['tbsCertList'])) {
4657
- if (is_array($rclist = &$this->_subArray($this->currentCert, 'tbsCertList/revokedCertificates', true))) {
4658
- if ($this->_revokedCertificate($rclist, $serial) === false) { // If not yet revoked
4659
- if (($i = $this->_revokedCertificate($rclist, $serial, true)) !== false) {
4660
- if (!empty($date)) {
4661
- $rclist[$i]['revocationDate'] = $this->_timeField($date);
4662
- }
4663
-
4664
- return true;
4665
- }
4666
- }
4667
- }
4668
- }
4669
-
4670
- return false;
4671
- }
4672
-
4673
- /**
4674
- * Unrevoke a certificate.
4675
- *
4676
- * @param string $serial
4677
- * @access public
4678
- * @return bool
4679
- */
4680
- function unrevoke($serial)
4681
- {
4682
- if (is_array($rclist = &$this->_subArray($this->currentCert, 'tbsCertList/revokedCertificates'))) {
4683
- if (($i = $this->_revokedCertificate($rclist, $serial)) !== false) {
4684
- unset($rclist[$i]);
4685
- $rclist = array_values($rclist);
4686
- return true;
4687
- }
4688
- }
4689
-
4690
- return false;
4691
- }
4692
-
4693
- /**
4694
- * Get a revoked certificate.
4695
- *
4696
- * @param string $serial
4697
- * @access public
4698
- * @return mixed
4699
- */
4700
- function getRevoked($serial)
4701
- {
4702
- if (is_array($rclist = $this->_subArray($this->currentCert, 'tbsCertList/revokedCertificates'))) {
4703
- if (($i = $this->_revokedCertificate($rclist, $serial)) !== false) {
4704
- return $rclist[$i];
4705
- }
4706
- }
4707
-
4708
- return false;
4709
- }
4710
-
4711
- /**
4712
- * List revoked certificates
4713
- *
4714
- * @param array $crl optional
4715
- * @access public
4716
- * @return array
4717
- */
4718
- function listRevoked($crl = null)
4719
- {
4720
- if (!isset($crl)) {
4721
- $crl = $this->currentCert;
4722
- }
4723
-
4724
- if (!isset($crl['tbsCertList'])) {
4725
- return false;
4726
- }
4727
-
4728
- $result = array();
4729
-
4730
- if (is_array($rclist = $this->_subArray($crl, 'tbsCertList/revokedCertificates'))) {
4731
- foreach ($rclist as $rc) {
4732
- $result[] = $rc['userCertificate']->toString();
4733
- }
4734
- }
4735
-
4736
- return $result;
4737
- }
4738
-
4739
- /**
4740
- * Remove a Revoked Certificate Extension
4741
- *
4742
- * @param string $serial
4743
- * @param string $id
4744
- * @access public
4745
- * @return bool
4746
- */
4747
- function removeRevokedCertificateExtension($serial, $id)
4748
- {
4749
- if (is_array($rclist = &$this->_subArray($this->currentCert, 'tbsCertList/revokedCertificates'))) {
4750
- if (($i = $this->_revokedCertificate($rclist, $serial)) !== false) {
4751
- return $this->_removeExtension($id, "tbsCertList/revokedCertificates/$i/crlEntryExtensions");
4752
- }
4753
- }
4754
-
4755
- return false;
4756
- }
4757
-
4758
- /**
4759
- * Get a Revoked Certificate Extension
4760
- *
4761
- * Returns the extension if it exists and false if not
4762
- *
4763
- * @param string $serial
4764
- * @param string $id
4765
- * @param array $crl optional
4766
- * @access public
4767
- * @return mixed
4768
- */
4769
- function getRevokedCertificateExtension($serial, $id, $crl = null)
4770
- {
4771
- if (!isset($crl)) {
4772
- $crl = $this->currentCert;
4773
- }
4774
-
4775
- if (is_array($rclist = $this->_subArray($crl, 'tbsCertList/revokedCertificates'))) {
4776
- if (($i = $this->_revokedCertificate($rclist, $serial)) !== false) {
4777
- return $this->_getExtension($id, $crl, "tbsCertList/revokedCertificates/$i/crlEntryExtensions");
4778
- }
4779
- }
4780
-
4781
- return false;
4782
- }
4783
-
4784
- /**
4785
- * Returns a list of all extensions in use for a given revoked certificate
4786
- *
4787
- * @param string $serial
4788
- * @param array $crl optional
4789
- * @access public
4790
- * @return array
4791
- */
4792
- function getRevokedCertificateExtensions($serial, $crl = null)
4793
- {
4794
- if (!isset($crl)) {
4795
- $crl = $this->currentCert;
4796
- }
4797
-
4798
- if (is_array($rclist = $this->_subArray($crl, 'tbsCertList/revokedCertificates'))) {
4799
- if (($i = $this->_revokedCertificate($rclist, $serial)) !== false) {
4800
- return $this->_getExtensions($crl, "tbsCertList/revokedCertificates/$i/crlEntryExtensions");
4801
- }
4802
- }
4803
-
4804
- return false;
4805
- }
4806
-
4807
- /**
4808
- * Set a Revoked Certificate Extension
4809
- *
4810
- * @param string $serial
4811
- * @param string $id
4812
- * @param mixed $value
4813
- * @param bool $critical optional
4814
- * @param bool $replace optional
4815
- * @access public
4816
- * @return bool
4817
- */
4818
- function setRevokedCertificateExtension($serial, $id, $value, $critical = false, $replace = true)
4819
- {
4820
- if (isset($this->currentCert['tbsCertList'])) {
4821
- if (is_array($rclist = &$this->_subArray($this->currentCert, 'tbsCertList/revokedCertificates', true))) {
4822
- if (($i = $this->_revokedCertificate($rclist, $serial, true)) !== false) {
4823
- return $this->_setExtension($id, $value, $critical, $replace, "tbsCertList/revokedCertificates/$i/crlEntryExtensions");
4824
- }
4825
- }
4826
- }
4827
-
4828
- return false;
4829
- }
4830
-
4831
- /**
4832
- * Extract raw BER from Base64 encoding
4833
- *
4834
- * @access private
4835
- * @param string $str
4836
- * @return string
4837
- */
4838
- function _extractBER($str)
4839
- {
4840
- /* X.509 certs are assumed to be base64 encoded but sometimes they'll have additional things in them
4841
- * above and beyond the ceritificate.
4842
- * ie. some may have the following preceding the -----BEGIN CERTIFICATE----- line:
4843
- *
4844
- * Bag Attributes
4845
- * localKeyID: 01 00 00 00
4846
- * subject=/O=organization/OU=org unit/CN=common name
4847
- * issuer=/O=organization/CN=common name
4848
- */
4849
- $temp = preg_replace('#.*?^-+[^-]+-+[\r\n ]*$#ms', '', $str, 1);
4850
- // remove the -----BEGIN CERTIFICATE----- and -----END CERTIFICATE----- stuff
4851
- $temp = preg_replace('#-+[^-]+-+#', '', $temp);
4852
- // remove new lines
4853
- $temp = str_replace(array("\r", "\n", ' '), '', $temp);
4854
- $temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? base64_decode($temp) : false;
4855
- return $temp != false ? $temp : $str;
4856
- }
4857
-
4858
- /**
4859
- * Returns the OID corresponding to a name
4860
- *
4861
- * What's returned in the associative array returned by loadX509() (or load*()) is either a name or an OID if
4862
- * no OID to name mapping is available. The problem with this is that what may be an unmapped OID in one version
4863
- * of phpseclib may not be unmapped in the next version, so apps that are looking at this OID may not be able
4864
- * to work from version to version.
4865
- *
4866
- * This method will return the OID if a name is passed to it and if no mapping is avialable it'll assume that
4867
- * what's being passed to it already is an OID and return that instead. A few examples.
4868
- *
4869
- * getOID('2.16.840.1.101.3.4.2.1') == '2.16.840.1.101.3.4.2.1'
4870
- * getOID('id-sha256') == '2.16.840.1.101.3.4.2.1'
4871
- * getOID('zzz') == 'zzz'
4872
- *
4873
- * @access public
4874
- * @return string
4875
- */
4876
- function getOID($name)
4877
- {
4878
- static $reverseMap;
4879
- if (!isset($reverseMap)) {
4880
- $reverseMap = array_flip($this->oids);
4881
- }
4882
- return isset($reverseMap[$name]) ? $reverseMap[$name] : $name;
4883
- }
4884
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/phpseclib/Math/BigInteger.php DELETED
@@ -1,3804 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Pure-PHP arbitrary precision integer arithmetic library.
5
- *
6
- * Supports base-2, base-10, base-16, and base-256 numbers. Uses the GMP or BCMath extensions, if available,
7
- * and an internal implementation, otherwise.
8
- *
9
- * PHP versions 4 and 5
10
- *
11
- * {@internal (all DocBlock comments regarding implementation - such as the one that follows - refer to the
12
- * {@link MATH_BIGINTEGER_MODE_INTERNAL MATH_BIGINTEGER_MODE_INTERNAL} mode)
13
- *
14
- * Math_BigInteger uses base-2**26 to perform operations such as multiplication and division and
15
- * base-2**52 (ie. two base 2**26 digits) to perform addition and subtraction. Because the largest possible
16
- * value when multiplying two base-2**26 numbers together is a base-2**52 number, double precision floating
17
- * point numbers - numbers that should be supported on most hardware and whose significand is 53 bits - are
18
- * used. As a consequence, bitwise operators such as >> and << cannot be used, nor can the modulo operator %,
19
- * which only supports integers. Although this fact will slow this library down, the fact that such a high
20
- * base is being used should more than compensate.
21
- *
22
- * Numbers are stored in {@link http://en.wikipedia.org/wiki/Endianness little endian} format. ie.
23
- * (new Math_BigInteger(pow(2, 26)))->value = array(0, 1)
24
- *
25
- * Useful resources are as follows:
26
- *
27
- * - {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf Handbook of Applied Cryptography (HAC)}
28
- * - {@link http://math.libtomcrypt.com/files/tommath.pdf Multi-Precision Math (MPM)}
29
- * - Java's BigInteger classes. See /j2se/src/share/classes/java/math in jdk-1_5_0-src-jrl.zip
30
- *
31
- * Here's an example of how to use this library:
32
- * <code>
33
- * <?php
34
- * include 'Math/BigInteger.php';
35
- *
36
- * $a = new Math_BigInteger(2);
37
- * $b = new Math_BigInteger(3);
38
- *
39
- * $c = $a->add($b);
40
- *
41
- * echo $c->toString(); // outputs 5
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 Math
64
- * @package Math_BigInteger
65
- * @author Jim Wigginton <terrafrost@php.net>
66
- * @copyright 2006 Jim Wigginton
67
- * @license http://www.opensource.org/licenses/mit-license.html MIT License
68
- * @link http://pear.php.net/package/Math_BigInteger
69
- */
70
-
71
- /**#@+
72
- * Reduction constants
73
- *
74
- * @access private
75
- * @see self::_reduce()
76
- */
77
- /**
78
- * @see self::_montgomery()
79
- * @see self::_prepMontgomery()
80
- */
81
- define('MATH_BIGINTEGER_MONTGOMERY', 0);
82
- /**
83
- * @see self::_barrett()
84
- */
85
- define('MATH_BIGINTEGER_BARRETT', 1);
86
- /**
87
- * @see self::_mod2()
88
- */
89
- define('MATH_BIGINTEGER_POWEROF2', 2);
90
- /**
91
- * @see self::_remainder()
92
- */
93
- define('MATH_BIGINTEGER_CLASSIC', 3);
94
- /**
95
- * @see self::__clone()
96
- */
97
- define('MATH_BIGINTEGER_NONE', 4);
98
- /**#@-*/
99
-
100
- /**#@+
101
- * Array constants
102
- *
103
- * Rather than create a thousands and thousands of new Math_BigInteger objects in repeated function calls to add() and
104
- * multiply() or whatever, we'll just work directly on arrays, taking them in as parameters and returning them.
105
- *
106
- * @access private
107
- */
108
- /**
109
- * $result[MATH_BIGINTEGER_VALUE] contains the value.
110
- */
111
- define('MATH_BIGINTEGER_VALUE', 0);
112
- /**
113
- * $result[MATH_BIGINTEGER_SIGN] contains the sign.
114
- */
115
- define('MATH_BIGINTEGER_SIGN', 1);
116
- /**#@-*/
117
-
118
- /**#@+
119
- * @access private
120
- * @see self::_montgomery()
121
- * @see self::_barrett()
122
- */
123
- /**
124
- * Cache constants
125
- *
126
- * $cache[MATH_BIGINTEGER_VARIABLE] tells us whether or not the cached data is still valid.
127
- */
128
- define('MATH_BIGINTEGER_VARIABLE', 0);
129
- /**
130
- * $cache[MATH_BIGINTEGER_DATA] contains the cached data.
131
- */
132
- define('MATH_BIGINTEGER_DATA', 1);
133
- /**#@-*/
134
-
135
- /**#@+
136
- * Mode constants.
137
- *
138
- * @access private
139
- * @see self::Math_BigInteger()
140
- */
141
- /**
142
- * To use the pure-PHP implementation
143
- */
144
- define('MATH_BIGINTEGER_MODE_INTERNAL', 1);
145
- /**
146
- * To use the BCMath library
147
- *
148
- * (if enabled; otherwise, the internal implementation will be used)
149
- */
150
- define('MATH_BIGINTEGER_MODE_BCMATH', 2);
151
- /**
152
- * To use the GMP library
153
- *
154
- * (if present; otherwise, either the BCMath or the internal implementation will be used)
155
- */
156
- define('MATH_BIGINTEGER_MODE_GMP', 3);
157
- /**#@-*/
158
-
159
- /**
160
- * Karatsuba Cutoff
161
- *
162
- * At what point do we switch between Karatsuba multiplication and schoolbook long multiplication?
163
- *
164
- * @access private
165
- */
166
- define('MATH_BIGINTEGER_KARATSUBA_CUTOFF', 25);
167
-
168
- /**
169
- * Pure-PHP arbitrary precision integer arithmetic library. Supports base-2, base-10, base-16, and base-256
170
- * numbers.
171
- *
172
- * @package Math_BigInteger
173
- * @author Jim Wigginton <terrafrost@php.net>
174
- * @access public
175
- */
176
- class Math_BigInteger
177
- {
178
- /**
179
- * Holds the BigInteger's value.
180
- *
181
- * @var array
182
- * @access private
183
- */
184
- var $value;
185
-
186
- /**
187
- * Holds the BigInteger's magnitude.
188
- *
189
- * @var bool
190
- * @access private
191
- */
192
- var $is_negative = false;
193
-
194
- /**
195
- * Precision
196
- *
197
- * @see self::setPrecision()
198
- * @access private
199
- */
200
- var $precision = -1;
201
-
202
- /**
203
- * Precision Bitmask
204
- *
205
- * @see self::setPrecision()
206
- * @access private
207
- */
208
- var $bitmask = false;
209
-
210
- /**
211
- * Mode independent value used for serialization.
212
- *
213
- * If the bcmath or gmp extensions are installed $this->value will be a non-serializable resource, hence the need for
214
- * a variable that'll be serializable regardless of whether or not extensions are being used. Unlike $this->value,
215
- * however, $this->hex is only calculated when $this->__sleep() is called.
216
- *
217
- * @see self::__sleep()
218
- * @see self::__wakeup()
219
- * @var string
220
- * @access private
221
- */
222
- var $hex;
223
-
224
- /**
225
- * Converts base-2, base-10, base-16, and binary strings (base-256) to BigIntegers.
226
- *
227
- * If the second parameter - $base - is negative, then it will be assumed that the number's are encoded using
228
- * two's compliment. The sole exception to this is -10, which is treated the same as 10 is.
229
- *
230
- * Here's an example:
231
- * <code>
232
- * <?php
233
- * include 'Math/BigInteger.php';
234
- *
235
- * $a = new Math_BigInteger('0x32', 16); // 50 in base-16
236
- *
237
- * echo $a->toString(); // outputs 50
238
- * ?>
239
- * </code>
240
- *
241
- * @param $x base-10 number or base-$base number if $base set.
242
- * @param int $base
243
- * @return Math_BigInteger
244
- * @access public
245
- */
246
- function __construct($x = 0, $base = 10)
247
- {
248
- if (!defined('MATH_BIGINTEGER_MODE')) {
249
- switch (true) {
250
- case extension_loaded('gmp'):
251
- define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_GMP);
252
- break;
253
- case extension_loaded('bcmath'):
254
- define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_BCMATH);
255
- break;
256
- default:
257
- define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_INTERNAL);
258
- }
259
- }
260
-
261
- if (extension_loaded('openssl') && !defined('MATH_BIGINTEGER_OPENSSL_DISABLE') && !defined('MATH_BIGINTEGER_OPENSSL_ENABLED')) {
262
- // some versions of XAMPP have mismatched versions of OpenSSL which causes it not to work
263
- ob_start();
264
- @phpinfo();
265
- $content = ob_get_contents();
266
- ob_end_clean();
267
-
268
- preg_match_all('#OpenSSL (Header|Library) Version(.*)#im', $content, $matches);
269
-
270
- $versions = array();
271
- if (!empty($matches[1])) {
272
- for ($i = 0; $i < count($matches[1]); $i++) {
273
- $fullVersion = trim(str_replace('=>', '', strip_tags($matches[2][$i])));
274
-
275
- // Remove letter part in OpenSSL version
276
- if (!preg_match('/(\d+\.\d+\.\d+)/i', $fullVersion, $m)) {
277
- $versions[$matches[1][$i]] = $fullVersion;
278
- } else {
279
- $versions[$matches[1][$i]] = $m[0];
280
- }
281
- }
282
- }
283
-
284
- // it doesn't appear that OpenSSL versions were reported upon until PHP 5.3+
285
- switch (true) {
286
- case !isset($versions['Header']):
287
- case !isset($versions['Library']):
288
- case $versions['Header'] == $versions['Library']:
289
- case version_compare($versions['Header'], '1.0.0') >= 0 && version_compare($versions['Library'], '1.0.0') >= 0:
290
- define('MATH_BIGINTEGER_OPENSSL_ENABLED', true);
291
- break;
292
- default:
293
- define('MATH_BIGINTEGER_OPENSSL_DISABLE', true);
294
- }
295
- }
296
-
297
- if (!defined('PHP_INT_SIZE')) {
298
- define('PHP_INT_SIZE', 4);
299
- }
300
-
301
- if (!defined('MATH_BIGINTEGER_BASE') && MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_INTERNAL) {
302
- switch (PHP_INT_SIZE) {
303
- case 8: // use 64-bit integers if int size is 8 bytes
304
- define('MATH_BIGINTEGER_BASE', 31);
305
- define('MATH_BIGINTEGER_BASE_FULL', 0x80000000);
306
- define('MATH_BIGINTEGER_MAX_DIGIT', 0x7FFFFFFF);
307
- define('MATH_BIGINTEGER_MSB', 0x40000000);
308
- // 10**9 is the closest we can get to 2**31 without passing it
309
- define('MATH_BIGINTEGER_MAX10', 1000000000);
310
- define('MATH_BIGINTEGER_MAX10_LEN', 9);
311
- // the largest digit that may be used in addition / subtraction
312
- define('MATH_BIGINTEGER_MAX_DIGIT2', pow(2, 62));
313
- break;
314
- //case 4: // use 64-bit floats if int size is 4 bytes
315
- default:
316
- define('MATH_BIGINTEGER_BASE', 26);
317
- define('MATH_BIGINTEGER_BASE_FULL', 0x4000000);
318
- define('MATH_BIGINTEGER_MAX_DIGIT', 0x3FFFFFF);
319
- define('MATH_BIGINTEGER_MSB', 0x2000000);
320
- // 10**7 is the closest to 2**26 without passing it
321
- define('MATH_BIGINTEGER_MAX10', 10000000);
322
- define('MATH_BIGINTEGER_MAX10_LEN', 7);
323
- // the largest digit that may be used in addition / subtraction
324
- // we do pow(2, 52) instead of using 4503599627370496 directly because some
325
- // PHP installations will truncate 4503599627370496.
326
- define('MATH_BIGINTEGER_MAX_DIGIT2', pow(2, 52));
327
- }
328
- }
329
-
330
- switch (MATH_BIGINTEGER_MODE) {
331
- case MATH_BIGINTEGER_MODE_GMP:
332
- switch (true) {
333
- case is_resource($x) && get_resource_type($x) == 'GMP integer':
334
- // PHP 5.6 switched GMP from using resources to objects
335
- case is_object($x) && get_class($x) == 'GMP':
336
- $this->value = $x;
337
- return;
338
- }
339
- $this->value = gmp_init(0);
340
- break;
341
- case MATH_BIGINTEGER_MODE_BCMATH:
342
- $this->value = '0';
343
- break;
344
- default:
345
- $this->value = array();
346
- }
347
-
348
- // '0' counts as empty() but when the base is 256 '0' is equal to ord('0') or 48
349
- // '0' is the only value like this per http://php.net/empty
350
- if (empty($x) && (abs($base) != 256 || $x !== '0')) {
351
- return;
352
- }
353
-
354
- switch ($base) {
355
- case -256:
356
- if (ord($x[0]) & 0x80) {
357
- $x = ~$x;
358
- $this->is_negative = true;
359
- }
360
- case 256:
361
- switch (MATH_BIGINTEGER_MODE) {
362
- case MATH_BIGINTEGER_MODE_GMP:
363
- $sign = $this->is_negative ? '-' : '';
364
- $this->value = gmp_init($sign . '0x' . bin2hex($x));
365
- break;
366
- case MATH_BIGINTEGER_MODE_BCMATH:
367
- // round $len to the nearest 4 (thanks, DavidMJ!)
368
- $len = (strlen($x) + 3) & 0xFFFFFFFC;
369
-
370
- $x = str_pad($x, $len, chr(0), STR_PAD_LEFT);
371
-
372
- for ($i = 0; $i < $len; $i+= 4) {
373
- $this->value = bcmul($this->value, '4294967296', 0); // 4294967296 == 2**32
374
- $this->value = bcadd($this->value, 0x1000000 * ord($x[$i]) + ((ord($x[$i + 1]) << 16) | (ord($x[$i + 2]) << 8) | ord($x[$i + 3])), 0);
375
- }
376
-
377
- if ($this->is_negative) {
378
- $this->value = '-' . $this->value;
379
- }
380
-
381
- break;
382
- // converts a base-2**8 (big endian / msb) number to base-2**26 (little endian / lsb)
383
- default:
384
- while (strlen($x)) {
385
- $this->value[] = $this->_bytes2int($this->_base256_rshift($x, MATH_BIGINTEGER_BASE));
386
- }
387
- }
388
-
389
- if ($this->is_negative) {
390
- if (MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL) {
391
- $this->is_negative = false;
392
- }
393
- $temp = $this->add(new Math_BigInteger('-1'));
394
- $this->value = $temp->value;
395
- }
396
- break;
397
- case 16:
398
- case -16:
399
- if ($base > 0 && $x[0] == '-') {
400
- $this->is_negative = true;
401
- $x = substr($x, 1);
402
- }
403
-
404
- $x = preg_replace('#^(?:0x)?([A-Fa-f0-9]*).*#', '$1', $x);
405
-
406
- $is_negative = false;
407
- if ($base < 0 && hexdec($x[0]) >= 8) {
408
- $this->is_negative = $is_negative = true;
409
- $x = bin2hex(~pack('H*', $x));
410
- }
411
-
412
- switch (MATH_BIGINTEGER_MODE) {
413
- case MATH_BIGINTEGER_MODE_GMP:
414
- $temp = $this->is_negative ? '-0x' . $x : '0x' . $x;
415
- $this->value = gmp_init($temp);
416
- $this->is_negative = false;
417
- break;
418
- case MATH_BIGINTEGER_MODE_BCMATH:
419
- $x = (strlen($x) & 1) ? '0' . $x : $x;
420
- $temp = new Math_BigInteger(pack('H*', $x), 256);
421
- $this->value = $this->is_negative ? '-' . $temp->value : $temp->value;
422
- $this->is_negative = false;
423
- break;
424
- default:
425
- $x = (strlen($x) & 1) ? '0' . $x : $x;
426
- $temp = new Math_BigInteger(pack('H*', $x), 256);
427
- $this->value = $temp->value;
428
- }
429
-
430
- if ($is_negative) {
431
- $temp = $this->add(new Math_BigInteger('-1'));
432
- $this->value = $temp->value;
433
- }
434
- break;
435
- case 10:
436
- case -10:
437
- // (?<!^)(?:-).*: find any -'s that aren't at the beginning and then any characters that follow that
438
- // (?<=^|-)0*: find any 0's that are preceded by the start of the string or by a - (ie. octals)
439
- // [^-0-9].*: find any non-numeric characters and then any characters that follow that
440
- $x = preg_replace('#(?<!^)(?:-).*|(?<=^|-)0*|[^-0-9].*#', '', $x);
441
-
442
- switch (MATH_BIGINTEGER_MODE) {
443
- case MATH_BIGINTEGER_MODE_GMP:
444
- $this->value = gmp_init($x);
445
- break;
446
- case MATH_BIGINTEGER_MODE_BCMATH:
447
- // explicitly casting $x to a string is necessary, here, since doing $x[0] on -1 yields different
448
- // results then doing it on '-1' does (modInverse does $x[0])
449
- $this->value = $x === '-' ? '0' : (string) $x;
450
- break;
451
- default:
452
- $temp = new Math_BigInteger();
453
-
454
- $multiplier = new Math_BigInteger();
455
- $multiplier->value = array(MATH_BIGINTEGER_MAX10);
456
-
457
- if ($x[0] == '-') {
458
- $this->is_negative = true;
459
- $x = substr($x, 1);
460
- }
461
-
462
- $x = str_pad($x, strlen($x) + ((MATH_BIGINTEGER_MAX10_LEN - 1) * strlen($x)) % MATH_BIGINTEGER_MAX10_LEN, 0, STR_PAD_LEFT);
463
- while (strlen($x)) {
464
- $temp = $temp->multiply($multiplier);
465
- $temp = $temp->add(new Math_BigInteger($this->_int2bytes(substr($x, 0, MATH_BIGINTEGER_MAX10_LEN)), 256));
466
- $x = substr($x, MATH_BIGINTEGER_MAX10_LEN);
467
- }
468
-
469
- $this->value = $temp->value;
470
- }
471
- break;
472
- case 2: // base-2 support originally implemented by Lluis Pamies - thanks!
473
- case -2:
474
- if ($base > 0 && $x[0] == '-') {
475
- $this->is_negative = true;
476
- $x = substr($x, 1);
477
- }
478
-
479
- $x = preg_replace('#^([01]*).*#', '$1', $x);
480
- $x = str_pad($x, strlen($x) + (3 * strlen($x)) % 4, 0, STR_PAD_LEFT);
481
-
482
- $str = '0x';
483
- while (strlen($x)) {
484
- $part = substr($x, 0, 4);
485
- $str.= dechex(bindec($part));
486
- $x = substr($x, 4);
487
- }
488
-
489
- if ($this->is_negative) {
490
- $str = '-' . $str;
491
- }
492
-
493
- $temp = new Math_BigInteger($str, 8 * $base); // ie. either -16 or +16
494
- $this->value = $temp->value;
495
- $this->is_negative = $temp->is_negative;
496
-
497
- break;
498
- default:
499
- // base not supported, so we'll let $this == 0
500
- }
501
- }
502
-
503
- /**
504
- * PHP4 compatible Default Constructor.
505
- *
506
- * @see self::__construct()
507
- * @param $x base-10 number or base-$base number if $base set.
508
- * @param int $base
509
- * @access public
510
- */
511
- function Math_BigInteger($x = 0, $base = 10)
512
- {
513
- $this->__construct($x, $base);
514
- }
515
-
516
- /**
517
- * Converts a BigInteger to a byte string (eg. base-256).
518
- *
519
- * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're
520
- * saved as two's compliment.
521
- *
522
- * Here's an example:
523
- * <code>
524
- * <?php
525
- * include 'Math/BigInteger.php';
526
- *
527
- * $a = new Math_BigInteger('65');
528
- *
529
- * echo $a->toBytes(); // outputs chr(65)
530
- * ?>
531
- * </code>
532
- *
533
- * @param bool $twos_compliment
534
- * @return string
535
- * @access public
536
- * @internal Converts a base-2**26 number to base-2**8
537
- */
538
- function toBytes($twos_compliment = false)
539
- {
540
- if ($twos_compliment) {
541
- $comparison = $this->compare(new Math_BigInteger());
542
- if ($comparison == 0) {
543
- return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
544
- }
545
-
546
- $temp = $comparison < 0 ? $this->add(new Math_BigInteger(1)) : $this->copy();
547
- $bytes = $temp->toBytes();
548
-
549
- if (empty($bytes)) { // eg. if the number we're trying to convert is -1
550
- $bytes = chr(0);
551
- }
552
-
553
- if (ord($bytes[0]) & 0x80) {
554
- $bytes = chr(0) . $bytes;
555
- }
556
-
557
- return $comparison < 0 ? ~$bytes : $bytes;
558
- }
559
-
560
- switch (MATH_BIGINTEGER_MODE) {
561
- case MATH_BIGINTEGER_MODE_GMP:
562
- if (gmp_cmp($this->value, gmp_init(0)) == 0) {
563
- return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
564
- }
565
-
566
- $temp = gmp_strval(gmp_abs($this->value), 16);
567
- $temp = (strlen($temp) & 1) ? '0' . $temp : $temp;
568
- $temp = pack('H*', $temp);
569
-
570
- return $this->precision > 0 ?
571
- substr(str_pad($temp, $this->precision >> 3, chr(0), STR_PAD_LEFT), -($this->precision >> 3)) :
572
- ltrim($temp, chr(0));
573
- case MATH_BIGINTEGER_MODE_BCMATH:
574
- if ($this->value === '0') {
575
- return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
576
- }
577
-
578
- $value = '';
579
- $current = $this->value;
580
-
581
- if ($current[0] == '-') {
582
- $current = substr($current, 1);
583
- }
584
-
585
- while (bccomp($current, '0', 0) > 0) {
586
- $temp = bcmod($current, '16777216');
587
- $value = chr($temp >> 16) . chr($temp >> 8) . chr($temp) . $value;
588
- $current = bcdiv($current, '16777216', 0);
589
- }
590
-
591
- return $this->precision > 0 ?
592
- substr(str_pad($value, $this->precision >> 3, chr(0), STR_PAD_LEFT), -($this->precision >> 3)) :
593
- ltrim($value, chr(0));
594
- }
595
-
596
- if (!count($this->value)) {
597
- return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
598
- }
599
- $result = $this->_int2bytes($this->value[count($this->value) - 1]);
600
-
601
- $temp = $this->copy();
602
-
603
- for ($i = count($temp->value) - 2; $i >= 0; --$i) {
604
- $temp->_base256_lshift($result, MATH_BIGINTEGER_BASE);
605
- $result = $result | str_pad($temp->_int2bytes($temp->value[$i]), strlen($result), chr(0), STR_PAD_LEFT);
606
- }
607
-
608
- return $this->precision > 0 ?
609
- str_pad(substr($result, -(($this->precision + 7) >> 3)), ($this->precision + 7) >> 3, chr(0), STR_PAD_LEFT) :
610
- $result;
611
- }
612
-
613
- /**
614
- * Converts a BigInteger to a hex string (eg. base-16)).
615
- *
616
- * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're
617
- * saved as two's compliment.
618
- *
619
- * Here's an example:
620
- * <code>
621
- * <?php
622
- * include 'Math/BigInteger.php';
623
- *
624
- * $a = new Math_BigInteger('65');
625
- *
626
- * echo $a->toHex(); // outputs '41'
627
- * ?>
628
- * </code>
629
- *
630
- * @param bool $twos_compliment
631
- * @return string
632
- * @access public
633
- * @internal Converts a base-2**26 number to base-2**8
634
- */
635
- function toHex($twos_compliment = false)
636
- {
637
- return bin2hex($this->toBytes($twos_compliment));
638
- }
639
-
640
- /**
641
- * Converts a BigInteger to a bit string (eg. base-2).
642
- *
643
- * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're
644
- * saved as two's compliment.
645
- *
646
- * Here's an example:
647
- * <code>
648
- * <?php
649
- * include 'Math/BigInteger.php';
650
- *
651
- * $a = new Math_BigInteger('65');
652
- *
653
- * echo $a->toBits(); // outputs '1000001'
654
- * ?>
655
- * </code>
656
- *
657
- * @param bool $twos_compliment
658
- * @return string
659
- * @access public
660
- * @internal Converts a base-2**26 number to base-2**2
661
- */
662
- function toBits($twos_compliment = false)
663
- {
664
- $hex = $this->toHex($twos_compliment);
665
- $bits = '';
666
- for ($i = strlen($hex) - 8, $start = strlen($hex) & 7; $i >= $start; $i-=8) {
667
- $bits = str_pad(decbin(hexdec(substr($hex, $i, 8))), 32, '0', STR_PAD_LEFT) . $bits;
668
- }
669
- if ($start) { // hexdec('') == 0
670
- $bits = str_pad(decbin(hexdec(substr($hex, 0, $start))), 8, '0', STR_PAD_LEFT) . $bits;
671
- }
672
- $result = $this->precision > 0 ? substr($bits, -$this->precision) : ltrim($bits, '0');
673
-
674
- if ($twos_compliment && $this->compare(new Math_BigInteger()) > 0 && $this->precision <= 0) {
675
- return '0' . $result;
676
- }
677
-
678
- return $result;
679
- }
680
-
681
- /**
682
- * Converts a BigInteger to a base-10 number.
683
- *
684
- * Here's an example:
685
- * <code>
686
- * <?php
687
- * include 'Math/BigInteger.php';
688
- *
689
- * $a = new Math_BigInteger('50');
690
- *
691
- * echo $a->toString(); // outputs 50
692
- * ?>
693
- * </code>
694
- *
695
- * @return string
696
- * @access public
697
- * @internal Converts a base-2**26 number to base-10**7 (which is pretty much base-10)
698
- */
699
- function toString()
700
- {
701
- switch (MATH_BIGINTEGER_MODE) {
702
- case MATH_BIGINTEGER_MODE_GMP:
703
- return gmp_strval($this->value);
704
- case MATH_BIGINTEGER_MODE_BCMATH:
705
- if ($this->value === '0') {
706
- return '0';
707
- }
708
-
709
- return ltrim($this->value, '0');
710
- }
711
-
712
- if (!count($this->value)) {
713
- return '0';
714
- }
715
-
716
- $temp = $this->copy();
717
- $temp->is_negative = false;
718
-
719
- $divisor = new Math_BigInteger();
720
- $divisor->value = array(MATH_BIGINTEGER_MAX10);
721
- $result = '';
722
- while (count($temp->value)) {
723
- list($temp, $mod) = $temp->divide($divisor);
724
- $result = str_pad(isset($mod->value[0]) ? $mod->value[0] : '', MATH_BIGINTEGER_MAX10_LEN, '0', STR_PAD_LEFT) . $result;
725
- }
726
- $result = ltrim($result, '0');
727
- if (empty($result)) {
728
- $result = '0';
729
- }
730
-
731
- if ($this->is_negative) {
732
- $result = '-' . $result;
733
- }
734
-
735
- return $result;
736
- }
737
-
738
- /**
739
- * Copy an object
740
- *
741
- * PHP5 passes objects by reference while PHP4 passes by value. As such, we need a function to guarantee
742
- * that all objects are passed by value, when appropriate. More information can be found here:
743
- *
744
- * {@link http://php.net/language.oop5.basic#51624}
745
- *
746
- * @access public
747
- * @see self::__clone()
748
- * @return Math_BigInteger
749
- */
750
- function copy()
751
- {
752
- $temp = new Math_BigInteger();
753
- $temp->value = $this->value;
754
- $temp->is_negative = $this->is_negative;
755
- $temp->precision = $this->precision;
756
- $temp->bitmask = $this->bitmask;
757
- return $temp;
758
- }
759
-
760
- /**
761
- * __toString() magic method
762
- *
763
- * Will be called, automatically, if you're supporting just PHP5. If you're supporting PHP4, you'll need to call
764
- * toString().
765
- *
766
- * @access public
767
- * @internal Implemented per a suggestion by Techie-Michael - thanks!
768
- */
769
- function __toString()
770
- {
771
- return $this->toString();
772
- }
773
-
774
- /**
775
- * __clone() magic method
776
- *
777
- * Although you can call Math_BigInteger::__toString() directly in PHP5, you cannot call Math_BigInteger::__clone()
778
- * directly in PHP5. You can in PHP4 since it's not a magic method, but in PHP5, you have to call it by using the PHP5
779
- * only syntax of $y = clone $x. As such, if you're trying to write an application that works on both PHP4 and PHP5,
780
- * call Math_BigInteger::copy(), instead.
781
- *
782
- * @access public
783
- * @see self::copy()
784
- * @return Math_BigInteger
785
- */
786
- function __clone()
787
- {
788
- return $this->copy();
789
- }
790
-
791
- /**
792
- * __sleep() magic method
793
- *
794
- * Will be called, automatically, when serialize() is called on a Math_BigInteger object.
795
- *
796
- * @see self::__wakeup()
797
- * @access public
798
- */
799
- function __sleep()
800
- {
801
- $this->hex = $this->toHex(true);
802
- $vars = array('hex');
803
- if ($this->precision > 0) {
804
- $vars[] = 'precision';
805
- }
806
- return $vars;
807
- }
808
-
809
- /**
810
- * __wakeup() magic method
811
- *
812
- * Will be called, automatically, when unserialize() is called on a Math_BigInteger object.
813
- *
814
- * @see self::__sleep()
815
- * @access public
816
- */
817
- function __wakeup()
818
- {
819
- $temp = new Math_BigInteger($this->hex, -16);
820
- $this->value = $temp->value;
821
- $this->is_negative = $temp->is_negative;
822
- if ($this->precision > 0) {
823
- // recalculate $this->bitmask
824
- $this->setPrecision($this->precision);
825
- }
826
- }
827
-
828
- /**
829
- * __debugInfo() magic method
830
- *
831
- * Will be called, automatically, when print_r() or var_dump() are called
832
- *
833
- * @access public
834
- */
835
- function __debugInfo()
836
- {
837
- $opts = array();
838
- switch (MATH_BIGINTEGER_MODE) {
839
- case MATH_BIGINTEGER_MODE_GMP:
840
- $engine = 'gmp';
841
- break;
842
- case MATH_BIGINTEGER_MODE_BCMATH:
843
- $engine = 'bcmath';
844
- break;
845
- case MATH_BIGINTEGER_MODE_INTERNAL:
846
- $engine = 'internal';
847
- $opts[] = PHP_INT_SIZE == 8 ? '64-bit' : '32-bit';
848
- }
849
- if (MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_GMP && defined('MATH_BIGINTEGER_OPENSSL_ENABLED')) {
850
- $opts[] = 'OpenSSL';
851
- }
852
- if (!empty($opts)) {
853
- $engine.= ' (' . implode($opts, ', ') . ')';
854
- }
855
- return array(
856
- 'value' => '0x' . $this->toHex(true),
857
- 'engine' => $engine
858
- );
859
- }
860
-
861
- /**
862
- * Adds two BigIntegers.
863
- *
864
- * Here's an example:
865
- * <code>
866
- * <?php
867
- * include 'Math/BigInteger.php';
868
- *
869
- * $a = new Math_BigInteger('10');
870
- * $b = new Math_BigInteger('20');
871
- *
872
- * $c = $a->add($b);
873
- *
874
- * echo $c->toString(); // outputs 30
875
- * ?>
876
- * </code>
877
- *
878
- * @param Math_BigInteger $y
879
- * @return Math_BigInteger
880
- * @access public
881
- * @internal Performs base-2**52 addition
882
- */
883
- function add($y)
884
- {
885
- switch (MATH_BIGINTEGER_MODE) {
886
- case MATH_BIGINTEGER_MODE_GMP:
887
- $temp = new Math_BigInteger();
888
- $temp->value = gmp_add($this->value, $y->value);
889
-
890
- return $this->_normalize($temp);
891
- case MATH_BIGINTEGER_MODE_BCMATH:
892
- $temp = new Math_BigInteger();
893
- $temp->value = bcadd($this->value, $y->value, 0);
894
-
895
- return $this->_normalize($temp);
896
- }
897
-
898
- $temp = $this->_add($this->value, $this->is_negative, $y->value, $y->is_negative);
899
-
900
- $result = new Math_BigInteger();
901
- $result->value = $temp[MATH_BIGINTEGER_VALUE];
902
- $result->is_negative = $temp[MATH_BIGINTEGER_SIGN];
903
-
904
- return $this->_normalize($result);
905
- }
906
-
907
- /**
908
- * Performs addition.
909
- *
910
- * @param array $x_value
911
- * @param bool $x_negative
912
- * @param array $y_value
913
- * @param bool $y_negative
914
- * @return array
915
- * @access private
916
- */
917
- function _add($x_value, $x_negative, $y_value, $y_negative)
918
- {
919
- $x_size = count($x_value);
920
- $y_size = count($y_value);
921
-
922
- if ($x_size == 0) {
923
- return array(
924
- MATH_BIGINTEGER_VALUE => $y_value,
925
- MATH_BIGINTEGER_SIGN => $y_negative
926
- );
927
- } elseif ($y_size == 0) {
928
- return array(
929
- MATH_BIGINTEGER_VALUE => $x_value,
930
- MATH_BIGINTEGER_SIGN => $x_negative
931
- );
932
- }
933
-
934
- // subtract, if appropriate
935
- if ($x_negative != $y_negative) {
936
- if ($x_value == $y_value) {
937
- return array(
938
- MATH_BIGINTEGER_VALUE => array(),
939
- MATH_BIGINTEGER_SIGN => false
940
- );
941
- }
942
-
943
- $temp = $this->_subtract($x_value, false, $y_value, false);
944
- $temp[MATH_BIGINTEGER_SIGN] = $this->_compare($x_value, false, $y_value, false) > 0 ?
945
- $x_negative : $y_negative;
946
-
947
- return $temp;
948
- }
949
-
950
- if ($x_size < $y_size) {
951
- $size = $x_size;
952
- $value = $y_value;
953
- } else {
954
- $size = $y_size;
955
- $value = $x_value;
956
- }
957
-
958
- $value[count($value)] = 0; // just in case the carry adds an extra digit
959
-
960
- $carry = 0;
961
- for ($i = 0, $j = 1; $j < $size; $i+=2, $j+=2) {
962
- $sum = $x_value[$j] * MATH_BIGINTEGER_BASE_FULL + $x_value[$i] + $y_value[$j] * MATH_BIGINTEGER_BASE_FULL + $y_value[$i] + $carry;
963
- $carry = $sum >= MATH_BIGINTEGER_MAX_DIGIT2; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1
964
- $sum = $carry ? $sum - MATH_BIGINTEGER_MAX_DIGIT2 : $sum;
965
-
966
- $temp = MATH_BIGINTEGER_BASE === 26 ? intval($sum / 0x4000000) : ($sum >> 31);
967
-
968
- $value[$i] = (int) ($sum - MATH_BIGINTEGER_BASE_FULL * $temp); // eg. a faster alternative to fmod($sum, 0x4000000)
969
- $value[$j] = $temp;
970
- }
971
-
972
- if ($j == $size) { // ie. if $y_size is odd
973
- $sum = $x_value[$i] + $y_value[$i] + $carry;
974
- $carry = $sum >= MATH_BIGINTEGER_BASE_FULL;
975
- $value[$i] = $carry ? $sum - MATH_BIGINTEGER_BASE_FULL : $sum;
976
- ++$i; // ie. let $i = $j since we've just done $value[$i]
977
- }
978
-
979
- if ($carry) {
980
- for (; $value[$i] == MATH_BIGINTEGER_MAX_DIGIT; ++$i) {
981
- $value[$i] = 0;
982
- }
983
- ++$value[$i];
984
- }
985
-
986
- return array(
987
- MATH_BIGINTEGER_VALUE => $this->_trim($value),
988
- MATH_BIGINTEGER_SIGN => $x_negative
989
- );
990
- }
991
-
992
- /**
993
- * Subtracts two BigIntegers.
994
- *
995
- * Here's an example:
996
- * <code>
997
- * <?php
998
- * include 'Math/BigInteger.php';
999
- *
1000
- * $a = new Math_BigInteger('10');
1001
- * $b = new Math_BigInteger('20');
1002
- *
1003
- * $c = $a->subtract($b);
1004
- *
1005
- * echo $c->toString(); // outputs -10
1006
- * ?>
1007
- * </code>
1008
- *
1009
- * @param Math_BigInteger $y
1010
- * @return Math_BigInteger
1011
- * @access public
1012
- * @internal Performs base-2**52 subtraction
1013
- */
1014
- function subtract($y)
1015
- {
1016
- switch (MATH_BIGINTEGER_MODE) {
1017
- case MATH_BIGINTEGER_MODE_GMP:
1018
- $temp = new Math_BigInteger();
1019
- $temp->value = gmp_sub($this->value, $y->value);
1020
-
1021
- return $this->_normalize($temp);
1022
- case MATH_BIGINTEGER_MODE_BCMATH:
1023
- $temp = new Math_BigInteger();
1024
- $temp->value = bcsub($this->value, $y->value, 0);
1025
-
1026
- return $this->_normalize($temp);
1027
- }
1028
-
1029
- $temp = $this->_subtract($this->value, $this->is_negative, $y->value, $y->is_negative);
1030
-
1031
- $result = new Math_BigInteger();
1032
- $result->value = $temp[MATH_BIGINTEGER_VALUE];
1033
- $result->is_negative = $temp[MATH_BIGINTEGER_SIGN];
1034
-
1035
- return $this->_normalize($result);
1036
- }
1037
-
1038
- /**
1039
- * Performs subtraction.
1040
- *
1041
- * @param array $x_value
1042
- * @param bool $x_negative
1043
- * @param array $y_value
1044
- * @param bool $y_negative
1045
- * @return array
1046
- * @access private
1047
- */
1048
- function _subtract($x_value, $x_negative, $y_value, $y_negative)
1049
- {
1050
- $x_size = count($x_value);
1051
- $y_size = count($y_value);
1052
-
1053
- if ($x_size == 0) {
1054
- return array(
1055
- MATH_BIGINTEGER_VALUE => $y_value,
1056
- MATH_BIGINTEGER_SIGN => !$y_negative
1057
- );
1058
- } elseif ($y_size == 0) {
1059
- return array(
1060
- MATH_BIGINTEGER_VALUE => $x_value,
1061
- MATH_BIGINTEGER_SIGN => $x_negative
1062
- );
1063
- }
1064
-
1065
- // add, if appropriate (ie. -$x - +$y or +$x - -$y)
1066
- if ($x_negative != $y_negative) {
1067
- $temp = $this->_add($x_value, false, $y_value, false);
1068
- $temp[MATH_BIGINTEGER_SIGN] = $x_negative;
1069
-
1070
- return $temp;
1071
- }
1072
-
1073
- $diff = $this->_compare($x_value, $x_negative, $y_value, $y_negative);
1074
-
1075
- if (!$diff) {
1076
- return array(
1077
- MATH_BIGINTEGER_VALUE => array(),
1078
- MATH_BIGINTEGER_SIGN => false
1079
- );
1080
- }
1081
-
1082
- // switch $x and $y around, if appropriate.
1083
- if ((!$x_negative && $diff < 0) || ($x_negative && $diff > 0)) {
1084
- $temp = $x_value;
1085
- $x_value = $y_value;
1086
- $y_value = $temp;
1087
-
1088
- $x_negative = !$x_negative;
1089
-
1090
- $x_size = count($x_value);
1091
- $y_size = count($y_value);
1092
- }
1093
-
1094
- // at this point, $x_value should be at least as big as - if not bigger than - $y_value
1095
-
1096
- $carry = 0;
1097
- for ($i = 0, $j = 1; $j < $y_size; $i+=2, $j+=2) {
1098
- $sum = $x_value[$j] * MATH_BIGINTEGER_BASE_FULL + $x_value[$i] - $y_value[$j] * MATH_BIGINTEGER_BASE_FULL - $y_value[$i] - $carry;
1099
- $carry = $sum < 0; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1
1100
- $sum = $carry ? $sum + MATH_BIGINTEGER_MAX_DIGIT2 : $sum;
1101
-
1102
- $temp = MATH_BIGINTEGER_BASE === 26 ? intval($sum / 0x4000000) : ($sum >> 31);
1103
-
1104
- $x_value[$i] = (int) ($sum - MATH_BIGINTEGER_BASE_FULL * $temp);
1105
- $x_value[$j] = $temp;
1106
- }
1107
-
1108
- if ($j == $y_size) { // ie. if $y_size is odd
1109
- $sum = $x_value[$i] - $y_value[$i] - $carry;
1110
- $carry = $sum < 0;
1111
- $x_value[$i] = $carry ? $sum + MATH_BIGINTEGER_BASE_FULL : $sum;
1112
- ++$i;
1113
- }
1114
-
1115
- if ($carry) {
1116
- for (; !$x_value[$i]; ++$i) {
1117
- $x_value[$i] = MATH_BIGINTEGER_MAX_DIGIT;
1118
- }
1119
- --$x_value[$i];
1120
- }
1121
-
1122
- return array(
1123
- MATH_BIGINTEGER_VALUE => $this->_trim($x_value),
1124
- MATH_BIGINTEGER_SIGN => $x_negative
1125
- );
1126
- }
1127
-
1128
- /**
1129
- * Multiplies two BigIntegers
1130
- *
1131
- * Here's an example:
1132
- * <code>
1133
- * <?php
1134
- * include 'Math/BigInteger.php';
1135
- *
1136
- * $a = new Math_BigInteger('10');
1137
- * $b = new Math_BigInteger('20');
1138
- *
1139
- * $c = $a->multiply($b);
1140
- *
1141
- * echo $c->toString(); // outputs 200
1142
- * ?>
1143
- * </code>
1144
- *
1145
- * @param Math_BigInteger $x
1146
- * @return Math_BigInteger
1147
- * @access public
1148
- */
1149
- function multiply($x)
1150
- {
1151
- switch (MATH_BIGINTEGER_MODE) {
1152
- case MATH_BIGINTEGER_MODE_GMP:
1153
- $temp = new Math_BigInteger();
1154
- $temp->value = gmp_mul($this->value, $x->value);
1155
-
1156
- return $this->_normalize($temp);
1157
- case MATH_BIGINTEGER_MODE_BCMATH:
1158
- $temp = new Math_BigInteger();
1159
- $temp->value = bcmul($this->value, $x->value, 0);
1160
-
1161
- return $this->_normalize($temp);
1162
- }
1163
-
1164
- $temp = $this->_multiply($this->value, $this->is_negative, $x->value, $x->is_negative);
1165
-
1166
- $product = new Math_BigInteger();
1167
- $product->value = $temp[MATH_BIGINTEGER_VALUE];
1168
- $product->is_negative = $temp[MATH_BIGINTEGER_SIGN];
1169
-
1170
- return $this->_normalize($product);
1171
- }
1172
-
1173
- /**
1174
- * Performs multiplication.
1175
- *
1176
- * @param array $x_value
1177
- * @param bool $x_negative
1178
- * @param array $y_value
1179
- * @param bool $y_negative
1180
- * @return array
1181
- * @access private
1182
- */
1183
- function _multiply($x_value, $x_negative, $y_value, $y_negative)
1184
- {
1185
- //if ( $x_value == $y_value ) {
1186
- // return array(
1187
- // MATH_BIGINTEGER_VALUE => $this->_square($x_value),
1188
- // MATH_BIGINTEGER_SIGN => $x_sign != $y_value
1189
- // );
1190
- //}
1191
-
1192
- $x_length = count($x_value);
1193
- $y_length = count($y_value);
1194
-
1195
- if (!$x_length || !$y_length) { // a 0 is being multiplied
1196
- return array(
1197
- MATH_BIGINTEGER_VALUE => array(),
1198
- MATH_BIGINTEGER_SIGN => false
1199
- );
1200
- }
1201
-
1202
- return array(
1203
- MATH_BIGINTEGER_VALUE => min($x_length, $y_length) < 2 * MATH_BIGINTEGER_KARATSUBA_CUTOFF ?
1204
- $this->_trim($this->_regularMultiply($x_value, $y_value)) :
1205
- $this->_trim($this->_karatsuba($x_value, $y_value)),
1206
- MATH_BIGINTEGER_SIGN => $x_negative != $y_negative
1207
- );
1208
- }
1209
-
1210
- /**
1211
- * Performs long multiplication on two BigIntegers
1212
- *
1213
- * Modeled after 'multiply' in MutableBigInteger.java.
1214
- *
1215
- * @param array $x_value
1216
- * @param array $y_value
1217
- * @return array
1218
- * @access private
1219
- */
1220
- function _regularMultiply($x_value, $y_value)
1221
- {
1222
- $x_length = count($x_value);
1223
- $y_length = count($y_value);
1224
-
1225
- if (!$x_length || !$y_length) { // a 0 is being multiplied
1226
- return array();
1227
- }
1228
-
1229
- if ($x_length < $y_length) {
1230
- $temp = $x_value;
1231
- $x_value = $y_value;
1232
- $y_value = $temp;
1233
-
1234
- $x_length = count($x_value);
1235
- $y_length = count($y_value);
1236
- }
1237
-
1238
- $product_value = $this->_array_repeat(0, $x_length + $y_length);
1239
-
1240
- // the following for loop could be removed if the for loop following it
1241
- // (the one with nested for loops) initially set $i to 0, but
1242
- // doing so would also make the result in one set of unnecessary adds,
1243
- // since on the outermost loops first pass, $product->value[$k] is going
1244
- // to always be 0
1245
-
1246
- $carry = 0;
1247
-
1248
- for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0
1249
- $temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0
1250
- $carry = MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
1251
- $product_value[$j] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
1252
- }
1253
-
1254
- $product_value[$j] = $carry;
1255
-
1256
- // the above for loop is what the previous comment was talking about. the
1257
- // following for loop is the "one with nested for loops"
1258
- for ($i = 1; $i < $y_length; ++$i) {
1259
- $carry = 0;
1260
-
1261
- for ($j = 0, $k = $i; $j < $x_length; ++$j, ++$k) {
1262
- $temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry;
1263
- $carry = MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
1264
- $product_value[$k] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
1265
- }
1266
-
1267
- $product_value[$k] = $carry;
1268
- }
1269
-
1270
- return $product_value;
1271
- }
1272
-
1273
- /**
1274
- * Performs Karatsuba multiplication on two BigIntegers
1275
- *
1276
- * See {@link http://en.wikipedia.org/wiki/Karatsuba_algorithm Karatsuba algorithm} and
1277
- * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=120 MPM 5.2.3}.
1278
- *
1279
- * @param array $x_value
1280
- * @param array $y_value
1281
- * @return array
1282
- * @access private
1283
- */
1284
- function _karatsuba($x_value, $y_value)
1285
- {
1286
- $m = min(count($x_value) >> 1, count($y_value) >> 1);
1287
-
1288
- if ($m < MATH_BIGINTEGER_KARATSUBA_CUTOFF) {
1289
- return $this->_regularMultiply($x_value, $y_value);
1290
- }
1291
-
1292
- $x1 = array_slice($x_value, $m);
1293
- $x0 = array_slice($x_value, 0, $m);
1294
- $y1 = array_slice($y_value, $m);
1295
- $y0 = array_slice($y_value, 0, $m);
1296
-
1297
- $z2 = $this->_karatsuba($x1, $y1);
1298
- $z0 = $this->_karatsuba($x0, $y0);
1299
-
1300
- $z1 = $this->_add($x1, false, $x0, false);
1301
- $temp = $this->_add($y1, false, $y0, false);
1302
- $z1 = $this->_karatsuba($z1[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_VALUE]);
1303
- $temp = $this->_add($z2, false, $z0, false);
1304
- $z1 = $this->_subtract($z1, false, $temp[MATH_BIGINTEGER_VALUE], false);
1305
-
1306
- $z2 = array_merge(array_fill(0, 2 * $m, 0), $z2);
1307
- $z1[MATH_BIGINTEGER_VALUE] = array_merge(array_fill(0, $m, 0), $z1[MATH_BIGINTEGER_VALUE]);
1308
-
1309
- $xy = $this->_add($z2, false, $z1[MATH_BIGINTEGER_VALUE], $z1[MATH_BIGINTEGER_SIGN]);
1310
- $xy = $this->_add($xy[MATH_BIGINTEGER_VALUE], $xy[MATH_BIGINTEGER_SIGN], $z0, false);
1311
-
1312
- return $xy[MATH_BIGINTEGER_VALUE];
1313
- }
1314
-
1315
- /**
1316
- * Performs squaring
1317
- *
1318
- * @param array $x
1319
- * @return array
1320
- * @access private
1321
- */
1322
- function _square($x = false)
1323
- {
1324
- return count($x) < 2 * MATH_BIGINTEGER_KARATSUBA_CUTOFF ?
1325
- $this->_trim($this->_baseSquare($x)) :
1326
- $this->_trim($this->_karatsubaSquare($x));
1327
- }
1328
-
1329
- /**
1330
- * Performs traditional squaring on two BigIntegers
1331
- *
1332
- * Squaring can be done faster than multiplying a number by itself can be. See
1333
- * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=7 HAC 14.2.4} /
1334
- * {@link http://math.libtomcrypt.com/files/tommat