WP Mail SMTP by WPForms - Version 1.5.2

Version Description

  • 2019-07-18 =
  • Fixed: "Redirect URI mismatch" error for "Gmail" mailer when trying to re-authorize an account that was initially created with version < v1.5.0.
  • Changed: Make "Authentication" setting in "Other SMTP" mailer ON by default for new users.
  • Changed: Mailers docs links now point to wpmailsmtp.com own site.
Download this release

Release Info

Developer slaFFik
Plugin Icon 128x128 WP Mail SMTP by WPForms
Version 1.5.2
Comparing to
See all releases

Code changes from version 1.5.1 to 1.5.2

Files changed (59) hide show
  1. assets/languages/wp-mail-smtp.pot +8 -4
  2. readme.txt +13 -6
  3. src/Admin/Area.php +1 -0
  4. src/Admin/PageAbstract.php +4 -0
  5. src/Admin/Pages/Test.php +1 -1
  6. src/Options.php +1 -0
  7. src/Providers/AuthAbstract.php +4 -0
  8. src/Providers/Gmail/Auth.php +27 -1
  9. src/Providers/Gmail/Options.php +1 -1
  10. src/Providers/Mailgun/Options.php +1 -1
  11. src/Providers/SMTP/Options.php +1 -1
  12. src/Providers/Sendgrid/Options.php +1 -1
  13. vendor/guzzlehttp/guzzle/LICENSE +19 -19
  14. vendor/guzzlehttp/guzzle/src/Client.php +422 -422
  15. vendor/guzzlehttp/guzzle/src/ClientInterface.php +84 -84
  16. vendor/guzzlehttp/guzzle/src/Cookie/CookieJar.php +314 -314
  17. vendor/guzzlehttp/guzzle/src/Cookie/CookieJarInterface.php +84 -84
  18. vendor/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php +90 -90
  19. vendor/guzzlehttp/guzzle/src/Cookie/SessionCookieJar.php +71 -71
  20. vendor/guzzlehttp/guzzle/src/Cookie/SetCookie.php +403 -403
  21. vendor/guzzlehttp/guzzle/src/Exception/BadResponseException.php +27 -27
  22. vendor/guzzlehttp/guzzle/src/Exception/ClientException.php +7 -7
  23. vendor/guzzlehttp/guzzle/src/Exception/ConnectException.php +37 -37
  24. vendor/guzzlehttp/guzzle/src/Exception/GuzzleException.php +13 -13
  25. vendor/guzzlehttp/guzzle/src/Exception/RequestException.php +217 -217
  26. vendor/guzzlehttp/guzzle/src/Exception/SeekException.php +27 -27
  27. vendor/guzzlehttp/guzzle/src/Exception/ServerException.php +7 -7
  28. vendor/guzzlehttp/guzzle/src/Exception/TooManyRedirectsException.php +4 -4
  29. vendor/guzzlehttp/guzzle/src/Exception/TransferException.php +4 -4
  30. vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php +565 -565
  31. vendor/guzzlehttp/guzzle/src/Handler/CurlFactoryInterface.php +27 -27
  32. vendor/guzzlehttp/guzzle/src/Handler/CurlHandler.php +45 -45
  33. vendor/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php +199 -199
  34. vendor/guzzlehttp/guzzle/src/Handler/EasyHandle.php +92 -92
  35. vendor/guzzlehttp/guzzle/src/Handler/MockHandler.php +189 -189
  36. vendor/guzzlehttp/guzzle/src/Handler/Proxy.php +55 -55
  37. vendor/guzzlehttp/guzzle/src/Handler/StreamHandler.php +532 -532
  38. vendor/guzzlehttp/guzzle/src/HandlerStack.php +273 -273
  39. vendor/guzzlehttp/guzzle/src/MessageFormatter.php +180 -180
  40. vendor/guzzlehttp/guzzle/src/Middleware.php +255 -255
  41. vendor/guzzlehttp/guzzle/src/Pool.php +123 -123
  42. vendor/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php +106 -106
  43. vendor/guzzlehttp/guzzle/src/RedirectMiddleware.php +237 -237
  44. vendor/guzzlehttp/guzzle/src/RequestOptions.php +255 -255
  45. vendor/guzzlehttp/guzzle/src/RetryMiddleware.php +112 -112
  46. vendor/guzzlehttp/guzzle/src/TransferStats.php +126 -126
  47. vendor/guzzlehttp/guzzle/src/UriTemplate.php +237 -237
  48. vendor/guzzlehttp/guzzle/src/functions.php +333 -333
  49. vendor/guzzlehttp/guzzle/src/functions_include.php +6 -6
  50. vendor/phpseclib/phpseclib/LICENSE +20 -21
  51. vendor/phpseclib/phpseclib/phpseclib/Crypt/AES.php +126 -126
  52. vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA.php +3201 -3201
  53. vendor/phpseclib/phpseclib/phpseclib/Crypt/Random.php +274 -274
  54. vendor/phpseclib/phpseclib/phpseclib/Crypt/Rijndael.php +936 -936
  55. vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger.php +3779 -3779
  56. vendor/phpseclib/phpseclib/phpseclib/bootstrap.php +16 -16
  57. vendor/phpseclib/phpseclib/phpseclib/openssl.cnf +6 -6
  58. vendor/phpseclib/phpseclib/travis/code_coverage_id_rsa +30 -0
  59. wp_mail_smtp.php +2 -2
assets/languages/wp-mail-smtp.pot CHANGED
@@ -1,13 +1,13 @@
1
  msgid ""
2
  msgstr ""
3
- "Project-Id-Version: WP Mail SMTP 1.5.0\n"
4
  "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/wp-mail-smtp\n"
5
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
6
  "Language-Team: LANGUAGE <LL@li.org>\n"
7
  "MIME-Version: 1.0\n"
8
  "Content-Type: text/plain; charset=UTF-8\n"
9
  "Content-Transfer-Encoding: 8bit\n"
10
- "POT-Creation-Date: 2019-07-12T17:44:13+03:00\n"
11
  "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
12
  "X-Generator: WP-CLI 2.2.0\n"
13
  "X-Domain: wp-mail-smtp\n"
@@ -128,7 +128,7 @@ msgstr ""
128
  msgid "WP Mail SMTP Pro related message was successfully dismissed."
129
  msgstr ""
130
 
131
- #: src/Admin/PageAbstract.php:77
132
  msgid "Save Settings"
133
  msgstr ""
134
 
@@ -733,7 +733,7 @@ msgid "This means the connection to your SMTP host was made successfully, but th
733
  msgstr ""
734
 
735
  #: src/Admin/Pages/Test.php:600
736
- msgid "Typically this error is returned when your are sending too many e-mails or e-mails that have been identified as spam."
737
  msgstr ""
738
 
739
  #: src/Admin/Pages/Test.php:603
@@ -1086,6 +1086,10 @@ msgstr ""
1086
  msgid "Consider running an email test after fixing it."
1087
  msgstr ""
1088
 
 
 
 
 
1089
  #: src/Providers/Gmail/Options.php:32
1090
  msgid "Gmail"
1091
  msgstr ""
1
  msgid ""
2
  msgstr ""
3
+ "Project-Id-Version: WP Mail SMTP 1.5.2\n"
4
  "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/wp-mail-smtp\n"
5
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
6
  "Language-Team: LANGUAGE <LL@li.org>\n"
7
  "MIME-Version: 1.0\n"
8
  "Content-Type: text/plain; charset=UTF-8\n"
9
  "Content-Transfer-Encoding: 8bit\n"
10
+ "POT-Creation-Date: 2019-07-18T11:22:11+03:00\n"
11
  "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
12
  "X-Generator: WP-CLI 2.2.0\n"
13
  "X-Domain: wp-mail-smtp\n"
128
  msgid "WP Mail SMTP Pro related message was successfully dismissed."
129
  msgstr ""
130
 
131
+ #: src/Admin/PageAbstract.php:81
132
  msgid "Save Settings"
133
  msgstr ""
134
 
733
  msgstr ""
734
 
735
  #: src/Admin/Pages/Test.php:600
736
+ msgid "Typically this error is returned when you are sending too many e-mails or e-mails that have been identified as spam."
737
  msgstr ""
738
 
739
  #: src/Admin/Pages/Test.php:603
1086
  msgid "Consider running an email test after fixing it."
1087
  msgstr ""
1088
 
1089
+ #: src/Providers/Gmail/Auth.php:170
1090
+ msgid "There was an error while processing the Google authentication request. Please make sure that you have Client ID and Client Secret both valid and saved."
1091
+ msgstr ""
1092
+
1093
  #: src/Providers/Gmail/Options.php:32
1094
  msgid "Gmail"
1095
  msgstr ""
readme.txt CHANGED
@@ -3,7 +3,7 @@ Contributors: wpforms, jaredatch, smub, slaFFik
3
  Tags: smtp, wp mail smtp, wordpress smtp, gmail smtp, sendgrid smtp, mailgun smtp, mail, mailer, phpmailer, wp_mail, email, mailgun, sengrid, gmail, wp smtp
4
  Requires at least: 4.9
5
  Tested up to: 5.2
6
- Stable tag: 1.5.1
7
  Requires PHP: 5.3
8
 
9
  The most popular WordPress SMTP and PHP Mailer plugin. Trusted by over 1 million sites.
@@ -12,7 +12,7 @@ The most popular WordPress SMTP and PHP Mailer plugin. Trusted by over 1 million
12
 
13
  ### WordPress Mail SMTP Plugin
14
 
15
- Having problems with your WordPress site not sending emails? You're not alone. Over 1 million websites use WP Mail SMTP to send their emails reliabily.
16
 
17
  Our goal is to make email deliverability easy and reliable. We want to ensure your emails reach the inbox.
18
 
@@ -59,7 +59,7 @@ Mailgun SMTP is a popular SMTP service provider that allows you to send large qu
59
 
60
  WP Mail SMTP plugin offers a native integration with MailGun. All you have to do is connect your Mailgun account, and you will improve your email deliverability.
61
 
62
- Read our <a href="https://wpforms.com/how-to-send-wordpress-emails-with-mailgun/" rel="friend">Mailgun documentation</a> for more details.
63
 
64
  = Gmail SMTP =
65
 
@@ -69,13 +69,13 @@ This allows you to use your <a href="http://www.wpbeginner.com/beginners-guide/h
69
 
70
  Unlike other Gmail SMTP plugins, our Gmail SMTP option uses OAuth to authenticate your Google account, keeping your login information 100% secure.
71
 
72
- Read our <a href="https://wpforms.com/how-to-securely-send-wordpress-emails-using-gmail-smtp/" rel="friend">Gmail documentation</a> for more details.
73
 
74
  = SendGrid SMTP =
75
 
76
  SendGrid has a free SMTP plan that you can use to send up to 100 emails per day. With our native SendGrid SMTP integration, you can easily and securely set up SendGrid SMTP on your WordPress site.
77
 
78
- Read our <a href="https://wpforms.com/fix-wordpress-email-notifications-with-sendgrid/" rel="friend">SendGrid documentation</a> for more details.
79
 
80
  = Microsoft SMTP (Outlook.com and Office 365) =
81
 
@@ -85,6 +85,8 @@ Many business use Outlook.com or Office 365 to their to power their email. For t
85
 
86
  Advanced or technical users can harness the power of Amazon AWS (Amazon Web Services) with the Amazon SES mailer. With this integration, you can send a high volume of emails at a very reasonable rate.
87
 
 
 
88
  = Other SMTP =
89
 
90
  WP Mail SMTP plugin also works with all major email services such as Gmail, Yahoo, Outlook, Microsoft Live, and any other email sending service that offers SMTP.
@@ -97,7 +99,7 @@ You can set the following options:
97
  * Choose to use SMTP authentication or not.
98
  * Specify an SMTP username and password.
99
 
100
- To see recommended settings for the popular services as well as troubleshooting tips, check out our <a href="https://wpforms.com/docs/how-to-set-up-smtp-using-the-wp-mail-smtp-plugin/" rel="friend">SMTP documentation</a>.
101
 
102
  We hope that you find WP Mail SMTP plugin helpful!
103
 
@@ -195,6 +197,11 @@ By all means please contact us to discuss features or options you'd like to see
195
 
196
  == Changelog ==
197
 
 
 
 
 
 
198
  = 1.5.1 - 2019-07-12 =
199
  * Fixed: Duplicated emails sent to the first recipient in a loop (and others not receiving their emails).
200
 
3
  Tags: smtp, wp mail smtp, wordpress smtp, gmail smtp, sendgrid smtp, mailgun smtp, mail, mailer, phpmailer, wp_mail, email, mailgun, sengrid, gmail, wp smtp
4
  Requires at least: 4.9
5
  Tested up to: 5.2
6
+ Stable tag: 1.5.2
7
  Requires PHP: 5.3
8
 
9
  The most popular WordPress SMTP and PHP Mailer plugin. Trusted by over 1 million sites.
12
 
13
  ### WordPress Mail SMTP Plugin
14
 
15
+ Having problems with your WordPress site not sending emails? You're not alone. Over 1 million websites use WP Mail SMTP to send their emails reliably.
16
 
17
  Our goal is to make email deliverability easy and reliable. We want to ensure your emails reach the inbox.
18
 
59
 
60
  WP Mail SMTP plugin offers a native integration with MailGun. All you have to do is connect your Mailgun account, and you will improve your email deliverability.
61
 
62
+ Read our <a href="https://wpmailsmtp.com/docs/how-to-set-up-the-mailgun-mailer-in-wp-mail-smtp/" rel="friend">Mailgun documentation</a> for more details.
63
 
64
  = Gmail SMTP =
65
 
69
 
70
  Unlike other Gmail SMTP plugins, our Gmail SMTP option uses OAuth to authenticate your Google account, keeping your login information 100% secure.
71
 
72
+ Read our <a href="https://wpmailsmtp.com/docs/how-to-set-up-the-gmail-mailer-in-wp-mail-smtp/" rel="friend">Gmail documentation</a> for more details.
73
 
74
  = SendGrid SMTP =
75
 
76
  SendGrid has a free SMTP plan that you can use to send up to 100 emails per day. With our native SendGrid SMTP integration, you can easily and securely set up SendGrid SMTP on your WordPress site.
77
 
78
+ Read our <a href="https://wpmailsmtp.com/docs/how-to-set-up-the-sendgrid-mailer-in-wp-mail-smtp/" rel="friend">SendGrid documentation</a> for more details.
79
 
80
  = Microsoft SMTP (Outlook.com and Office 365) =
81
 
85
 
86
  Advanced or technical users can harness the power of Amazon AWS (Amazon Web Services) with the Amazon SES mailer. With this integration, you can send a high volume of emails at a very reasonable rate.
87
 
88
+ Read our <a href="https://wpmailsmtp.com/docs/how-to-set-up-the-amazon-ses-mailer-in-wp-mail-smtp/" rel="friend">Amazon SES documentation</a> for more details.
89
+
90
  = Other SMTP =
91
 
92
  WP Mail SMTP plugin also works with all major email services such as Gmail, Yahoo, Outlook, Microsoft Live, and any other email sending service that offers SMTP.
99
  * Choose to use SMTP authentication or not.
100
  * Specify an SMTP username and password.
101
 
102
+ To see recommended settings for the popular services as well as troubleshooting tips, check out our <a href="https://wpmailsmtp.com/docs/how-to-set-up-the-other-smtp-mailer-in-wp-mail-smtp/" rel="friend">SMTP documentation</a>.
103
 
104
  We hope that you find WP Mail SMTP plugin helpful!
105
 
197
 
198
  == Changelog ==
199
 
200
+ = 1.5.2 - 2019-07-18 =
201
+ * Fixed: "Redirect URI mismatch" error for "Gmail" mailer when trying to re-authorize an account that was initially created with version < v1.5.0.
202
+ * Changed: Make "Authentication" setting in "Other SMTP" mailer ON by default for new users.
203
+ * Changed: Mailers docs links now point to wpmailsmtp.com own site.
204
+
205
  = 1.5.1 - 2019-07-12 =
206
  * Fixed: Duplicated emails sent to the first recipient in a loop (and others not receiving their emails).
207
 
src/Admin/Area.php CHANGED
@@ -731,6 +731,7 @@ class Area {
731
  * Get plugin admin area page URL.
732
  *
733
  * @since 1.0.0
 
734
  *
735
  * @param string $page
736
  *
731
  * Get plugin admin area page URL.
732
  *
733
  * @since 1.0.0
734
+ * @since 1.5.0 URL is changed to support the top level position of the plugin admin area.
735
  *
736
  * @param string $page
737
  *
src/Admin/PageAbstract.php CHANGED
@@ -18,6 +18,7 @@ abstract class PageAbstract implements PageInterface {
18
  * @inheritdoc
19
  */
20
  public function get_link() {
 
21
  return esc_url(
22
  add_query_arg(
23
  'tab',
@@ -51,6 +52,7 @@ abstract class PageAbstract implements PageInterface {
51
  * @since 1.0.0
52
  */
53
  public function wp_nonce_field() {
 
54
  wp_nonce_field( Area::SLUG . '-' . $this->slug );
55
  }
56
 
@@ -61,6 +63,7 @@ abstract class PageAbstract implements PageInterface {
61
  * @since 1.0.0
62
  */
63
  public function check_admin_referer() {
 
64
  check_admin_referer( Area::SLUG . '-' . $this->slug );
65
  }
66
 
@@ -70,6 +73,7 @@ abstract class PageAbstract implements PageInterface {
70
  * @since 1.5.0
71
  */
72
  public function display_save_btn() {
 
73
  ?>
74
 
75
  <p class="wp-mail-smtp-submit">
18
  * @inheritdoc
19
  */
20
  public function get_link() {
21
+
22
  return esc_url(
23
  add_query_arg(
24
  'tab',
52
  * @since 1.0.0
53
  */
54
  public function wp_nonce_field() {
55
+
56
  wp_nonce_field( Area::SLUG . '-' . $this->slug );
57
  }
58
 
63
  * @since 1.0.0
64
  */
65
  public function check_admin_referer() {
66
+
67
  check_admin_referer( Area::SLUG . '-' . $this->slug );
68
  }
69
 
73
  * @since 1.5.0
74
  */
75
  public function display_save_btn() {
76
+
77
  ?>
78
 
79
  <p class="wp-mail-smtp-submit">
src/Admin/Pages/Test.php CHANGED
@@ -597,7 +597,7 @@ Lead Developer, WP Mail SMTP';
597
  'description' => array(
598
  '<strong>' . esc_html__( 'Error due to unsolicited and/or bulk e-mail.', 'wp-mail-smtp' ) . '</strong>',
599
  esc_html__( 'This means the connection to your SMTP host was made successfully, but the host rejected the email.', 'wp-mail-smtp' ),
600
- esc_html__( 'Typically this error is returned when your are sending too many e-mails or e-mails that have been identified as spam.', 'wp-mail-smtp' ),
601
  ),
602
  'steps' => array(
603
  esc_html__( 'Check the emails that are sending are sending individually. Example: email is not sending to 30 recipients. You can install any WordPress e-mail logging plugin to do that.', 'wp-mail-smtp' ),
597
  'description' => array(
598
  '<strong>' . esc_html__( 'Error due to unsolicited and/or bulk e-mail.', 'wp-mail-smtp' ) . '</strong>',
599
  esc_html__( 'This means the connection to your SMTP host was made successfully, but the host rejected the email.', 'wp-mail-smtp' ),
600
+ esc_html__( 'Typically this error is returned when you are sending too many e-mails or e-mails that have been identified as spam.', 'wp-mail-smtp' ),
601
  ),
602
  'steps' => array(
603
  esc_html__( 'Check the emails that are sending are sending individually. Example: email is not sending to 30 recipients. You can install any WordPress e-mail logging plugin to do that.', 'wp-mail-smtp' ),
src/Options.php CHANGED
@@ -146,6 +146,7 @@ class Options {
146
  ),
147
  'smtp' => array(
148
  'autotls' => true,
 
149
  ),
150
  );
151
  }
146
  ),
147
  'smtp' => array(
148
  'autotls' => true,
149
+ 'auth' => true,
150
  ),
151
  );
152
  }
src/Providers/AuthAbstract.php CHANGED
@@ -51,6 +51,7 @@ abstract class AuthAbstract implements AuthInterface {
51
  * @since 1.0.0
52
  */
53
  protected function include_vendor_lib() {
 
54
  require_once wp_mail_smtp()->plugin_path . '/vendor/autoload.php';
55
  }
56
 
@@ -62,6 +63,7 @@ abstract class AuthAbstract implements AuthInterface {
62
  * @return string
63
  */
64
  public static function get_plugin_auth_url() {
 
65
  return add_query_arg( 'tab', 'auth', wp_mail_smtp()->get_admin()->get_admin_page_url() );
66
  }
67
 
@@ -132,6 +134,7 @@ abstract class AuthAbstract implements AuthInterface {
132
  * @inheritdoc
133
  */
134
  public function is_clients_saved() {
 
135
  return ! empty( $this->options['client_id'] ) && ! empty( $this->options['client_secret'] );
136
  }
137
 
@@ -139,6 +142,7 @@ abstract class AuthAbstract implements AuthInterface {
139
  * @inheritdoc
140
  */
141
  public function is_auth_required() {
 
142
  return empty( $this->options['access_token'] ) || empty( $this->options['refresh_token'] );
143
  }
144
  }
51
  * @since 1.0.0
52
  */
53
  protected function include_vendor_lib() {
54
+
55
  require_once wp_mail_smtp()->plugin_path . '/vendor/autoload.php';
56
  }
57
 
63
  * @return string
64
  */
65
  public static function get_plugin_auth_url() {
66
+
67
  return add_query_arg( 'tab', 'auth', wp_mail_smtp()->get_admin()->get_admin_page_url() );
68
  }
69
 
134
  * @inheritdoc
135
  */
136
  public function is_clients_saved() {
137
+
138
  return ! empty( $this->options['client_id'] ) && ! empty( $this->options['client_secret'] );
139
  }
140
 
142
  * @inheritdoc
143
  */
144
  public function is_auth_required() {
145
+
146
  return empty( $this->options['access_token'] ) || empty( $this->options['refresh_token'] );
147
  }
148
  }
src/Providers/Gmail/Auth.php CHANGED
@@ -2,6 +2,7 @@
2
 
3
  namespace WPMailSMTP\Providers\Gmail;
4
 
 
5
  use WPMailSMTP\Debug;
6
  use WPMailSMTP\Options as PluginOptions;
7
  use WPMailSMTP\Providers\AuthAbstract;
@@ -37,6 +38,24 @@ class Auth extends AuthAbstract {
37
  }
38
  }
39
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
  /**
41
  * Init and get the Google Client object.
42
  *
@@ -140,9 +159,16 @@ class Auth extends AuthAbstract {
140
  */
141
  public function process() {
142
 
 
 
 
 
 
143
  // We can't process without saved client_id/secret.
144
  if ( ! $this->is_clients_saved() ) {
145
- Debug::set( 'There was an error while processing the Google authentication request. Please make sure that you have Client ID and Client Secret both valid and saved.' );
 
 
146
  wp_safe_redirect(
147
  add_query_arg(
148
  'error',
2
 
3
  namespace WPMailSMTP\Providers\Gmail;
4
 
5
+ use WPMailSMTP\Admin\Area;
6
  use WPMailSMTP\Debug;
7
  use WPMailSMTP\Options as PluginOptions;
8
  use WPMailSMTP\Providers\AuthAbstract;
38
  }
39
  }
40
 
41
+ /**
42
+ * Get the url, that users will be redirected back to finish the OAuth process.
43
+ *
44
+ * @since 1.5.2 Returned to the old, pre-1.5, structure of the link to preserve BC.
45
+ *
46
+ * @return string
47
+ */
48
+ public static function get_plugin_auth_url() {
49
+
50
+ return add_query_arg(
51
+ array(
52
+ 'page' => Area::SLUG,
53
+ 'tab' => 'auth',
54
+ ),
55
+ admin_url( 'options-general.php' )
56
+ );
57
+ }
58
+
59
  /**
60
  * Init and get the Google Client object.
61
  *
159
  */
160
  public function process() {
161
 
162
+ if ( ! ( isset( $_GET['tab'] ) && $_GET['tab'] === 'auth' ) ) {
163
+ wp_safe_redirect( wp_mail_smtp()->get_admin()->get_admin_page_url() );
164
+ exit;
165
+ }
166
+
167
  // We can't process without saved client_id/secret.
168
  if ( ! $this->is_clients_saved() ) {
169
+ Debug::set(
170
+ esc_html__( 'There was an error while processing the Google authentication request. Please make sure that you have Client ID and Client Secret both valid and saved.', 'wp-mail-smtp' )
171
+ );
172
  wp_safe_redirect(
173
  add_query_arg(
174
  'error',
src/Providers/Gmail/Options.php CHANGED
@@ -43,7 +43,7 @@ class Options extends OptionsAbstract {
43
  ),
44
  )
45
  ),
46
- '<a href="https://wpforms.com/how-to-securely-send-wordpress-emails-using-gmail-smtp/" target="_blank" rel="noopener noreferrer">',
47
  '</a>'
48
  ),
49
  'php' => '5.5',
43
  ),
44
  )
45
  ),
46
+ '<a href="https://wpmailsmtp.com/docs/how-to-set-up-the-gmail-mailer-in-wp-mail-smtp/" target="_blank" rel="noopener noreferrer">',
47
  '</a>'
48
  ),
49
  'php' => '5.5',
src/Providers/Mailgun/Options.php CHANGED
@@ -38,7 +38,7 @@ class Options extends OptionsAbstract {
38
  ),
39
  '<a href="https://www.mailgun.com" target="_blank" rel="noopener noreferrer">',
40
  '</a>',
41
- '<a href="https://wpforms.com/how-to-send-wordpress-emails-with-mailgun/" target="_blank" rel="noopener noreferrer">',
42
  '</a>'
43
  ),
44
  )
38
  ),
39
  '<a href="https://www.mailgun.com" target="_blank" rel="noopener noreferrer">',
40
  '</a>',
41
+ '<a href="https://wpmailsmtp.com/docs/how-to-set-up-the-mailgun-mailer-in-wp-mail-smtp/" target="_blank" rel="noopener noreferrer">',
42
  '</a>'
43
  ),
44
  )
src/Providers/SMTP/Options.php CHANGED
@@ -36,7 +36,7 @@ class Options extends OptionsAbstract {
36
  ),
37
  )
38
  ),
39
- 'https://wpforms.com/docs/how-to-set-up-smtp-using-the-wp-mail-smtp-plugin/'
40
  ),
41
  )
42
  );
36
  ),
37
  )
38
  ),
39
+ 'https://wpmailsmtp.com/docs/how-to-set-up-the-other-smtp-mailer-in-wp-mail-smtp/'
40
  ),
41
  )
42
  );
src/Providers/Sendgrid/Options.php CHANGED
@@ -38,7 +38,7 @@ class Options extends OptionsAbstract {
38
  ),
39
  '<a href="https://sendgrid.com" target="_blank" rel="noopener noreferrer">',
40
  '</a>',
41
- '<a href="https://wpforms.com/fix-wordpress-email-notifications-with-sendgrid/" target="_blank" rel="noopener noreferrer">',
42
  '</a>'
43
  ),
44
  )
38
  ),
39
  '<a href="https://sendgrid.com" target="_blank" rel="noopener noreferrer">',
40
  '</a>',
41
+ '<a href="https://wpmailsmtp.com/docs/how-to-set-up-the-sendgrid-mailer-in-wp-mail-smtp/" target="_blank" rel="noopener noreferrer">',
42
  '</a>'
43
  ),
44
  )
vendor/guzzlehttp/guzzle/LICENSE CHANGED
@@ -1,19 +1,19 @@
1
- Copyright (c) 2011-2018 Michael Dowling, https://github.com/mtdowling <mtdowling@gmail.com>
2
-
3
- Permission is hereby granted, free of charge, to any person obtaining a copy
4
- of this software and associated documentation files (the "Software"), to deal
5
- in the Software without restriction, including without limitation the rights
6
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
- copies of the Software, and to permit persons to whom the Software is
8
- furnished to do so, subject to the following conditions:
9
-
10
- The above copyright notice and this permission notice shall be included in
11
- all copies or substantial portions of the Software.
12
-
13
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
- THE SOFTWARE.
1
+ Copyright (c) 2011-2018 Michael Dowling, https://github.com/mtdowling <mtdowling@gmail.com>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
vendor/guzzlehttp/guzzle/src/Client.php CHANGED
@@ -1,422 +1,422 @@
1
- <?php
2
- namespace GuzzleHttp;
3
-
4
- use GuzzleHttp\Cookie\CookieJar;
5
- use GuzzleHttp\Promise;
6
- use GuzzleHttp\Psr7;
7
- use Psr\Http\Message\UriInterface;
8
- use Psr\Http\Message\RequestInterface;
9
- use Psr\Http\Message\ResponseInterface;
10
-
11
- /**
12
- * @method ResponseInterface get(string|UriInterface $uri, array $options = [])
13
- * @method ResponseInterface head(string|UriInterface $uri, array $options = [])
14
- * @method ResponseInterface put(string|UriInterface $uri, array $options = [])
15
- * @method ResponseInterface post(string|UriInterface $uri, array $options = [])
16
- * @method ResponseInterface patch(string|UriInterface $uri, array $options = [])
17
- * @method ResponseInterface delete(string|UriInterface $uri, array $options = [])
18
- * @method Promise\PromiseInterface getAsync(string|UriInterface $uri, array $options = [])
19
- * @method Promise\PromiseInterface headAsync(string|UriInterface $uri, array $options = [])
20
- * @method Promise\PromiseInterface putAsync(string|UriInterface $uri, array $options = [])
21
- * @method Promise\PromiseInterface postAsync(string|UriInterface $uri, array $options = [])
22
- * @method Promise\PromiseInterface patchAsync(string|UriInterface $uri, array $options = [])
23
- * @method Promise\PromiseInterface deleteAsync(string|UriInterface $uri, array $options = [])
24
- */
25
- class Client implements ClientInterface
26
- {
27
- /** @var array Default request options */
28
- private $config;
29
-
30
- /**
31
- * Clients accept an array of constructor parameters.
32
- *
33
- * Here's an example of creating a client using a base_uri and an array of
34
- * default request options to apply to each request:
35
- *
36
- * $client = new Client([
37
- * 'base_uri' => 'http://www.foo.com/1.0/',
38
- * 'timeout' => 0,
39
- * 'allow_redirects' => false,
40
- * 'proxy' => '192.168.16.1:10'
41
- * ]);
42
- *
43
- * Client configuration settings include the following options:
44
- *
45
- * - handler: (callable) Function that transfers HTTP requests over the
46
- * wire. The function is called with a Psr7\Http\Message\RequestInterface
47
- * and array of transfer options, and must return a
48
- * GuzzleHttp\Promise\PromiseInterface that is fulfilled with a
49
- * Psr7\Http\Message\ResponseInterface on success. "handler" is a
50
- * constructor only option that cannot be overridden in per/request
51
- * options. If no handler is provided, a default handler will be created
52
- * that enables all of the request options below by attaching all of the
53
- * default middleware to the handler.
54
- * - base_uri: (string|UriInterface) Base URI of the client that is merged
55
- * into relative URIs. Can be a string or instance of UriInterface.
56
- * - **: any request option
57
- *
58
- * @param array $config Client configuration settings.
59
- *
60
- * @see \GuzzleHttp\RequestOptions for a list of available request options.
61
- */
62
- public function __construct(array $config = [])
63
- {
64
- if (!isset($config['handler'])) {
65
- $config['handler'] = HandlerStack::create();
66
- } elseif (!is_callable($config['handler'])) {
67
- throw new \InvalidArgumentException('handler must be a callable');
68
- }
69
-
70
- // Convert the base_uri to a UriInterface
71
- if (isset($config['base_uri'])) {
72
- $config['base_uri'] = Psr7\uri_for($config['base_uri']);
73
- }
74
-
75
- $this->configureDefaults($config);
76
- }
77
-
78
- public function __call($method, $args)
79
- {
80
- if (count($args) < 1) {
81
- throw new \InvalidArgumentException('Magic request methods require a URI and optional options array');
82
- }
83
-
84
- $uri = $args[0];
85
- $opts = isset($args[1]) ? $args[1] : [];
86
-
87
- return substr($method, -5) === 'Async'
88
- ? $this->requestAsync(substr($method, 0, -5), $uri, $opts)
89
- : $this->request($method, $uri, $opts);
90
- }
91
-
92
- public function sendAsync(RequestInterface $request, array $options = [])
93
- {
94
- // Merge the base URI into the request URI if needed.
95
- $options = $this->prepareDefaults($options);
96
-
97
- return $this->transfer(
98
- $request->withUri($this->buildUri($request->getUri(), $options), $request->hasHeader('Host')),
99
- $options
100
- );
101
- }
102
-
103
- public function send(RequestInterface $request, array $options = [])
104
- {
105
- $options[RequestOptions::SYNCHRONOUS] = true;
106
- return $this->sendAsync($request, $options)->wait();
107
- }
108
-
109
- public function requestAsync($method, $uri = '', array $options = [])
110
- {
111
- $options = $this->prepareDefaults($options);
112
- // Remove request modifying parameter because it can be done up-front.
113
- $headers = isset($options['headers']) ? $options['headers'] : [];
114
- $body = isset($options['body']) ? $options['body'] : null;
115
- $version = isset($options['version']) ? $options['version'] : '1.1';
116
- // Merge the URI into the base URI.
117
- $uri = $this->buildUri($uri, $options);
118
- if (is_array($body)) {
119
- $this->invalidBody();
120
- }
121
- $request = new Psr7\Request($method, $uri, $headers, $body, $version);
122
- // Remove the option so that they are not doubly-applied.
123
- unset($options['headers'], $options['body'], $options['version']);
124
-
125
- return $this->transfer($request, $options);
126
- }
127
-
128
- public function request($method, $uri = '', array $options = [])
129
- {
130
- $options[RequestOptions::SYNCHRONOUS] = true;
131
- return $this->requestAsync($method, $uri, $options)->wait();
132
- }
133
-
134
- public function getConfig($option = null)
135
- {
136
- return $option === null
137
- ? $this->config
138
- : (isset($this->config[$option]) ? $this->config[$option] : null);
139
- }
140
-
141
- private function buildUri($uri, array $config)
142
- {
143
- // for BC we accept null which would otherwise fail in uri_for
144
- $uri = Psr7\uri_for($uri === null ? '' : $uri);
145
-
146
- if (isset($config['base_uri'])) {
147
- $uri = Psr7\UriResolver::resolve(Psr7\uri_for($config['base_uri']), $uri);
148
- }
149
-
150
- return $uri->getScheme() === '' && $uri->getHost() !== '' ? $uri->withScheme('http') : $uri;
151
- }
152
-
153
- /**
154
- * Configures the default options for a client.
155
- *
156
- * @param array $config
157
- */
158
- private function configureDefaults(array $config)
159
- {
160
- $defaults = [
161
- 'allow_redirects' => RedirectMiddleware::$defaultSettings,
162
- 'http_errors' => true,
163
- 'decode_content' => true,
164
- 'verify' => true,
165
- 'cookies' => false
166
- ];
167
-
168
- // Use the standard Linux HTTP_PROXY and HTTPS_PROXY if set.
169
-
170
- // We can only trust the HTTP_PROXY environment variable in a CLI
171
- // process due to the fact that PHP has no reliable mechanism to
172
- // get environment variables that start with "HTTP_".
173
- if (php_sapi_name() == 'cli' && getenv('HTTP_PROXY')) {
174
- $defaults['proxy']['http'] = getenv('HTTP_PROXY');
175
- }
176
-
177
- if ($proxy = getenv('HTTPS_PROXY')) {
178
- $defaults['proxy']['https'] = $proxy;
179
- }
180
-
181
- if ($noProxy = getenv('NO_PROXY')) {
182
- $cleanedNoProxy = str_replace(' ', '', $noProxy);
183
- $defaults['proxy']['no'] = explode(',', $cleanedNoProxy);
184
- }
185
-
186
- $this->config = $config + $defaults;
187
-
188
- if (!empty($config['cookies']) && $config['cookies'] === true) {
189
- $this->config['cookies'] = new CookieJar();
190
- }
191
-
192
- // Add the default user-agent header.
193
- if (!isset($this->config['headers'])) {
194
- $this->config['headers'] = ['User-Agent' => default_user_agent()];
195
- } else {
196
- // Add the User-Agent header if one was not already set.
197
- foreach (array_keys($this->config['headers']) as $name) {
198
- if (strtolower($name) === 'user-agent') {
199
- return;
200
- }
201
- }
202
- $this->config['headers']['User-Agent'] = default_user_agent();
203
- }
204
- }
205
-
206
- /**
207
- * Merges default options into the array.
208
- *
209
- * @param array $options Options to modify by reference
210
- *
211
- * @return array
212
- */
213
- private function prepareDefaults($options)
214
- {
215
- $defaults = $this->config;
216
-
217
- if (!empty($defaults['headers'])) {
218
- // Default headers are only added if they are not present.
219
- $defaults['_conditional'] = $defaults['headers'];
220
- unset($defaults['headers']);
221
- }
222
-
223
- // Special handling for headers is required as they are added as
224
- // conditional headers and as headers passed to a request ctor.
225
- if (array_key_exists('headers', $options)) {
226
- // Allows default headers to be unset.
227
- if ($options['headers'] === null) {
228
- $defaults['_conditional'] = null;
229
- unset($options['headers']);
230
- } elseif (!is_array($options['headers'])) {
231
- throw new \InvalidArgumentException('headers must be an array');
232
- }
233
- }
234
-
235
- // Shallow merge defaults underneath options.
236
- $result = $options + $defaults;
237
-
238
- // Remove null values.
239
- foreach ($result as $k => $v) {
240
- if ($v === null) {
241
- unset($result[$k]);
242
- }
243
- }
244
-
245
- return $result;
246
- }
247
-
248
- /**
249
- * Transfers the given request and applies request options.
250
- *
251
- * The URI of the request is not modified and the request options are used
252
- * as-is without merging in default options.
253
- *
254
- * @param RequestInterface $request
255
- * @param array $options
256
- *
257
- * @return Promise\PromiseInterface
258
- */
259
- private function transfer(RequestInterface $request, array $options)
260
- {
261
- // save_to -> sink
262
- if (isset($options['save_to'])) {
263
- $options['sink'] = $options['save_to'];
264
- unset($options['save_to']);
265
- }
266
-
267
- // exceptions -> http_errors
268
- if (isset($options['exceptions'])) {
269
- $options['http_errors'] = $options['exceptions'];
270
- unset($options['exceptions']);
271
- }
272
-
273
- $request = $this->applyOptions($request, $options);
274
- $handler = $options['handler'];
275
-
276
- try {
277
- return Promise\promise_for($handler($request, $options));
278
- } catch (\Exception $e) {
279
- return Promise\rejection_for($e);
280
- }
281
- }
282
-
283
- /**
284
- * Applies the array of request options to a request.
285
- *
286
- * @param RequestInterface $request
287
- * @param array $options
288
- *
289
- * @return RequestInterface
290
- */
291
- private function applyOptions(RequestInterface $request, array &$options)
292
- {
293
- $modify = [
294
- 'set_headers' => [],
295
- ];
296
-
297
- if (isset($options['headers'])) {
298
- $modify['set_headers'] = $options['headers'];
299
- unset($options['headers']);
300
- }
301
-
302
- if (isset($options['form_params'])) {
303
- if (isset($options['multipart'])) {
304
- throw new \InvalidArgumentException('You cannot use '
305
- . 'form_params and multipart at the same time. Use the '
306
- . 'form_params option if you want to send application/'
307
- . 'x-www-form-urlencoded requests, and the multipart '
308
- . 'option to send multipart/form-data requests.');
309
- }
310
- $options['body'] = http_build_query($options['form_params'], '', '&');
311
- unset($options['form_params']);
312
- // Ensure that we don't have the header in different case and set the new value.
313
- $options['_conditional'] = Psr7\_caseless_remove(['Content-Type'], $options['_conditional']);
314
- $options['_conditional']['Content-Type'] = 'application/x-www-form-urlencoded';
315
- }
316
-
317
- if (isset($options['multipart'])) {
318
- $options['body'] = new Psr7\MultipartStream($options['multipart']);
319
- unset($options['multipart']);
320
- }
321
-
322
- if (isset($options['json'])) {
323
- $options['body'] = \GuzzleHttp\json_encode($options['json']);
324
- unset($options['json']);
325
- // Ensure that we don't have the header in different case and set the new value.
326
- $options['_conditional'] = Psr7\_caseless_remove(['Content-Type'], $options['_conditional']);
327
- $options['_conditional']['Content-Type'] = 'application/json';
328
- }
329
-
330
- if (!empty($options['decode_content'])
331
- && $options['decode_content'] !== true
332
- ) {
333
- // Ensure that we don't have the header in different case and set the new value.
334
- $options['_conditional'] = Psr7\_caseless_remove(['Accept-Encoding'], $options['_conditional']);
335
- $modify['set_headers']['Accept-Encoding'] = $options['decode_content'];
336
- }
337
-
338
- if (isset($options['body'])) {
339
- if (is_array($options['body'])) {
340
- $this->invalidBody();
341
- }
342
- $modify['body'] = Psr7\stream_for($options['body']);
343
- unset($options['body']);
344
- }
345
-
346
- if (!empty($options['auth']) && is_array($options['auth'])) {
347
- $value = $options['auth'];
348
- $type = isset($value[2]) ? strtolower($value[2]) : 'basic';
349
- switch ($type) {
350
- case 'basic':
351
- // Ensure that we don't have the header in different case and set the new value.
352
- $modify['set_headers'] = Psr7\_caseless_remove(['Authorization'], $modify['set_headers']);
353
- $modify['set_headers']['Authorization'] = 'Basic '
354
- . base64_encode("$value[0]:$value[1]");
355
- break;
356
- case 'digest':
357
- // @todo: Do not rely on curl
358
- $options['curl'][CURLOPT_HTTPAUTH] = CURLAUTH_DIGEST;
359
- $options['curl'][CURLOPT_USERPWD] = "$value[0]:$value[1]";
360
- break;
361
- case 'ntlm':
362
- $options['curl'][CURLOPT_HTTPAUTH] = CURLAUTH_NTLM;
363
- $options['curl'][CURLOPT_USERPWD] = "$value[0]:$value[1]";
364
- break;
365
- }
366
- }
367
-
368
- if (isset($options['query'])) {
369
- $value = $options['query'];
370
- if (is_array($value)) {
371
- $value = http_build_query($value, null, '&', PHP_QUERY_RFC3986);
372
- }
373
- if (!is_string($value)) {
374
- throw new \InvalidArgumentException('query must be a string or array');
375
- }
376
- $modify['query'] = $value;
377
- unset($options['query']);
378
- }
379
-
380
- // Ensure that sink is not an invalid value.
381
- if (isset($options['sink'])) {
382
- // TODO: Add more sink validation?
383
- if (is_bool($options['sink'])) {
384
- throw new \InvalidArgumentException('sink must not be a boolean');
385
- }
386
- }
387
-
388
- $request = Psr7\modify_request($request, $modify);
389
- if ($request->getBody() instanceof Psr7\MultipartStream) {
390
- // Use a multipart/form-data POST if a Content-Type is not set.
391
- // Ensure that we don't have the header in different case and set the new value.
392
- $options['_conditional'] = Psr7\_caseless_remove(['Content-Type'], $options['_conditional']);
393
- $options['_conditional']['Content-Type'] = 'multipart/form-data; boundary='
394
- . $request->getBody()->getBoundary();
395
- }
396
-
397
- // Merge in conditional headers if they are not present.
398
- if (isset($options['_conditional'])) {
399
- // Build up the changes so it's in a single clone of the message.
400
- $modify = [];
401
- foreach ($options['_conditional'] as $k => $v) {
402
- if (!$request->hasHeader($k)) {
403
- $modify['set_headers'][$k] = $v;
404
- }
405
- }
406
- $request = Psr7\modify_request($request, $modify);
407
- // Don't pass this internal value along to middleware/handlers.
408
- unset($options['_conditional']);
409
- }
410
-
411
- return $request;
412
- }
413
-
414
- private function invalidBody()
415
- {
416
- throw new \InvalidArgumentException('Passing in the "body" request '
417
- . 'option as an array to send a POST request has been deprecated. '
418
- . 'Please use the "form_params" request option to send a '
419
- . 'application/x-www-form-urlencoded request, or the "multipart" '
420
- . 'request option to send a multipart/form-data request.');
421
- }
422
- }
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ use GuzzleHttp\Cookie\CookieJar;
5
+ use GuzzleHttp\Promise;
6
+ use GuzzleHttp\Psr7;
7
+ use Psr\Http\Message\UriInterface;
8
+ use Psr\Http\Message\RequestInterface;
9
+ use Psr\Http\Message\ResponseInterface;
10
+
11
+ /**
12
+ * @method ResponseInterface get(string|UriInterface $uri, array $options = [])
13
+ * @method ResponseInterface head(string|UriInterface $uri, array $options = [])
14
+ * @method ResponseInterface put(string|UriInterface $uri, array $options = [])
15
+ * @method ResponseInterface post(string|UriInterface $uri, array $options = [])
16
+ * @method ResponseInterface patch(string|UriInterface $uri, array $options = [])
17
+ * @method ResponseInterface delete(string|UriInterface $uri, array $options = [])
18
+ * @method Promise\PromiseInterface getAsync(string|UriInterface $uri, array $options = [])
19
+ * @method Promise\PromiseInterface headAsync(string|UriInterface $uri, array $options = [])
20
+ * @method Promise\PromiseInterface putAsync(string|UriInterface $uri, array $options = [])
21
+ * @method Promise\PromiseInterface postAsync(string|UriInterface $uri, array $options = [])
22
+ * @method Promise\PromiseInterface patchAsync(string|UriInterface $uri, array $options = [])
23
+ * @method Promise\PromiseInterface deleteAsync(string|UriInterface $uri, array $options = [])
24
+ */
25
+ class Client implements ClientInterface
26
+ {
27
+ /** @var array Default request options */
28
+ private $config;
29
+
30
+ /**
31
+ * Clients accept an array of constructor parameters.
32
+ *
33
+ * Here's an example of creating a client using a base_uri and an array of
34
+ * default request options to apply to each request:
35
+ *
36
+ * $client = new Client([
37
+ * 'base_uri' => 'http://www.foo.com/1.0/',
38
+ * 'timeout' => 0,
39
+ * 'allow_redirects' => false,
40
+ * 'proxy' => '192.168.16.1:10'
41
+ * ]);
42
+ *
43
+ * Client configuration settings include the following options:
44
+ *
45
+ * - handler: (callable) Function that transfers HTTP requests over the
46
+ * wire. The function is called with a Psr7\Http\Message\RequestInterface
47
+ * and array of transfer options, and must return a
48
+ * GuzzleHttp\Promise\PromiseInterface that is fulfilled with a
49
+ * Psr7\Http\Message\ResponseInterface on success. "handler" is a
50
+ * constructor only option that cannot be overridden in per/request
51
+ * options. If no handler is provided, a default handler will be created
52
+ * that enables all of the request options below by attaching all of the
53
+ * default middleware to the handler.
54
+ * - base_uri: (string|UriInterface) Base URI of the client that is merged
55
+ * into relative URIs. Can be a string or instance of UriInterface.
56
+ * - **: any request option
57
+ *
58
+ * @param array $config Client configuration settings.
59
+ *
60
+ * @see \GuzzleHttp\RequestOptions for a list of available request options.
61
+ */
62
+ public function __construct(array $config = [])
63
+ {
64
+ if (!isset($config['handler'])) {
65
+ $config['handler'] = HandlerStack::create();
66
+ } elseif (!is_callable($config['handler'])) {
67
+ throw new \InvalidArgumentException('handler must be a callable');
68
+ }
69
+
70
+ // Convert the base_uri to a UriInterface
71
+ if (isset($config['base_uri'])) {
72
+ $config['base_uri'] = Psr7\uri_for($config['base_uri']);
73
+ }
74
+
75
+ $this->configureDefaults($config);
76
+ }
77
+
78
+ public function __call($method, $args)
79
+ {
80
+ if (count($args) < 1) {
81
+ throw new \InvalidArgumentException('Magic request methods require a URI and optional options array');
82
+ }
83
+
84
+ $uri = $args[0];
85
+ $opts = isset($args[1]) ? $args[1] : [];
86
+
87
+ return substr($method, -5) === 'Async'
88
+ ? $this->requestAsync(substr($method, 0, -5), $uri, $opts)
89
+ : $this->request($method, $uri, $opts);
90
+ }
91
+
92
+ public function sendAsync(RequestInterface $request, array $options = [])
93
+ {
94
+ // Merge the base URI into the request URI if needed.
95
+ $options = $this->prepareDefaults($options);
96
+
97
+ return $this->transfer(
98
+ $request->withUri($this->buildUri($request->getUri(), $options), $request->hasHeader('Host')),
99
+ $options
100
+ );
101
+ }
102
+
103
+ public function send(RequestInterface $request, array $options = [])
104
+ {
105
+ $options[RequestOptions::SYNCHRONOUS] = true;
106
+ return $this->sendAsync($request, $options)->wait();
107
+ }
108
+
109
+ public function requestAsync($method, $uri = '', array $options = [])
110
+ {
111
+ $options = $this->prepareDefaults($options);
112
+ // Remove request modifying parameter because it can be done up-front.
113
+ $headers = isset($options['headers']) ? $options['headers'] : [];
114
+ $body = isset($options['body']) ? $options['body'] : null;
115
+ $version = isset($options['version']) ? $options['version'] : '1.1';
116
+ // Merge the URI into the base URI.
117
+ $uri = $this->buildUri($uri, $options);
118
+ if (is_array($body)) {
119
+ $this->invalidBody();
120
+ }
121
+ $request = new Psr7\Request($method, $uri, $headers, $body, $version);
122
+ // Remove the option so that they are not doubly-applied.
123
+ unset($options['headers'], $options['body'], $options['version']);
124
+
125
+ return $this->transfer($request, $options);
126
+ }
127
+
128
+ public function request($method, $uri = '', array $options = [])
129
+ {
130
+ $options[RequestOptions::SYNCHRONOUS] = true;
131
+ return $this->requestAsync($method, $uri, $options)->wait();
132
+ }
133
+
134
+ public function getConfig($option = null)
135
+ {
136
+ return $option === null
137
+ ? $this->config
138
+ : (isset($this->config[$option]) ? $this->config[$option] : null);
139
+ }
140
+
141
+ private function buildUri($uri, array $config)
142
+ {
143
+ // for BC we accept null which would otherwise fail in uri_for
144
+ $uri = Psr7\uri_for($uri === null ? '' : $uri);
145
+
146
+ if (isset($config['base_uri'])) {
147
+ $uri = Psr7\UriResolver::resolve(Psr7\uri_for($config['base_uri']), $uri);
148
+ }
149
+
150
+ return $uri->getScheme() === '' && $uri->getHost() !== '' ? $uri->withScheme('http') : $uri;
151
+ }
152
+
153
+ /**
154
+ * Configures the default options for a client.
155
+ *
156
+ * @param array $config
157
+ */
158
+ private function configureDefaults(array $config)
159
+ {
160
+ $defaults = [
161
+ 'allow_redirects' => RedirectMiddleware::$defaultSettings,
162
+ 'http_errors' => true,
163
+ 'decode_content' => true,
164
+ 'verify' => true,
165
+ 'cookies' => false
166
+ ];
167
+
168
+ // Use the standard Linux HTTP_PROXY and HTTPS_PROXY if set.
169
+
170
+ // We can only trust the HTTP_PROXY environment variable in a CLI
171
+ // process due to the fact that PHP has no reliable mechanism to
172
+ // get environment variables that start with "HTTP_".
173
+ if (php_sapi_name() == 'cli' && getenv('HTTP_PROXY')) {
174
+ $defaults['proxy']['http'] = getenv('HTTP_PROXY');
175
+ }
176
+
177
+ if ($proxy = getenv('HTTPS_PROXY')) {
178
+ $defaults['proxy']['https'] = $proxy;
179
+ }
180
+
181
+ if ($noProxy = getenv('NO_PROXY')) {
182
+ $cleanedNoProxy = str_replace(' ', '', $noProxy);
183
+ $defaults['proxy']['no'] = explode(',', $cleanedNoProxy);
184
+ }
185
+
186
+ $this->config = $config + $defaults;
187
+
188
+ if (!empty($config['cookies']) && $config['cookies'] === true) {
189
+ $this->config['cookies'] = new CookieJar();
190
+ }
191
+
192
+ // Add the default user-agent header.
193
+ if (!isset($this->config['headers'])) {
194
+ $this->config['headers'] = ['User-Agent' => default_user_agent()];
195
+ } else {
196
+ // Add the User-Agent header if one was not already set.
197
+ foreach (array_keys($this->config['headers']) as $name) {
198
+ if (strtolower($name) === 'user-agent') {
199
+ return;
200
+ }
201
+ }
202
+ $this->config['headers']['User-Agent'] = default_user_agent();
203
+ }
204
+ }
205
+
206
+ /**
207
+ * Merges default options into the array.
208
+ *
209
+ * @param array $options Options to modify by reference
210
+ *
211
+ * @return array
212
+ */
213
+ private function prepareDefaults($options)
214
+ {
215
+ $defaults = $this->config;
216
+
217
+ if (!empty($defaults['headers'])) {
218
+ // Default headers are only added if they are not present.
219
+ $defaults['_conditional'] = $defaults['headers'];
220
+ unset($defaults['headers']);
221
+ }
222
+
223
+ // Special handling for headers is required as they are added as
224
+ // conditional headers and as headers passed to a request ctor.
225
+ if (array_key_exists('headers', $options)) {
226
+ // Allows default headers to be unset.
227
+ if ($options['headers'] === null) {
228
+ $defaults['_conditional'] = null;
229
+ unset($options['headers']);
230
+ } elseif (!is_array($options['headers'])) {
231
+ throw new \InvalidArgumentException('headers must be an array');
232
+ }
233
+ }
234
+
235
+ // Shallow merge defaults underneath options.
236
+ $result = $options + $defaults;
237
+
238
+ // Remove null values.
239
+ foreach ($result as $k => $v) {
240
+ if ($v === null) {
241
+ unset($result[$k]);
242
+ }
243
+ }
244
+
245
+ return $result;
246
+ }
247
+
248
+ /**
249
+ * Transfers the given request and applies request options.
250
+ *
251
+ * The URI of the request is not modified and the request options are used
252
+ * as-is without merging in default options.
253
+ *
254
+ * @param RequestInterface $request
255
+ * @param array $options
256
+ *
257
+ * @return Promise\PromiseInterface
258
+ */
259
+ private function transfer(RequestInterface $request, array $options)
260
+ {
261
+ // save_to -> sink
262
+ if (isset($options['save_to'])) {
263
+ $options['sink'] = $options['save_to'];
264
+ unset($options['save_to']);
265
+ }
266
+
267
+ // exceptions -> http_errors
268
+ if (isset($options['exceptions'])) {
269
+ $options['http_errors'] = $options['exceptions'];
270
+ unset($options['exceptions']);
271
+ }
272
+
273
+ $request = $this->applyOptions($request, $options);
274
+ $handler = $options['handler'];
275
+
276
+ try {
277
+ return Promise\promise_for($handler($request, $options));
278
+ } catch (\Exception $e) {
279
+ return Promise\rejection_for($e);
280
+ }
281
+ }
282
+
283
+ /**
284
+ * Applies the array of request options to a request.
285
+ *
286
+ * @param RequestInterface $request
287
+ * @param array $options
288
+ *
289
+ * @return RequestInterface
290
+ */
291
+ private function applyOptions(RequestInterface $request, array &$options)
292
+ {
293
+ $modify = [
294
+ 'set_headers' => [],
295
+ ];
296
+
297
+ if (isset($options['headers'])) {
298
+ $modify['set_headers'] = $options['headers'];
299
+ unset($options['headers']);
300
+ }
301
+
302
+ if (isset($options['form_params'])) {
303
+ if (isset($options['multipart'])) {
304
+ throw new \InvalidArgumentException('You cannot use '
305
+ . 'form_params and multipart at the same time. Use the '
306
+ . 'form_params option if you want to send application/'
307
+ . 'x-www-form-urlencoded requests, and the multipart '
308
+ . 'option to send multipart/form-data requests.');
309
+ }
310
+ $options['body'] = http_build_query($options['form_params'], '', '&');
311
+ unset($options['form_params']);
312
+ // Ensure that we don't have the header in different case and set the new value.
313
+ $options['_conditional'] = Psr7\_caseless_remove(['Content-Type'], $options['_conditional']);
314
+ $options['_conditional']['Content-Type'] = 'application/x-www-form-urlencoded';
315
+ }
316
+
317
+ if (isset($options['multipart'])) {
318
+ $options['body'] = new Psr7\MultipartStream($options['multipart']);
319
+ unset($options['multipart']);
320
+ }
321
+
322
+ if (isset($options['json'])) {
323
+ $options['body'] = \GuzzleHttp\json_encode($options['json']);
324
+ unset($options['json']);
325
+ // Ensure that we don't have the header in different case and set the new value.
326
+ $options['_conditional'] = Psr7\_caseless_remove(['Content-Type'], $options['_conditional']);
327
+ $options['_conditional']['Content-Type'] = 'application/json';
328
+ }
329
+
330
+ if (!empty($options['decode_content'])
331
+ && $options['decode_content'] !== true
332
+ ) {
333
+ // Ensure that we don't have the header in different case and set the new value.
334
+ $options['_conditional'] = Psr7\_caseless_remove(['Accept-Encoding'], $options['_conditional']);
335
+ $modify['set_headers']['Accept-Encoding'] = $options['decode_content'];
336
+ }
337
+
338
+ if (isset($options['body'])) {
339
+ if (is_array($options['body'])) {
340
+ $this->invalidBody();
341
+ }
342
+ $modify['body'] = Psr7\stream_for($options['body']);
343
+ unset($options['body']);
344
+ }
345
+
346
+ if (!empty($options['auth']) && is_array($options['auth'])) {
347
+ $value = $options['auth'];
348
+ $type = isset($value[2]) ? strtolower($value[2]) : 'basic';
349
+ switch ($type) {
350
+ case 'basic':
351
+ // Ensure that we don't have the header in different case and set the new value.
352
+ $modify['set_headers'] = Psr7\_caseless_remove(['Authorization'], $modify['set_headers']);
353
+ $modify['set_headers']['Authorization'] = 'Basic '
354
+ . base64_encode("$value[0]:$value[1]");
355
+ break;
356
+ case 'digest':
357
+ // @todo: Do not rely on curl
358
+ $options['curl'][CURLOPT_HTTPAUTH] = CURLAUTH_DIGEST;
359
+ $options['curl'][CURLOPT_USERPWD] = "$value[0]:$value[1]";
360
+ break;
361
+ case 'ntlm':
362
+ $options['curl'][CURLOPT_HTTPAUTH] = CURLAUTH_NTLM;
363
+ $options['curl'][CURLOPT_USERPWD] = "$value[0]:$value[1]";
364
+ break;
365
+ }
366
+ }
367
+
368
+ if (isset($options['query'])) {
369
+ $value = $options['query'];
370
+ if (is_array($value)) {
371
+ $value = http_build_query($value, null, '&', PHP_QUERY_RFC3986);
372
+ }
373
+ if (!is_string($value)) {
374
+ throw new \InvalidArgumentException('query must be a string or array');
375
+ }
376
+ $modify['query'] = $value;
377
+ unset($options['query']);
378
+ }
379
+
380
+ // Ensure that sink is not an invalid value.
381
+ if (isset($options['sink'])) {
382
+ // TODO: Add more sink validation?
383
+ if (is_bool($options['sink'])) {
384
+ throw new \InvalidArgumentException('sink must not be a boolean');
385
+ }
386
+ }
387
+
388
+ $request = Psr7\modify_request($request, $modify);
389
+ if ($request->getBody() instanceof Psr7\MultipartStream) {
390
+ // Use a multipart/form-data POST if a Content-Type is not set.
391
+ // Ensure that we don't have the header in different case and set the new value.
392
+ $options['_conditional'] = Psr7\_caseless_remove(['Content-Type'], $options['_conditional']);
393
+ $options['_conditional']['Content-Type'] = 'multipart/form-data; boundary='
394
+ . $request->getBody()->getBoundary();
395
+ }
396
+
397
+ // Merge in conditional headers if they are not present.
398
+ if (isset($options['_conditional'])) {
399
+ // Build up the changes so it's in a single clone of the message.
400
+ $modify = [];
401
+ foreach ($options['_conditional'] as $k => $v) {
402
+ if (!$request->hasHeader($k)) {
403
+ $modify['set_headers'][$k] = $v;
404
+ }
405
+ }
406
+ $request = Psr7\modify_request($request, $modify);
407
+ // Don't pass this internal value along to middleware/handlers.
408
+ unset($options['_conditional']);
409
+ }
410
+
411
+ return $request;
412
+ }
413
+
414
+ private function invalidBody()
415
+ {
416
+ throw new \InvalidArgumentException('Passing in the "body" request '
417
+ . 'option as an array to send a POST request has been deprecated. '
418
+ . 'Please use the "form_params" request option to send a '
419
+ . 'application/x-www-form-urlencoded request, or the "multipart" '
420
+ . 'request option to send a multipart/form-data request.');
421
+ }
422
+ }
vendor/guzzlehttp/guzzle/src/ClientInterface.php CHANGED
@@ -1,84 +1,84 @@
1
- <?php
2
- namespace GuzzleHttp;
3
-
4
- use GuzzleHttp\Promise\PromiseInterface;
5
- use GuzzleHttp\Exception\GuzzleException;
6
- use Psr\Http\Message\RequestInterface;
7
- use Psr\Http\Message\ResponseInterface;
8
- use Psr\Http\Message\UriInterface;
9
-
10
- /**
11
- * Client interface for sending HTTP requests.
12
- */
13
- interface ClientInterface
14
- {
15
- const VERSION = '6.3.3';
16
-
17
- /**
18
- * Send an HTTP request.
19
- *
20
- * @param RequestInterface $request Request to send
21
- * @param array $options Request options to apply to the given
22
- * request and to the transfer.
23
- *
24
- * @return ResponseInterface
25
- * @throws GuzzleException
26
- */
27
- public function send(RequestInterface $request, array $options = []);
28
-
29
- /**
30
- * Asynchronously send an HTTP request.
31
- *
32
- * @param RequestInterface $request Request to send
33
- * @param array $options Request options to apply to the given
34
- * request and to the transfer.
35
- *
36
- * @return PromiseInterface
37
- */
38
- public function sendAsync(RequestInterface $request, array $options = []);
39
-
40
- /**
41
- * Create and send an HTTP request.
42
- *
43
- * Use an absolute path to override the base path of the client, or a
44
- * relative path to append to the base path of the client. The URL can
45
- * contain the query string as well.
46
- *
47
- * @param string $method HTTP method.
48
- * @param string|UriInterface $uri URI object or string.
49
- * @param array $options Request options to apply.
50
- *
51
- * @return ResponseInterface
52
- * @throws GuzzleException
53
- */
54
- public function request($method, $uri, array $options = []);
55
-
56
- /**
57
- * Create and send an asynchronous HTTP request.
58
- *
59
- * Use an absolute path to override the base path of the client, or a
60
- * relative path to append to the base path of the client. The URL can
61
- * contain the query string as well. Use an array to provide a URL
62
- * template and additional variables to use in the URL template expansion.
63
- *
64
- * @param string $method HTTP method
65
- * @param string|UriInterface $uri URI object or string.
66
- * @param array $options Request options to apply.
67
- *
68
- * @return PromiseInterface
69
- */
70
- public function requestAsync($method, $uri, array $options = []);
71
-
72
- /**
73
- * Get a client configuration option.
74
- *
75
- * These options include default request options of the client, a "handler"
76
- * (if utilized by the concrete client), and a "base_uri" if utilized by
77
- * the concrete client.
78
- *
79
- * @param string|null $option The config option to retrieve.
80
- *
81
- * @return mixed
82
- */
83
- public function getConfig($option = null);
84
- }
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ use GuzzleHttp\Promise\PromiseInterface;
5
+ use GuzzleHttp\Exception\GuzzleException;
6
+ use Psr\Http\Message\RequestInterface;
7
+ use Psr\Http\Message\ResponseInterface;
8
+ use Psr\Http\Message\UriInterface;
9
+
10
+ /**
11
+ * Client interface for sending HTTP requests.
12
+ */
13
+ interface ClientInterface
14
+ {
15
+ const VERSION = '6.3.3';
16
+
17
+ /**
18
+ * Send an HTTP request.
19
+ *
20
+ * @param RequestInterface $request Request to send
21
+ * @param array $options Request options to apply to the given
22
+ * request and to the transfer.
23
+ *
24
+ * @return ResponseInterface
25
+ * @throws GuzzleException
26
+ */
27
+ public function send(RequestInterface $request, array $options = []);
28
+
29
+ /**
30
+ * Asynchronously send an HTTP request.
31
+ *
32
+ * @param RequestInterface $request Request to send
33
+ * @param array $options Request options to apply to the given
34
+ * request and to the transfer.
35
+ *
36
+ * @return PromiseInterface
37
+ */
38
+ public function sendAsync(RequestInterface $request, array $options = []);
39
+
40
+ /**
41
+ * Create and send an HTTP request.
42
+ *
43
+ * Use an absolute path to override the base path of the client, or a
44
+ * relative path to append to the base path of the client. The URL can
45
+ * contain the query string as well.
46
+ *
47
+ * @param string $method HTTP method.
48
+ * @param string|UriInterface $uri URI object or string.
49
+ * @param array $options Request options to apply.
50
+ *
51
+ * @return ResponseInterface
52
+ * @throws GuzzleException
53
+ */
54
+ public function request($method, $uri, array $options = []);
55
+
56
+ /**
57
+ * Create and send an asynchronous HTTP request.
58
+ *
59
+ * Use an absolute path to override the base path of the client, or a
60
+ * relative path to append to the base path of the client. The URL can
61
+ * contain the query string as well. Use an array to provide a URL
62
+ * template and additional variables to use in the URL template expansion.
63
+ *
64
+ * @param string $method HTTP method
65
+ * @param string|UriInterface $uri URI object or string.
66
+ * @param array $options Request options to apply.
67
+ *
68
+ * @return PromiseInterface
69
+ */
70
+ public function requestAsync($method, $uri, array $options = []);
71
+
72
+ /**
73
+ * Get a client configuration option.
74
+ *
75
+ * These options include default request options of the client, a "handler"
76
+ * (if utilized by the concrete client), and a "base_uri" if utilized by
77
+ * the concrete client.
78
+ *
79
+ * @param string|null $option The config option to retrieve.
80
+ *
81
+ * @return mixed
82
+ */
83
+ public function getConfig($option = null);
84
+ }
vendor/guzzlehttp/guzzle/src/Cookie/CookieJar.php CHANGED
@@ -1,314 +1,314 @@
1
- <?php
2
- namespace GuzzleHttp\Cookie;
3
-
4
- use Psr\Http\Message\RequestInterface;
5
- use Psr\Http\Message\ResponseInterface;
6
-
7
- /**
8
- * Cookie jar that stores cookies as an array
9
- */
10
- class CookieJar implements CookieJarInterface
11
- {
12
- /** @var SetCookie[] Loaded cookie data */
13
- private $cookies = [];
14
-
15
- /** @var bool */
16
- private $strictMode;
17
-
18
- /**
19
- * @param bool $strictMode Set to true to throw exceptions when invalid
20
- * cookies are added to the cookie jar.
21
- * @param array $cookieArray Array of SetCookie objects or a hash of
22
- * arrays that can be used with the SetCookie
23
- * constructor
24
- */
25
- public function __construct($strictMode = false, $cookieArray = [])
26
- {
27
- $this->strictMode = $strictMode;
28
-
29
- foreach ($cookieArray as $cookie) {
30
- if (!($cookie instanceof SetCookie)) {
31
- $cookie = new SetCookie($cookie);
32
- }
33
- $this->setCookie($cookie);
34
- }
35
- }
36
-
37
- /**
38
- * Create a new Cookie jar from an associative array and domain.
39
- *
40
- * @param array $cookies Cookies to create the jar from
41
- * @param string $domain Domain to set the cookies to
42
- *
43
- * @return self
44
- */
45
- public static function fromArray(array $cookies, $domain)
46
- {
47
- $cookieJar = new self();
48
- foreach ($cookies as $name => $value) {
49
- $cookieJar->setCookie(new SetCookie([
50
- 'Domain' => $domain,
51
- 'Name' => $name,
52
- 'Value' => $value,
53
- 'Discard' => true
54
- ]));
55
- }
56
-
57
- return $cookieJar;
58
- }
59
-
60
- /**
61
- * @deprecated
62
- */
63
- public static function getCookieValue($value)
64
- {
65
- return $value;
66
- }
67
-
68
- /**
69
- * Evaluate if this cookie should be persisted to storage
70
- * that survives between requests.
71
- *
72
- * @param SetCookie $cookie Being evaluated.
73
- * @param bool $allowSessionCookies If we should persist session cookies
74
- * @return bool
75
- */
76
- public static function shouldPersist(
77
- SetCookie $cookie,
78
- $allowSessionCookies = false
79
- ) {
80
- if ($cookie->getExpires() || $allowSessionCookies) {
81
- if (!$cookie->getDiscard()) {
82
- return true;
83
- }
84
- }
85
-
86
- return false;
87
- }
88
-
89
- /**
90
- * Finds and returns the cookie based on the name
91
- *
92
- * @param string $name cookie name to search for
93
- * @return SetCookie|null cookie that was found or null if not found
94
- */
95
- public function getCookieByName($name)
96
- {
97
- // don't allow a null name
98
- if ($name === null) {
99
- return null;
100
- }
101
- foreach ($this->cookies as $cookie) {
102
- if ($cookie->getName() !== null && strcasecmp($cookie->getName(), $name) === 0) {
103
- return $cookie;
104
- }
105
- }
106
- }
107
-
108
- public function toArray()
109
- {
110
- return array_map(function (SetCookie $cookie) {
111
- return $cookie->toArray();
112
- }, $this->getIterator()->getArrayCopy());
113
- }
114
-
115
- public function clear($domain = null, $path = null, $name = null)
116
- {
117
- if (!$domain) {
118
- $this->cookies = [];
119
- return;
120
- } elseif (!$path) {
121
- $this->cookies = array_filter(
122
- $this->cookies,
123
- function (SetCookie $cookie) use ($path, $domain) {
124
- return !$cookie->matchesDomain($domain);
125
- }
126
- );
127
- } elseif (!$name) {
128
- $this->cookies = array_filter(
129
- $this->cookies,
130
- function (SetCookie $cookie) use ($path, $domain) {
131
- return !($cookie->matchesPath($path) &&
132
- $cookie->matchesDomain($domain));
133
- }
134
- );
135
- } else {
136
- $this->cookies = array_filter(
137
- $this->cookies,
138
- function (SetCookie $cookie) use ($path, $domain, $name) {
139
- return !($cookie->getName() == $name &&
140
- $cookie->matchesPath($path) &&
141
- $cookie->matchesDomain($domain));
142
- }
143
- );
144
- }
145
- }
146
-
147
- public function clearSessionCookies()
148
- {
149
- $this->cookies = array_filter(
150
- $this->cookies,
151
- function (SetCookie $cookie) {
152
- return !$cookie->getDiscard() && $cookie->getExpires();
153
- }
154
- );
155
- }
156
-
157
- public function setCookie(SetCookie $cookie)
158
- {
159
- // If the name string is empty (but not 0), ignore the set-cookie
160
- // string entirely.
161
- $name = $cookie->getName();
162
- if (!$name && $name !== '0') {
163
- return false;
164
- }
165
-
166
- // Only allow cookies with set and valid domain, name, value
167
- $result = $cookie->validate();
168
- if ($result !== true) {
169
- if ($this->strictMode) {
170
- throw new \RuntimeException('Invalid cookie: ' . $result);
171
- } else {
172
- $this->removeCookieIfEmpty($cookie);
173
- return false;
174
- }
175
- }
176
-
177
- // Resolve conflicts with previously set cookies
178
- foreach ($this->cookies as $i => $c) {
179
-
180
- // Two cookies are identical, when their path, and domain are
181
- // identical.
182
- if ($c->getPath() != $cookie->getPath() ||
183
- $c->getDomain() != $cookie->getDomain() ||
184
- $c->getName() != $cookie->getName()
185
- ) {
186
- continue;
187
- }
188
-
189
- // The previously set cookie is a discard cookie and this one is
190
- // not so allow the new cookie to be set
191
- if (!$cookie->getDiscard() && $c->getDiscard()) {
192
- unset($this->cookies[$i]);
193
- continue;
194
- }
195
-
196
- // If the new cookie's expiration is further into the future, then
197
- // replace the old cookie
198
- if ($cookie->getExpires() > $c->getExpires()) {
199
- unset($this->cookies[$i]);
200
- continue;
201
- }
202
-
203
- // If the value has changed, we better change it
204
- if ($cookie->getValue() !== $c->getValue()) {
205
- unset($this->cookies[$i]);
206
- continue;
207
- }
208
-
209
- // The cookie exists, so no need to continue
210
- return false;
211
- }
212
-
213
- $this->cookies[] = $cookie;
214
-
215
- return true;
216
- }
217
-
218
- public function count()
219
- {
220
- return count($this->cookies);
221
- }
222
-
223
- public function getIterator()
224
- {
225
- return new \ArrayIterator(array_values($this->cookies));
226
- }
227
-
228
- public function extractCookies(
229
- RequestInterface $request,
230
- ResponseInterface $response
231
- ) {
232
- if ($cookieHeader = $response->getHeader('Set-Cookie')) {
233
- foreach ($cookieHeader as $cookie) {
234
- $sc = SetCookie::fromString($cookie);
235
- if (!$sc->getDomain()) {
236
- $sc->setDomain($request->getUri()->getHost());
237
- }
238
- if (0 !== strpos($sc->getPath(), '/')) {
239
- $sc->setPath($this->getCookiePathFromRequest($request));
240
- }
241
- $this->setCookie($sc);
242
- }
243
- }
244
- }
245
-
246
- /**
247
- * Computes cookie path following RFC 6265 section 5.1.4
248
- *
249
- * @link https://tools.ietf.org/html/rfc6265#section-5.1.4
250
- *
251
- * @param RequestInterface $request
252
- * @return string
253
- */
254
- private function getCookiePathFromRequest(RequestInterface $request)
255
- {
256
- $uriPath = $request->getUri()->getPath();
257
- if ('' === $uriPath) {
258
- return '/';
259
- }
260
- if (0 !== strpos($uriPath, '/')) {
261
- return '/';
262
- }
263
- if ('/' === $uriPath) {
264
- return '/';
265
- }
266
- if (0 === $lastSlashPos = strrpos($uriPath, '/')) {
267
- return '/';
268
- }
269
-
270
- return substr($uriPath, 0, $lastSlashPos);
271
- }
272
-
273
- public function withCookieHeader(RequestInterface $request)
274
- {
275
- $values = [];
276
- $uri = $request->getUri();
277
- $scheme = $uri->getScheme();
278
- $host = $uri->getHost();
279
- $path = $uri->getPath() ?: '/';
280
-
281
- foreach ($this->cookies as $cookie) {
282
- if ($cookie->matchesPath($path) &&
283
- $cookie->matchesDomain($host) &&
284
- !$cookie->isExpired() &&
285
- (!$cookie->getSecure() || $scheme === 'https')
286
- ) {
287
- $values[] = $cookie->getName() . '='
288
- . $cookie->getValue();
289
- }
290
- }
291
-
292
- return $values
293
- ? $request->withHeader('Cookie', implode('; ', $values))
294
- : $request;
295
- }
296
-
297
- /**
298
- * If a cookie already exists and the server asks to set it again with a
299
- * null value, the cookie must be deleted.
300
- *
301
- * @param SetCookie $cookie
302
- */
303
- private function removeCookieIfEmpty(SetCookie $cookie)
304
- {
305
- $cookieValue = $cookie->getValue();
306
- if ($cookieValue === null || $cookieValue === '') {
307
- $this->clear(
308
- $cookie->getDomain(),
309
- $cookie->getPath(),
310
- $cookie->getName()
311
- );
312
- }
313
- }
314
- }
1
+ <?php
2
+ namespace GuzzleHttp\Cookie;
3
+
4
+ use Psr\Http\Message\RequestInterface;
5
+ use Psr\Http\Message\ResponseInterface;
6
+
7
+ /**
8
+ * Cookie jar that stores cookies as an array
9
+ */
10
+ class CookieJar implements CookieJarInterface
11
+ {
12
+ /** @var SetCookie[] Loaded cookie data */
13
+ private $cookies = [];
14
+
15
+ /** @var bool */
16
+ private $strictMode;
17
+
18
+ /**
19
+ * @param bool $strictMode Set to true to throw exceptions when invalid
20
+ * cookies are added to the cookie jar.
21
+ * @param array $cookieArray Array of SetCookie objects or a hash of
22
+ * arrays that can be used with the SetCookie
23
+ * constructor
24
+ */
25
+ public function __construct($strictMode = false, $cookieArray = [])
26
+ {
27
+ $this->strictMode = $strictMode;
28
+
29
+ foreach ($cookieArray as $cookie) {
30
+ if (!($cookie instanceof SetCookie)) {
31
+ $cookie = new SetCookie($cookie);
32
+ }
33
+ $this->setCookie($cookie);
34
+ }
35
+ }
36
+
37
+ /**
38
+ * Create a new Cookie jar from an associative array and domain.
39
+ *
40
+ * @param array $cookies Cookies to create the jar from
41
+ * @param string $domain Domain to set the cookies to
42
+ *
43
+ * @return self
44
+ */
45
+ public static function fromArray(array $cookies, $domain)
46
+ {
47
+ $cookieJar = new self();
48
+ foreach ($cookies as $name => $value) {
49
+ $cookieJar->setCookie(new SetCookie([
50
+ 'Domain' => $domain,
51
+ 'Name' => $name,
52
+ 'Value' => $value,
53
+ 'Discard' => true
54
+ ]));
55
+ }
56
+
57
+ return $cookieJar;
58
+ }
59
+
60
+ /**
61
+ * @deprecated
62
+ */
63
+ public static function getCookieValue($value)
64
+ {
65
+ return $value;
66
+ }
67
+
68
+ /**
69
+ * Evaluate if this cookie should be persisted to storage
70
+ * that survives between requests.
71
+ *
72
+ * @param SetCookie $cookie Being evaluated.
73
+ * @param bool $allowSessionCookies If we should persist session cookies
74
+ * @return bool
75
+ */
76
+ public static function shouldPersist(
77
+ SetCookie $cookie,
78
+ $allowSessionCookies = false
79
+ ) {
80
+ if ($cookie->getExpires() || $allowSessionCookies) {
81
+ if (!$cookie->getDiscard()) {
82
+ return true;
83
+ }
84
+ }
85
+
86
+ return false;
87
+ }
88
+
89
+ /**
90
+ * Finds and returns the cookie based on the name
91
+ *
92
+ * @param string $name cookie name to search for
93
+ * @return SetCookie|null cookie that was found or null if not found
94
+ */
95
+ public function getCookieByName($name)
96
+ {
97
+ // don't allow a null name
98
+ if ($name === null) {
99
+ return null;
100
+ }
101
+ foreach ($this->cookies as $cookie) {
102
+ if ($cookie->getName() !== null && strcasecmp($cookie->getName(), $name) === 0) {
103
+ return $cookie;
104
+ }
105
+ }
106
+ }
107
+
108
+ public function toArray()
109
+ {
110
+ return array_map(function (SetCookie $cookie) {
111
+ return $cookie->toArray();
112
+ }, $this->getIterator()->getArrayCopy());
113
+ }
114
+
115
+ public function clear($domain = null, $path = null, $name = null)
116
+ {
117
+ if (!$domain) {
118
+ $this->cookies = [];
119
+ return;
120
+ } elseif (!$path) {
121
+ $this->cookies = array_filter(
122
+ $this->cookies,
123
+ function (SetCookie $cookie) use ($path, $domain) {
124
+ return !$cookie->matchesDomain($domain);
125
+ }
126
+ );
127
+ } elseif (!$name) {
128
+ $this->cookies = array_filter(
129
+ $this->cookies,
130
+ function (SetCookie $cookie) use ($path, $domain) {
131
+ return !($cookie->matchesPath($path) &&
132
+ $cookie->matchesDomain($domain));
133
+ }
134
+ );
135
+ } else {
136
+ $this->cookies = array_filter(
137
+ $this->cookies,
138
+ function (SetCookie $cookie) use ($path, $domain, $name) {
139
+ return !($cookie->getName() == $name &&
140
+ $cookie->matchesPath($path) &&
141
+ $cookie->matchesDomain($domain));
142
+ }
143
+ );
144
+ }
145
+ }
146
+
147
+ public function clearSessionCookies()
148
+ {
149
+ $this->cookies = array_filter(
150
+ $this->cookies,
151
+ function (SetCookie $cookie) {
152
+ return !$cookie->getDiscard() && $cookie->getExpires();
153
+ }
154
+ );
155
+ }
156
+
157
+ public function setCookie(SetCookie $cookie)
158
+ {
159
+ // If the name string is empty (but not 0), ignore the set-cookie
160
+ // string entirely.
161
+ $name = $cookie->getName();
162
+ if (!$name && $name !== '0') {
163
+ return false;
164
+ }
165
+
166
+ // Only allow cookies with set and valid domain, name, value
167
+ $result = $cookie->validate();
168
+ if ($result !== true) {
169
+ if ($this->strictMode) {
170
+ throw new \RuntimeException('Invalid cookie: ' . $result);
171
+ } else {
172
+ $this->removeCookieIfEmpty($cookie);
173
+ return false;
174
+ }
175
+ }
176
+
177
+ // Resolve conflicts with previously set cookies
178
+ foreach ($this->cookies as $i => $c) {
179
+
180
+ // Two cookies are identical, when their path, and domain are
181
+ // identical.
182
+ if ($c->getPath() != $cookie->getPath() ||
183
+ $c->getDomain() != $cookie->getDomain() ||
184
+ $c->getName() != $cookie->getName()
185
+ ) {
186
+ continue;
187
+ }
188
+
189
+ // The previously set cookie is a discard cookie and this one is
190
+ // not so allow the new cookie to be set
191
+ if (!$cookie->getDiscard() && $c->getDiscard()) {
192
+ unset($this->cookies[$i]);
193
+ continue;
194
+ }
195
+
196
+ // If the new cookie's expiration is further into the future, then
197
+ // replace the old cookie
198
+ if ($cookie->getExpires() > $c->getExpires()) {
199
+ unset($this->cookies[$i]);
200
+ continue;
201
+ }
202
+
203
+ // If the value has changed, we better change it
204
+ if ($cookie->getValue() !== $c->getValue()) {
205
+ unset($this->cookies[$i]);
206
+ continue;
207
+ }
208
+
209
+ // The cookie exists, so no need to continue
210
+ return false;
211
+ }
212
+
213
+ $this->cookies[] = $cookie;
214
+
215
+ return true;
216
+ }
217
+
218
+ public function count()
219
+ {
220
+ return count($this->cookies);
221
+ }
222
+
223
+ public function getIterator()
224
+ {
225
+ return new \ArrayIterator(array_values($this->cookies));
226
+ }
227
+
228
+ public function extractCookies(
229
+ RequestInterface $request,
230
+ ResponseInterface $response
231
+ ) {
232
+ if ($cookieHeader = $response->getHeader('Set-Cookie')) {
233
+ foreach ($cookieHeader as $cookie) {
234
+ $sc = SetCookie::fromString($cookie);
235
+ if (!$sc->getDomain()) {
236
+ $sc->setDomain($request->getUri()->getHost());
237
+ }
238
+ if (0 !== strpos($sc->getPath(), '/')) {
239
+ $sc->setPath($this->getCookiePathFromRequest($request));
240
+ }
241
+ $this->setCookie($sc);
242
+ }
243
+ }
244
+ }
245
+
246
+ /**
247
+ * Computes cookie path following RFC 6265 section 5.1.4
248
+ *
249
+ * @link https://tools.ietf.org/html/rfc6265#section-5.1.4
250
+ *
251
+ * @param RequestInterface $request
252
+ * @return string
253
+ */
254
+ private function getCookiePathFromRequest(RequestInterface $request)
255
+ {
256
+ $uriPath = $request->getUri()->getPath();
257
+ if ('' === $uriPath) {
258
+ return '/';
259
+ }
260
+ if (0 !== strpos($uriPath, '/')) {
261
+ return '/';
262
+ }
263
+ if ('/' === $uriPath) {
264
+ return '/';
265
+ }
266
+ if (0 === $lastSlashPos = strrpos($uriPath, '/')) {
267
+ return '/';
268
+ }
269
+
270
+ return substr($uriPath, 0, $lastSlashPos);
271
+ }
272
+
273
+ public function withCookieHeader(RequestInterface $request)
274
+ {
275
+ $values = [];
276
+ $uri = $request->getUri();
277
+ $scheme = $uri->getScheme();
278
+ $host = $uri->getHost();
279
+ $path = $uri->getPath() ?: '/';
280
+
281
+ foreach ($this->cookies as $cookie) {
282
+ if ($cookie->matchesPath($path) &&
283
+ $cookie->matchesDomain($host) &&
284
+ !$cookie->isExpired() &&
285
+ (!$cookie->getSecure() || $scheme === 'https')
286
+ ) {
287
+ $values[] = $cookie->getName() . '='
288
+ . $cookie->getValue();
289
+ }
290
+ }
291
+
292
+ return $values
293
+ ? $request->withHeader('Cookie', implode('; ', $values))
294
+ : $request;
295
+ }
296
+
297
+ /**
298
+ * If a cookie already exists and the server asks to set it again with a
299
+ * null value, the cookie must be deleted.
300
+ *
301
+ * @param SetCookie $cookie
302
+ */
303
+ private function removeCookieIfEmpty(SetCookie $cookie)
304
+ {
305
+ $cookieValue = $cookie->getValue();
306
+ if ($cookieValue === null || $cookieValue === '') {
307
+ $this->clear(
308
+ $cookie->getDomain(),
309
+ $cookie->getPath(),
310
+ $cookie->getName()
311
+ );
312
+ }
313
+ }
314
+ }
vendor/guzzlehttp/guzzle/src/Cookie/CookieJarInterface.php CHANGED
@@ -1,84 +1,84 @@
1
- <?php
2
- namespace GuzzleHttp\Cookie;
3
-
4
- use Psr\Http\Message\RequestInterface;
5
- use Psr\Http\Message\ResponseInterface;
6
-
7
- /**
8
- * Stores HTTP cookies.
9
- *
10
- * It extracts cookies from HTTP requests, and returns them in HTTP responses.
11
- * CookieJarInterface instances automatically expire contained cookies when
12
- * necessary. Subclasses are also responsible for storing and retrieving
13
- * cookies from a file, database, etc.
14
- *
15
- * @link http://docs.python.org/2/library/cookielib.html Inspiration
16
- */
17
- interface CookieJarInterface extends \Countable, \IteratorAggregate
18
- {
19
- /**
20
- * Create a request with added cookie headers.
21
- *
22
- * If no matching cookies are found in the cookie jar, then no Cookie
23
- * header is added to the request and the same request is returned.
24
- *
25
- * @param RequestInterface $request Request object to modify.
26
- *
27
- * @return RequestInterface returns the modified request.
28
- */
29
- public function withCookieHeader(RequestInterface $request);
30
-
31
- /**
32
- * Extract cookies from an HTTP response and store them in the CookieJar.
33
- *
34
- * @param RequestInterface $request Request that was sent
35
- * @param ResponseInterface $response Response that was received
36
- */
37
- public function extractCookies(
38
- RequestInterface $request,
39
- ResponseInterface $response
40
- );
41
-
42
- /**
43
- * Sets a cookie in the cookie jar.
44
- *
45
- * @param SetCookie $cookie Cookie to set.
46
- *
47
- * @return bool Returns true on success or false on failure
48
- */
49
- public function setCookie(SetCookie $cookie);
50
-
51
- /**
52
- * Remove cookies currently held in the cookie jar.
53
- *
54
- * Invoking this method without arguments will empty the whole cookie jar.
55
- * If given a $domain argument only cookies belonging to that domain will
56
- * be removed. If given a $domain and $path argument, cookies belonging to
57
- * the specified path within that domain are removed. If given all three
58
- * arguments, then the cookie with the specified name, path and domain is
59
- * removed.
60
- *
61
- * @param string $domain Clears cookies matching a domain
62
- * @param string $path Clears cookies matching a domain and path
63
- * @param string $name Clears cookies matching a domain, path, and name
64
- *
65
- * @return CookieJarInterface
66
- */
67
- public function clear($domain = null, $path = null, $name = null);
68
-
69
- /**
70
- * Discard all sessions cookies.
71
- *
72
- * Removes cookies that don't have an expire field or a have a discard
73
- * field set to true. To be called when the user agent shuts down according
74
- * to RFC 2965.
75
- */
76
- public function clearSessionCookies();
77
-
78
- /**
79
- * Converts the cookie jar to an array.
80
- *
81
- * @return array
82
- */
83
- public function toArray();
84
- }
1
+ <?php
2
+ namespace GuzzleHttp\Cookie;
3
+
4
+ use Psr\Http\Message\RequestInterface;
5
+ use Psr\Http\Message\ResponseInterface;
6
+
7
+ /**
8
+ * Stores HTTP cookies.
9
+ *
10
+ * It extracts cookies from HTTP requests, and returns them in HTTP responses.
11
+ * CookieJarInterface instances automatically expire contained cookies when
12
+ * necessary. Subclasses are also responsible for storing and retrieving
13
+ * cookies from a file, database, etc.
14
+ *
15
+ * @link http://docs.python.org/2/library/cookielib.html Inspiration
16
+ */
17
+ interface CookieJarInterface extends \Countable, \IteratorAggregate
18
+ {
19
+ /**
20
+ * Create a request with added cookie headers.
21
+ *
22
+ * If no matching cookies are found in the cookie jar, then no Cookie
23
+ * header is added to the request and the same request is returned.
24
+ *
25
+ * @param RequestInterface $request Request object to modify.
26
+ *
27
+ * @return RequestInterface returns the modified request.
28
+ */
29
+ public function withCookieHeader(RequestInterface $request);
30
+
31
+ /**
32
+ * Extract cookies from an HTTP response and store them in the CookieJar.
33
+ *
34
+ * @param RequestInterface $request Request that was sent
35
+ * @param ResponseInterface $response Response that was received
36
+ */
37
+ public function extractCookies(
38
+ RequestInterface $request,
39
+ ResponseInterface $response
40
+ );
41
+
42
+ /**
43
+ * Sets a cookie in the cookie jar.
44
+ *
45
+ * @param SetCookie $cookie Cookie to set.
46
+ *
47
+ * @return bool Returns true on success or false on failure
48
+ */
49
+ public function setCookie(SetCookie $cookie);
50
+
51
+ /**
52
+ * Remove cookies currently held in the cookie jar.
53
+ *
54
+ * Invoking this method without arguments will empty the whole cookie jar.
55
+ * If given a $domain argument only cookies belonging to that domain will
56
+ * be removed. If given a $domain and $path argument, cookies belonging to
57
+ * the specified path within that domain are removed. If given all three
58
+ * arguments, then the cookie with the specified name, path and domain is
59
+ * removed.
60
+ *
61
+ * @param string $domain Clears cookies matching a domain
62
+ * @param string $path Clears cookies matching a domain and path
63
+ * @param string $name Clears cookies matching a domain, path, and name
64
+ *
65
+ * @return CookieJarInterface
66
+ */
67
+ public function clear($domain = null, $path = null, $name = null);
68
+
69
+ /**
70
+ * Discard all sessions cookies.
71
+ *
72
+ * Removes cookies that don't have an expire field or a have a discard
73
+ * field set to true. To be called when the user agent shuts down according
74
+ * to RFC 2965.
75
+ */
76
+ public function clearSessionCookies();
77
+
78
+ /**
79
+ * Converts the cookie jar to an array.
80
+ *
81
+ * @return array
82
+ */
83
+ public function toArray();
84
+ }
vendor/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php CHANGED
@@ -1,90 +1,90 @@
1
- <?php
2
- namespace GuzzleHttp\Cookie;
3
-
4
- /**
5
- * Persists non-session cookies using a JSON formatted file
6
- */
7
- class FileCookieJar extends CookieJar
8
- {
9
- /** @var string filename */
10
- private $filename;
11
-
12
- /** @var bool Control whether to persist session cookies or not. */
13
- private $storeSessionCookies;
14
-
15
- /**
16
- * Create a new FileCookieJar object
17
- *
18
- * @param string $cookieFile File to store the cookie data
19
- * @param bool $storeSessionCookies Set to true to store session cookies
20
- * in the cookie jar.
21
- *
22
- * @throws \RuntimeException if the file cannot be found or created
23
- */
24
- public function __construct($cookieFile, $storeSessionCookies = false)
25
- {
26
- $this->filename = $cookieFile;
27
- $this->storeSessionCookies = $storeSessionCookies;
28
-
29
- if (file_exists($cookieFile)) {
30
- $this->load($cookieFile);
31
- }
32
- }
33
-
34
- /**
35
- * Saves the file when shutting down
36
- */
37
- public function __destruct()
38
- {
39
- $this->save($this->filename);
40
- }
41
-
42
- /**
43
- * Saves the cookies to a file.
44
- *
45
- * @param string $filename File to save
46
- * @throws \RuntimeException if the file cannot be found or created
47
- */
48
- public function save($filename)
49
- {
50
- $json = [];
51
- foreach ($this as $cookie) {
52
- /** @var SetCookie $cookie */
53
- if (CookieJar::shouldPersist($cookie, $this->storeSessionCookies)) {
54
- $json[] = $cookie->toArray();
55
- }
56
- }
57
-
58
- $jsonStr = \GuzzleHttp\json_encode($json);
59
- if (false === file_put_contents($filename, $jsonStr)) {
60
- throw new \RuntimeException("Unable to save file {$filename}");
61
- }
62
- }
63
-
64
- /**
65
- * Load cookies from a JSON formatted file.
66
- *
67
- * Old cookies are kept unless overwritten by newly loaded ones.
68
- *
69
- * @param string $filename Cookie file to load.
70
- * @throws \RuntimeException if the file cannot be loaded.
71
- */
72
- public function load($filename)
73
- {
74
- $json = file_get_contents($filename);
75
- if (false === $json) {
76
- throw new \RuntimeException("Unable to load file {$filename}");
77
- } elseif ($json === '') {
78
- return;
79
- }
80
-
81
- $data = \GuzzleHttp\json_decode($json, true);
82
- if (is_array($data)) {
83
- foreach (json_decode($json, true) as $cookie) {
84
- $this->setCookie(new SetCookie($cookie));
85
- }
86
- } elseif (strlen($data)) {
87
- throw new \RuntimeException("Invalid cookie file: {$filename}");
88
- }
89
- }
90
- }
1
+ <?php
2
+ namespace GuzzleHttp\Cookie;
3
+
4
+ /**
5
+ * Persists non-session cookies using a JSON formatted file
6
+ */
7
+ class FileCookieJar extends CookieJar
8
+ {
9
+ /** @var string filename */
10
+ private $filename;
11
+
12
+ /** @var bool Control whether to persist session cookies or not. */
13
+ private $storeSessionCookies;
14
+
15
+ /**
16
+ * Create a new FileCookieJar object
17
+ *
18
+ * @param string $cookieFile File to store the cookie data
19
+ * @param bool $storeSessionCookies Set to true to store session cookies
20
+ * in the cookie jar.
21
+ *
22
+ * @throws \RuntimeException if the file cannot be found or created
23
+ */
24
+ public function __construct($cookieFile, $storeSessionCookies = false)
25
+ {
26
+ $this->filename = $cookieFile;
27
+ $this->storeSessionCookies = $storeSessionCookies;
28
+
29
+ if (file_exists($cookieFile)) {
30
+ $this->load($cookieFile);
31
+ }
32
+ }
33
+
34
+ /**
35
+ * Saves the file when shutting down
36
+ */
37
+ public function __destruct()
38
+ {
39
+ $this->save($this->filename);
40
+ }
41
+
42
+ /**
43
+ * Saves the cookies to a file.
44
+ *
45
+ * @param string $filename File to save
46
+ * @throws \RuntimeException if the file cannot be found or created
47
+ */
48
+ public function save($filename)
49
+ {
50
+ $json = [];
51
+ foreach ($this as $cookie) {
52
+ /** @var SetCookie $cookie */
53
+ if (CookieJar::shouldPersist($cookie, $this->storeSessionCookies)) {
54
+ $json[] = $cookie->toArray();
55
+ }
56
+ }
57
+
58
+ $jsonStr = \GuzzleHttp\json_encode($json);
59
+ if (false === file_put_contents($filename, $jsonStr)) {
60
+ throw new \RuntimeException("Unable to save file {$filename}");
61
+ }
62
+ }
63
+
64
+ /**
65
+ * Load cookies from a JSON formatted file.
66
+ *
67
+ * Old cookies are kept unless overwritten by newly loaded ones.
68
+ *
69
+ * @param string $filename Cookie file to load.
70
+ * @throws \RuntimeException if the file cannot be loaded.
71
+ */
72
+ public function load($filename)
73
+ {
74
+ $json = file_get_contents($filename);
75
+ if (false === $json) {
76
+ throw new \RuntimeException("Unable to load file {$filename}");
77
+ } elseif ($json === '') {
78
+ return;
79
+ }
80
+
81
+ $data = \GuzzleHttp\json_decode($json, true);
82
+ if (is_array($data)) {
83
+ foreach (json_decode($json, true) as $cookie) {
84
+ $this->setCookie(new SetCookie($cookie));
85
+ }
86
+ } elseif (strlen($data)) {
87
+ throw new \RuntimeException("Invalid cookie file: {$filename}");
88
+ }
89
+ }
90
+ }
vendor/guzzlehttp/guzzle/src/Cookie/SessionCookieJar.php CHANGED
@@ -1,71 +1,71 @@
1
- <?php
2
- namespace GuzzleHttp\Cookie;
3
-
4
- /**
5
- * Persists cookies in the client session
6
- */
7
- class SessionCookieJar extends CookieJar
8
- {
9
- /** @var string session key */
10
- private $sessionKey;
11
-
12
- /** @var bool Control whether to persist session cookies or not. */
13
- private $storeSessionCookies;
14
-
15
- /**
16
- * Create a new SessionCookieJar object
17
- *
18
- * @param string $sessionKey Session key name to store the cookie
19
- * data in session
20
- * @param bool $storeSessionCookies Set to true to store session cookies
21
- * in the cookie jar.
22
- */
23
- public function __construct($sessionKey, $storeSessionCookies = false)
24
- {
25
- $this->sessionKey = $sessionKey;
26
- $this->storeSessionCookies = $storeSessionCookies;
27
- $this->load();
28
- }
29
-
30
- /**
31
- * Saves cookies to session when shutting down
32
- */
33
- public function __destruct()
34
- {
35
- $this->save();
36
- }
37
-
38
- /**
39
- * Save cookies to the client session
40
- */
41
- public function save()
42
- {
43
- $json = [];
44
- foreach ($this as $cookie) {
45
- /** @var SetCookie $cookie */
46
- if (CookieJar::shouldPersist($cookie, $this->storeSessionCookies)) {
47
- $json[] = $cookie->toArray();
48
- }
49
- }
50
-
51
- $_SESSION[$this->sessionKey] = json_encode($json);
52
- }
53
-
54
- /**
55
- * Load the contents of the client session into the data array
56
- */
57
- protected function load()
58
- {
59
- if (!isset($_SESSION[$this->sessionKey])) {
60
- return;
61
- }
62
- $data = json_decode($_SESSION[$this->sessionKey], true);
63
- if (is_array($data)) {
64
- foreach ($data as $cookie) {
65
- $this->setCookie(new SetCookie($cookie));
66
- }
67
- } elseif (strlen($data)) {
68
- throw new \RuntimeException("Invalid cookie data");
69
- }
70
- }
71
- }
1
+ <?php
2
+ namespace GuzzleHttp\Cookie;
3
+
4
+ /**
5
+ * Persists cookies in the client session
6
+ */
7
+ class SessionCookieJar extends CookieJar
8
+ {
9
+ /** @var string session key */
10
+ private $sessionKey;
11
+
12
+ /** @var bool Control whether to persist session cookies or not. */
13
+ private $storeSessionCookies;
14
+
15
+ /**
16
+ * Create a new SessionCookieJar object
17
+ *
18
+ * @param string $sessionKey Session key name to store the cookie
19
+ * data in session
20
+ * @param bool $storeSessionCookies Set to true to store session cookies
21
+ * in the cookie jar.
22
+ */
23
+ public function __construct($sessionKey, $storeSessionCookies = false)
24
+ {
25
+ $this->sessionKey = $sessionKey;
26
+ $this->storeSessionCookies = $storeSessionCookies;
27
+ $this->load();
28
+ }
29
+
30
+ /**
31
+ * Saves cookies to session when shutting down
32
+ */
33
+ public function __destruct()
34
+ {
35
+ $this->save();
36
+ }
37
+
38
+ /**
39
+ * Save cookies to the client session
40
+ */
41
+ public function save()
42
+ {
43
+ $json = [];
44
+ foreach ($this as $cookie) {
45
+ /** @var SetCookie $cookie */
46
+ if (CookieJar::shouldPersist($cookie, $this->storeSessionCookies)) {
47
+ $json[] = $cookie->toArray();
48
+ }
49
+ }
50
+
51
+ $_SESSION[$this->sessionKey] = json_encode($json);
52
+ }
53
+
54
+ /**
55
+ * Load the contents of the client session into the data array
56
+ */
57
+ protected function load()
58
+ {
59
+ if (!isset($_SESSION[$this->sessionKey])) {
60
+ return;
61
+ }
62
+ $data = json_decode($_SESSION[$this->sessionKey], true);
63
+ if (is_array($data)) {
64
+ foreach ($data as $cookie) {
65
+ $this->setCookie(new SetCookie($cookie));
66
+ }
67
+ } elseif (strlen($data)) {
68
+ throw new \RuntimeException("Invalid cookie data");
69
+ }
70
+ }
71
+ }
vendor/guzzlehttp/guzzle/src/Cookie/SetCookie.php CHANGED
@@ -1,403 +1,403 @@
1
- <?php
2
- namespace GuzzleHttp\Cookie;
3
-
4
- /**
5
- * Set-Cookie object
6
- */
7
- class SetCookie
8
- {
9
- /** @var array */
10
- private static $defaults = [
11
- 'Name' => null,
12
- 'Value' => null,
13
- 'Domain' => null,
14
- 'Path' => '/',
15
- 'Max-Age' => null,
16
- 'Expires' => null,
17
- 'Secure' => false,
18
- 'Discard' => false,
19
- 'HttpOnly' => false
20
- ];
21
-
22
- /** @var array Cookie data */
23
- private $data;
24
-
25
- /**
26
- * Create a new SetCookie object from a string
27
- *
28
- * @param string $cookie Set-Cookie header string
29
- *
30
- * @return self
31
- */
32
- public static function fromString($cookie)
33
- {
34
- // Create the default return array
35
- $data = self::$defaults;
36
- // Explode the cookie string using a series of semicolons
37
- $pieces = array_filter(array_map('trim', explode(';', $cookie)));
38
- // The name of the cookie (first kvp) must exist and include an equal sign.
39
- if (empty($pieces[0]) || !strpos($pieces[0], '=')) {
40
- return new self($data);
41
- }
42
-
43
- // Add the cookie pieces into the parsed data array
44
- foreach ($pieces as $part) {
45
- $cookieParts = explode('=', $part, 2);
46
- $key = trim($cookieParts[0]);
47
- $value = isset($cookieParts[1])
48
- ? trim($cookieParts[1], " \n\r\t\0\x0B")
49
- : true;
50
-
51
- // Only check for non-cookies when cookies have been found
52
- if (empty($data['Name'])) {
53
- $data['Name'] = $key;
54
- $data['Value'] = $value;
55
- } else {
56
- foreach (array_keys(self::$defaults) as $search) {
57
- if (!strcasecmp($search, $key)) {
58
- $data[$search] = $value;
59
- continue 2;
60
- }
61
- }
62
- $data[$key] = $value;
63
- }
64
- }
65
-
66
- return new self($data);
67
- }
68
-
69
- /**
70
- * @param array $data Array of cookie data provided by a Cookie parser
71
- */
72
- public function __construct(array $data = [])
73
- {
74
- $this->data = array_replace(self::$defaults, $data);
75
- // Extract the Expires value and turn it into a UNIX timestamp if needed
76
- if (!$this->getExpires() && $this->getMaxAge()) {
77
- // Calculate the Expires date
78
- $this->setExpires(time() + $this->getMaxAge());
79
- } elseif ($this->getExpires() && !is_numeric($this->getExpires())) {
80
- $this->setExpires($this->getExpires());
81
- }
82
- }
83
-
84
- public function __toString()
85
- {
86
- $str = $this->data['Name'] . '=' . $this->data['Value'] . '; ';
87
- foreach ($this->data as $k => $v) {
88
- if ($k !== 'Name' && $k !== 'Value' && $v !== null && $v !== false) {
89
- if ($k === 'Expires') {
90
- $str .= 'Expires=' . gmdate('D, d M Y H:i:s \G\M\T', $v) . '; ';
91
- } else {
92
- $str .= ($v === true ? $k : "{$k}={$v}") . '; ';
93
- }
94
- }
95
- }
96
-
97
- return rtrim($str, '; ');
98
- }
99
-
100
- public function toArray()
101
- {
102
- return $this->data;
103
- }
104
-
105
- /**
106
- * Get the cookie name
107
- *
108
- * @return string
109
- */
110
- public function getName()
111
- {
112
- return $this->data['Name'];
113
- }
114
-
115
- /**
116
- * Set the cookie name
117
- *
118
- * @param string $name Cookie name
119
- */
120
- public function setName($name)
121
- {
122
- $this->data['Name'] = $name;
123
- }
124
-
125
- /**
126
- * Get the cookie value
127
- *
128
- * @return string
129
- */
130
- public function getValue()
131
- {
132
- return $this->data['Value'];
133
- }
134
-
135
- /**
136
- * Set the cookie value
137
- *
138
- * @param string $value Cookie value
139
- */
140
- public function setValue($value)
141
- {
142
- $this->data['Value'] = $value;
143
- }
144
-
145
- /**
146
- * Get the domain
147
- *
148
- * @return string|null
149
- */
150
- public function getDomain()
151
- {
152
- return $this->data['Domain'];
153
- }
154
-
155
- /**
156
- * Set the domain of the cookie
157
- *
158
- * @param string $domain
159
- */
160
- public function setDomain($domain)
161
- {
162
- $this->data['Domain'] = $domain;
163
- }
164
-
165
- /**
166
- * Get the path
167
- *
168
- * @return string
169
- */
170
- public function getPath()
171
- {
172
- return $this->data['Path'];
173
- }
174
-
175
- /**
176
- * Set the path of the cookie
177
- *
178
- * @param string $path Path of the cookie
179
- */
180
- public function setPath($path)
181
- {
182
- $this->data['Path'] = $path;
183
- }
184
-
185
- /**
186
- * Maximum lifetime of the cookie in seconds
187
- *
188
- * @return int|null
189
- */
190
- public function getMaxAge()
191
- {
192
- return $this->data['Max-Age'];
193
- }
194
-
195
- /**
196
- * Set the max-age of the cookie
197
- *
198
- * @param int $maxAge Max age of the cookie in seconds
199
- */
200
- public function setMaxAge($maxAge)
201
- {
202
- $this->data['Max-Age'] = $maxAge;
203
- }
204
-
205
- /**
206
- * The UNIX timestamp when the cookie Expires
207
- *
208
- * @return mixed
209
- */
210
- public function getExpires()
211
- {
212
- return $this->data['Expires'];
213
- }
214
-
215
- /**
216
- * Set the unix timestamp for which the cookie will expire
217
- *
218
- * @param int $timestamp Unix timestamp
219
- */
220
- public function setExpires($timestamp)
221
- {
222
- $this->data['Expires'] = is_numeric($timestamp)
223
- ? (int) $timestamp
224
- : strtotime($timestamp);
225
- }
226
-
227
- /**
228
- * Get whether or not this is a secure cookie
229
- *
230
- * @return null|bool
231
- */
232
- public function getSecure()
233
- {
234
- return $this->data['Secure'];
235
- }
236
-
237
- /**
238
- * Set whether or not the cookie is secure
239
- *
240
- * @param bool $secure Set to true or false if secure
241
- */
242
- public function setSecure($secure)
243
- {
244
- $this->data['Secure'] = $secure;
245
- }
246
-
247
- /**
248
- * Get whether or not this is a session cookie
249
- *
250
- * @return null|bool
251
- */
252
- public function getDiscard()
253
- {
254
- return $this->data['Discard'];
255
- }
256
-
257
- /**
258
- * Set whether or not this is a session cookie
259
- *
260
- * @param bool $discard Set to true or false if this is a session cookie
261
- */
262
- public function setDiscard($discard)
263
- {
264
- $this->data['Discard'] = $discard;
265
- }
266
-
267
- /**
268
- * Get whether or not this is an HTTP only cookie
269
- *
270
- * @return bool
271
- */
272
- public function getHttpOnly()
273
- {
274
- return $this->data['HttpOnly'];
275
- }
276
-
277
- /**
278
- * Set whether or not this is an HTTP only cookie
279
- *
280
- * @param bool $httpOnly Set to true or false if this is HTTP only
281
- */
282
- public function setHttpOnly($httpOnly)
283
- {
284
- $this->data['HttpOnly'] = $httpOnly;
285
- }
286
-
287
- /**
288
- * Check if the cookie matches a path value.
289
- *
290
- * A request-path path-matches a given cookie-path if at least one of
291
- * the following conditions holds:
292
- *
293
- * - The cookie-path and the request-path are identical.
294
- * - The cookie-path is a prefix of the request-path, and the last
295
- * character of the cookie-path is %x2F ("/").
296
- * - The cookie-path is a prefix of the request-path, and the first
297
- * character of the request-path that is not included in the cookie-
298
- * path is a %x2F ("/") character.
299
- *
300
- * @param string $requestPath Path to check against
301
- *
302
- * @return bool
303
- */
304
- public function matchesPath($requestPath)
305
- {
306
- $cookiePath = $this->getPath();
307
-
308
- // Match on exact matches or when path is the default empty "/"
309
- if ($cookiePath === '/' || $cookiePath == $requestPath) {
310
- return true;
311
- }
312
-
313
- // Ensure that the cookie-path is a prefix of the request path.
314
- if (0 !== strpos($requestPath, $cookiePath)) {
315
- return false;
316
- }
317
-
318
- // Match if the last character of the cookie-path is "/"
319
- if (substr($cookiePath, -1, 1) === '/') {
320
- return true;
321
- }
322
-
323
- // Match if the first character not included in cookie path is "/"
324
- return substr($requestPath, strlen($cookiePath), 1) === '/';
325
- }
326
-
327
- /**
328
- * Check if the cookie matches a domain value
329
- *
330
- * @param string $domain Domain to check against
331
- *
332
- * @return bool
333
- */
334
- public function matchesDomain($domain)
335
- {
336
- // Remove the leading '.' as per spec in RFC 6265.
337
- // http://tools.ietf.org/html/rfc6265#section-5.2.3
338
- $cookieDomain = ltrim($this->getDomain(), '.');
339
-
340
- // Domain not set or exact match.
341
- if (!$cookieDomain || !strcasecmp($domain, $cookieDomain)) {
342
- return true;
343
- }
344
-
345
- // Matching the subdomain according to RFC 6265.
346
- // http://tools.ietf.org/html/rfc6265#section-5.1.3
347
- if (filter_var($domain, FILTER_VALIDATE_IP)) {
348
- return false;
349
- }
350
-
351
- return (bool) preg_match('/\.' . preg_quote($cookieDomain, '/') . '$/', $domain);
352
- }
353
-
354
- /**
355
- * Check if the cookie is expired
356
- *
357
- * @return bool
358
- */
359
- public function isExpired()
360
- {
361
- return $this->getExpires() !== null && time() > $this->getExpires();
362
- }
363
-
364
- /**
365
- * Check if the cookie is valid according to RFC 6265
366
- *
367
- * @return bool|string Returns true if valid or an error message if invalid
368
- */
369
- public function validate()
370
- {
371
- // Names must not be empty, but can be 0
372
- $name = $this->getName();
373
- if (empty($name) && !is_numeric($name)) {
374
- return 'The cookie name must not be empty';
375
- }
376
-
377
- // Check if any of the invalid characters are present in the cookie name
378
- if (preg_match(
379
- '/[\x00-\x20\x22\x28-\x29\x2c\x2f\x3a-\x40\x5c\x7b\x7d\x7f]/',
380
- $name
381
- )) {
382
- return 'Cookie name must not contain invalid characters: ASCII '
383
- . 'Control characters (0-31;127), space, tab and the '
384
- . 'following characters: ()<>@,;:\"/?={}';
385
- }
386
-
387
- // Value must not be empty, but can be 0
388
- $value = $this->getValue();
389
- if (empty($value) && !is_numeric($value)) {
390
- return 'The cookie value must not be empty';
391
- }
392
-
393
- // Domains must not be empty, but can be 0
394
- // A "0" is not a valid internet domain, but may be used as server name
395
- // in a private network.
396
- $domain = $this->getDomain();
397
- if (empty($domain) && !is_numeric($domain)) {
398
- return 'The cookie domain must not be empty';
399
- }
400
-
401
- return true;
402
- }
403
- }
1
+ <?php
2
+ namespace GuzzleHttp\Cookie;
3
+
4
+ /**
5
+ * Set-Cookie object
6
+ */
7
+ class SetCookie
8
+ {
9
+ /** @var array */
10
+ private static $defaults = [
11
+ 'Name' => null,
12
+ 'Value' => null,
13
+ 'Domain' => null,
14
+ 'Path' => '/',
15
+ 'Max-Age' => null,
16
+ 'Expires' => null,
17
+ 'Secure' => false,
18
+ 'Discard' => false,
19
+ 'HttpOnly' => false
20
+ ];
21
+
22
+ /** @var array Cookie data */
23
+ private $data;
24
+
25
+ /**
26
+ * Create a new SetCookie object from a string
27
+ *
28
+ * @param string $cookie Set-Cookie header string
29
+ *
30
+ * @return self
31
+ */
32
+ public static function fromString($cookie)
33
+ {
34
+ // Create the default return array
35
+ $data = self::$defaults;
36
+ // Explode the cookie string using a series of semicolons
37
+ $pieces = array_filter(array_map('trim', explode(';', $cookie)));
38
+ // The name of the cookie (first kvp) must exist and include an equal sign.
39
+ if (empty($pieces[0]) || !strpos($pieces[0], '=')) {
40
+ return new self($data);
41
+ }
42
+
43
+ // Add the cookie pieces into the parsed data array
44
+ foreach ($pieces as $part) {
45
+ $cookieParts = explode('=', $part, 2);
46
+ $key = trim($cookieParts[0]);
47
+ $value = isset($cookieParts[1])
48
+ ? trim($cookieParts[1], " \n\r\t\0\x0B")
49
+ : true;
50
+
51
+ // Only check for non-cookies when cookies have been found
52
+ if (empty($data['Name'])) {
53
+ $data['Name'] = $key;
54
+ $data['Value'] = $value;
55
+ } else {
56
+ foreach (array_keys(self::$defaults) as $search) {
57
+ if (!strcasecmp($search, $key)) {
58
+ $data[$search] = $value;
59
+ continue 2;
60
+ }
61
+ }
62
+ $data[$key] = $value;
63
+ }
64
+ }
65
+
66
+ return new self($data);
67
+ }
68
+
69
+ /**
70
+ * @param array $data Array of cookie data provided by a Cookie parser
71
+ */
72
+ public function __construct(array $data = [])
73
+ {
74
+ $this->data = array_replace(self::$defaults, $data);
75
+ // Extract the Expires value and turn it into a UNIX timestamp if needed
76
+ if (!$this->getExpires() && $this->getMaxAge()) {
77
+ // Calculate the Expires date
78
+ $this->setExpires(time() + $this->getMaxAge());
79
+ } elseif ($this->getExpires() && !is_numeric($this->getExpires())) {
80
+ $this->setExpires($this->getExpires());
81
+ }
82
+ }
83
+
84
+ public function __toString()
85
+ {
86
+ $str = $this->data['Name'] . '=' . $this->data['Value'] . '; ';
87
+ foreach ($this->data as $k => $v) {
88
+ if ($k !== 'Name' && $k !== 'Value' && $v !== null && $v !== false) {
89
+ if ($k === 'Expires') {
90
+ $str .= 'Expires=' . gmdate('D, d M Y H:i:s \G\M\T', $v) . '; ';
91
+ } else {
92
+ $str .= ($v === true ? $k : "{$k}={$v}") . '; ';
93
+ }
94
+ }
95
+ }
96
+
97
+ return rtrim($str, '; ');
98
+ }
99
+
100
+ public function toArray()
101
+ {
102
+ return $this->data;
103
+ }
104
+
105
+ /**
106
+ * Get the cookie name
107
+ *
108
+ * @return string
109
+ */
110
+ public function getName()
111
+ {
112
+ return $this->data['Name'];
113
+ }
114
+
115
+ /**
116
+ * Set the cookie name
117
+ *
118
+ * @param string $name Cookie name
119
+ */
120
+ public function setName($name)
121
+ {
122
+ $this->data['Name'] = $name;
123
+ }
124
+
125
+ /**
126
+ * Get the cookie value
127
+ *
128
+ * @return string
129
+ */
130
+ public function getValue()
131
+ {
132
+ return $this->data['Value'];
133
+ }
134
+
135
+ /**
136
+ * Set the cookie value
137
+ *
138
+ * @param string $value Cookie value
139
+ */
140
+ public function setValue($value)
141
+ {
142
+ $this->data['Value'] = $value;
143
+ }
144
+
145
+ /**
146
+ * Get the domain
147
+ *
148
+ * @return string|null
149
+ */
150
+ public function getDomain()
151
+ {
152
+ return $this->data['Domain'];
153
+ }
154
+
155
+ /**
156
+ * Set the domain of the cookie
157
+ *
158
+ * @param string $domain
159
+ */
160
+ public function setDomain($domain)
161
+ {
162
+ $this->data['Domain'] = $domain;
163
+ }
164
+
165
+ /**
166
+ * Get the path
167
+ *
168
+ * @return string
169
+ */
170
+ public function getPath()
171
+ {
172
+ return $this->data['Path'];
173
+ }
174
+
175
+ /**
176
+ * Set the path of the cookie
177
+ *
178
+ * @param string $path Path of the cookie
179
+ */
180
+ public function setPath($path)
181
+ {
182
+ $this->data['Path'] = $path;
183
+ }
184
+
185
+ /**
186
+ * Maximum lifetime of the cookie in seconds
187
+ *
188
+ * @return int|null
189
+ */
190
+ public function getMaxAge()
191
+ {
192
+ return $this->data['Max-Age'];
193
+ }
194
+
195
+ /**
196
+ * Set the max-age of the cookie
197
+ *
198
+ * @param int $maxAge Max age of the cookie in seconds
199
+ */
200
+ public function setMaxAge($maxAge)
201
+ {
202
+ $this->data['Max-Age'] = $maxAge;
203
+ }
204
+
205
+ /**
206
+ * The UNIX timestamp when the cookie Expires
207
+ *
208
+ * @return mixed
209
+ */
210
+ public function getExpires()
211
+ {
212
+ return $this->data['Expires'];
213
+ }
214
+
215
+ /**
216
+ * Set the unix timestamp for which the cookie will expire
217
+ *
218
+ * @param int $timestamp Unix timestamp
219
+ */
220
+ public function setExpires($timestamp)
221
+ {
222
+ $this->data['Expires'] = is_numeric($timestamp)
223
+ ? (int) $timestamp
224
+ : strtotime($timestamp);
225
+ }
226
+
227
+ /**
228
+ * Get whether or not this is a secure cookie
229
+ *
230
+ * @return null|bool
231
+ */
232
+ public function getSecure()
233
+ {
234
+ return $this->data['Secure'];
235
+ }
236
+
237
+ /**
238
+ * Set whether or not the cookie is secure
239
+ *
240
+ * @param bool $secure Set to true or false if secure
241
+ */
242
+ public function setSecure($secure)
243
+ {
244
+ $this->data['Secure'] = $secure;
245
+ }
246
+
247
+ /**
248
+ * Get whether or not this is a session cookie
249
+ *
250
+ * @return null|bool
251
+ */
252
+ public function getDiscard()
253
+ {
254
+ return $this->data['Discard'];
255
+ }
256
+
257
+ /**
258
+ * Set whether or not this is a session cookie
259
+ *
260
+ * @param bool $discard Set to true or false if this is a session cookie
261
+ */
262
+ public function setDiscard($discard)
263
+ {
264
+ $this->data['Discard'] = $discard;
265
+ }
266
+
267
+ /**
268
+ * Get whether or not this is an HTTP only cookie
269
+ *
270
+ * @return bool
271
+ */
272
+ public function getHttpOnly()
273
+ {
274
+ return $this->data['HttpOnly'];
275
+ }
276
+
277
+ /**
278
+ * Set whether or not this is an HTTP only cookie
279
+ *
280
+ * @param bool $httpOnly Set to true or false if this is HTTP only
281
+ */
282
+ public function setHttpOnly($httpOnly)
283
+ {
284
+ $this->data['HttpOnly'] = $httpOnly;
285
+ }
286
+
287
+ /**
288
+ * Check if the cookie matches a path value.
289
+ *
290
+ * A request-path path-matches a given cookie-path if at least one of
291
+ * the following conditions holds:
292
+ *
293
+ * - The cookie-path and the request-path are identical.
294
+ * - The cookie-path is a prefix of the request-path, and the last
295
+ * character of the cookie-path is %x2F ("/").
296
+ * - The cookie-path is a prefix of the request-path, and the first
297
+ * character of the request-path that is not included in the cookie-
298
+ * path is a %x2F ("/") character.
299
+ *
300
+ * @param string $requestPath Path to check against
301
+ *
302
+ * @return bool
303
+ */
304
+ public function matchesPath($requestPath)
305
+ {
306
+ $cookiePath = $this->getPath();
307
+
308
+ // Match on exact matches or when path is the default empty "/"
309
+ if ($cookiePath === '/' || $cookiePath == $requestPath) {
310
+ return true;
311
+ }
312
+
313
+ // Ensure that the cookie-path is a prefix of the request path.
314
+ if (0 !== strpos($requestPath, $cookiePath)) {
315
+ return false;
316
+ }
317
+
318
+ // Match if the last character of the cookie-path is "/"
319
+ if (substr($cookiePath, -1, 1) === '/') {
320
+ return true;
321
+ }
322
+
323
+ // Match if the first character not included in cookie path is "/"
324
+ return substr($requestPath, strlen($cookiePath), 1) === '/';
325
+ }
326
+
327
+ /**
328
+ * Check if the cookie matches a domain value
329
+ *
330
+ * @param string $domain Domain to check against
331
+ *
332
+ * @return bool
333
+ */
334
+ public function matchesDomain($domain)
335
+ {
336
+ // Remove the leading '.' as per spec in RFC 6265.
337
+ // http://tools.ietf.org/html/rfc6265#section-5.2.3
338
+ $cookieDomain = ltrim($this->getDomain(), '.');
339
+
340
+ // Domain not set or exact match.
341
+ if (!$cookieDomain || !strcasecmp($domain, $cookieDomain)) {
342
+ return true;
343
+ }
344
+
345
+ // Matching the subdomain according to RFC 6265.
346
+ // http://tools.ietf.org/html/rfc6265#section-5.1.3
347
+ if (filter_var($domain, FILTER_VALIDATE_IP)) {
348
+ return false;
349
+ }
350
+
351
+ return (bool) preg_match('/\.' . preg_quote($cookieDomain, '/') . '$/', $domain);
352
+ }
353
+
354
+ /**
355
+ * Check if the cookie is expired
356
+ *
357
+ * @return bool
358
+ */
359
+ public function isExpired()
360
+ {
361
+ return $this->getExpires() !== null && time() > $this->getExpires();
362
+ }
363
+
364
+ /**
365
+ * Check if the cookie is valid according to RFC 6265
366
+ *
367
+ * @return bool|string Returns true if valid or an error message if invalid
368
+ */
369
+ public function validate()
370
+ {
371
+ // Names must not be empty, but can be 0
372
+ $name = $this->getName();
373
+ if (empty($name) && !is_numeric($name)) {
374
+ return 'The cookie name must not be empty';
375
+ }
376
+
377
+ // Check if any of the invalid characters are present in the cookie name
378
+ if (preg_match(
379
+ '/[\x00-\x20\x22\x28-\x29\x2c\x2f\x3a-\x40\x5c\x7b\x7d\x7f]/',
380
+ $name
381
+ )) {
382
+ return 'Cookie name must not contain invalid characters: ASCII '
383
+ . 'Control characters (0-31;127), space, tab and the '
384
+ . 'following characters: ()<>@,;:\"/?={}';
385
+ }
386
+
387
+ // Value must not be empty, but can be 0
388
+ $value = $this->getValue();
389
+ if (empty($value) && !is_numeric($value)) {
390
+ return 'The cookie value must not be empty';
391
+ }
392
+
393
+ // Domains must not be empty, but can be 0
394
+ // A "0" is not a valid internet domain, but may be used as server name
395
+ // in a private network.
396
+ $domain = $this->getDomain();
397
+ if (empty($domain) && !is_numeric($domain)) {
398
+ return 'The cookie domain must not be empty';
399
+ }
400
+
401
+ return true;
402
+ }
403
+ }
vendor/guzzlehttp/guzzle/src/Exception/BadResponseException.php CHANGED
@@ -1,27 +1,27 @@
1
- <?php
2
- namespace GuzzleHttp\Exception;
3
-
4
- use Psr\Http\Message\RequestInterface;
5
- use Psr\Http\Message\ResponseInterface;
6
-
7
- /**
8
- * Exception when an HTTP error occurs (4xx or 5xx error)
9
- */
10
- class BadResponseException extends RequestException
11
- {
12
- public function __construct(
13
- $message,
14
- RequestInterface $request,
15
- ResponseInterface $response = null,
16
- \Exception $previous = null,
17
- array $handlerContext = []
18
- ) {
19
- if (null === $response) {
20
- @trigger_error(
21
- 'Instantiating the ' . __CLASS__ . ' class without a Response is deprecated since version 6.3 and will be removed in 7.0.',
22
- E_USER_DEPRECATED
23
- );
24
- }
25
- parent::__construct($message, $request, $response, $previous, $handlerContext);
26
- }
27
- }
1
+ <?php
2
+ namespace GuzzleHttp\Exception;
3
+
4
+ use Psr\Http\Message\RequestInterface;
5
+ use Psr\Http\Message\ResponseInterface;
6
+
7
+ /**
8
+ * Exception when an HTTP error occurs (4xx or 5xx error)
9
+ */
10
+ class BadResponseException extends RequestException
11
+ {
12
+ public function __construct(
13
+ $message,
14
+ RequestInterface $request,
15
+ ResponseInterface $response = null,
16
+ \Exception $previous = null,
17
+ array $handlerContext = []
18
+ ) {
19
+ if (null === $response) {
20
+ @trigger_error(
21
+ 'Instantiating the ' . __CLASS__ . ' class without a Response is deprecated since version 6.3 and will be removed in 7.0.',
22
+ E_USER_DEPRECATED
23
+ );
24
+ }
25
+ parent::__construct($message, $request, $response, $previous, $handlerContext);
26
+ }
27
+ }
vendor/guzzlehttp/guzzle/src/Exception/ClientException.php CHANGED
@@ -1,7 +1,7 @@
1
- <?php
2
- namespace GuzzleHttp\Exception;
3
-
4
- /**
5
- * Exception when a client error is encountered (4xx codes)
6
- */
7
- class ClientException extends BadResponseException {}
1
+ <?php
2
+ namespace GuzzleHttp\Exception;
3
+
4
+ /**
5
+ * Exception when a client error is encountered (4xx codes)
6
+ */
7
+ class ClientException extends BadResponseException {}
vendor/guzzlehttp/guzzle/src/Exception/ConnectException.php CHANGED
@@ -1,37 +1,37 @@
1
- <?php
2
- namespace GuzzleHttp\Exception;
3
-
4
- use Psr\Http\Message\RequestInterface;
5
-
6
- /**
7
- * Exception thrown when a connection cannot be established.
8
- *
9
- * Note that no response is present for a ConnectException
10
- */
11
- class ConnectException extends RequestException
12
- {
13
- public function __construct(
14
- $message,
15
- RequestInterface $request,
16
- \Exception $previous = null,
17
- array $handlerContext = []
18
- ) {
19
- parent::__construct($message, $request, null, $previous, $handlerContext);
20
- }
21
-
22
- /**
23
- * @return null
24
- */
25
- public function getResponse()
26
- {
27
- return null;
28
- }
29
-
30
- /**
31
- * @return bool
32
- */
33
- public function hasResponse()
34
- {
35
- return false;
36
- }
37
- }
1
+ <?php
2
+ namespace GuzzleHttp\Exception;
3
+
4
+ use Psr\Http\Message\RequestInterface;
5
+
6
+ /**
7
+ * Exception thrown when a connection cannot be established.
8
+ *
9
+ * Note that no response is present for a ConnectException
10
+ */
11
+ class ConnectException extends RequestException
12
+ {
13
+ public function __construct(
14
+ $message,
15
+ RequestInterface $request,
16
+ \Exception $previous = null,
17
+ array $handlerContext = []
18
+ ) {
19
+ parent::__construct($message, $request, null, $previous, $handlerContext);
20
+ }
21
+
22
+ /**
23
+ * @return null
24
+ */
25
+ public function getResponse()
26
+ {
27
+ return null;
28
+ }
29
+
30
+ /**
31
+ * @return bool
32
+ */
33
+ public function hasResponse()
34
+ {
35
+ return false;
36
+ }
37
+ }
vendor/guzzlehttp/guzzle/src/Exception/GuzzleException.php CHANGED
@@ -1,13 +1,13 @@
1
- <?php
2
- namespace GuzzleHttp\Exception;
3
-
4
- /**
5
- * @method string getMessage()
6
- * @method \Throwable|null getPrevious()
7
- * @method mixed getCode()
8
- * @method string getFile()
9
- * @method int getLine()
10
- * @method array getTrace()
11
- * @method string getTraceAsString()
12
- */
13
- interface GuzzleException {}
1
+ <?php
2
+ namespace GuzzleHttp\Exception;
3
+
4
+ /**
5
+ * @method string getMessage()
6
+ * @method \Throwable|null getPrevious()
7
+ * @method mixed getCode()
8
+ * @method string getFile()
9
+ * @method int getLine()
10
+ * @method array getTrace()
11
+ * @method string getTraceAsString()
12
+ */
13
+ interface GuzzleException {}
vendor/guzzlehttp/guzzle/src/Exception/RequestException.php CHANGED
@@ -1,217 +1,217 @@
1
- <?php
2
- namespace GuzzleHttp\Exception;
3
-
4
- use Psr\Http\Message\RequestInterface;
5
- use Psr\Http\Message\ResponseInterface;
6
- use GuzzleHttp\Promise\PromiseInterface;
7
- use Psr\Http\Message\UriInterface;
8
-
9
- /**
10
- * HTTP Request exception
11
- */
12
- class RequestException extends TransferException
13
- {
14
- /** @var RequestInterface */
15
- private $request;
16
-
17
- /** @var ResponseInterface */
18
- private $response;
19
-
20
- /** @var array */
21
- private $handlerContext;
22
-
23
- public function __construct(
24
- $message,
25
- RequestInterface $request,
26
- ResponseInterface $response = null,
27
- \Exception $previous = null,
28
- array $handlerContext = []
29
- ) {
30
- // Set the code of the exception if the response is set and not future.
31
- $code = $response && !($response instanceof PromiseInterface)
32
- ? $response->getStatusCode()
33
- : 0;
34
- parent::__construct($message, $code, $previous);
35
- $this->request = $request;
36
- $this->response = $response;
37
- $this->handlerContext = $handlerContext;
38
- }
39
-
40
- /**
41
- * Wrap non-RequestExceptions with a RequestException
42
- *
43
- * @param RequestInterface $request
44
- * @param \Exception $e
45
- *
46
- * @return RequestException
47
- */
48
- public static function wrapException(RequestInterface $request, \Exception $e)
49
- {
50
- return $e instanceof RequestException
51
- ? $e
52
- : new RequestException($e->getMessage(), $request, null, $e);
53
- }
54
-
55
- /**
56
- * Factory method to create a new exception with a normalized error message
57
- *
58
- * @param RequestInterface $request Request
59
- * @param ResponseInterface $response Response received
60
- * @param \Exception $previous Previous exception
61
- * @param array $ctx Optional handler context.
62
- *
63
- * @return self
64
- */
65
- public static function create(
66
- RequestInterface $request,
67
- ResponseInterface $response = null,
68
- \Exception $previous = null,
69
- array $ctx = []
70
- ) {
71
- if (!$response) {
72
- return new self(
73
- 'Error completing request',
74
- $request,
75
- null,
76
- $previous,
77
- $ctx
78
- );
79
- }
80
-
81
- $level = (int) floor($response->getStatusCode() / 100);
82
- if ($level === 4) {
83
- $label = 'Client error';
84
- $className = ClientException::class;
85
- } elseif ($level === 5) {
86
- $label = 'Server error';
87
- $className = ServerException::class;
88
- } else {
89
- $label = 'Unsuccessful request';
90
- $className = __CLASS__;
91
- }
92
-
93
- $uri = $request->getUri();
94
- $uri = static::obfuscateUri($uri);
95
-
96
- // Client Error: `GET /` resulted in a `404 Not Found` response:
97
- // <html> ... (truncated)
98
- $message = sprintf(
99
- '%s: `%s %s` resulted in a `%s %s` response',
100
- $label,
101
- $request->getMethod(),
102
- $uri,
103
- $response->getStatusCode(),
104
- $response->getReasonPhrase()
105
- );
106
-
107
- $summary = static::getResponseBodySummary($response);
108
-
109
- if ($summary !== null) {
110
- $message .= ":\n{$summary}\n";
111
- }
112
-
113
- return new $className($message, $request, $response, $previous, $ctx);
114
- }
115
-
116
- /**
117
- * Get a short summary of the response
118
- *
119
- * Will return `null` if the response is not printable.
120
- *
121
- * @param ResponseInterface $response
122
- *
123
- * @return string|null
124
- */
125
- public static function getResponseBodySummary(ResponseInterface $response)
126
- {
127
- $body = $response->getBody();
128
-
129
- if (!$body->isSeekable()) {
130
- return null;
131
- }
132
-
133
- $size = $body->getSize();
134
-
135
- if ($size === 0) {
136
- return null;
137
- }
138
-
139
- $summary = $body->read(120);
140
- $body->rewind();
141
-
142
- if ($size > 120) {
143
- $summary .= ' (truncated...)';
144
- }
145
-
146
- // Matches any printable character, including unicode characters:
147
- // letters, marks, numbers, punctuation, spacing, and separators.
148
- if (preg_match('/[^\pL\pM\pN\pP\pS\pZ\n\r\t]/', $summary)) {
149
- return null;
150
- }
151
-
152
- return $summary;
153
- }
154
-
155
- /**
156
- * Obfuscates URI if there is an username and a password present
157
- *
158
- * @param UriInterface $uri
159
- *
160
- * @return UriInterface
161
- */
162
- private static function obfuscateUri($uri)
163
- {
164
- $userInfo = $uri->getUserInfo();
165
-
166
- if (false !== ($pos = strpos($userInfo, ':'))) {
167
- return $uri->withUserInfo(substr($userInfo, 0, $pos), '***');
168
- }
169
-
170
- return $uri;
171
- }
172
-
173
- /**
174
- * Get the request that caused the exception
175
- *
176
- * @return RequestInterface
177
- */
178
- public function getRequest()
179
- {
180
- return $this->request;
181
- }
182
-
183
- /**
184
- * Get the associated response
185
- *
186
- * @return ResponseInterface|null
187
- */
188
- public function getResponse()
189
- {
190
- return $this->response;
191
- }
192
-
193
- /**
194
- * Check if a response was received
195
- *
196
- * @return bool
197
- */
198
- public function hasResponse()
199
- {
200
- return $this->response !== null;
201
- }
202
-
203
- /**
204
- * Get contextual information about the error from the underlying handler.
205
- *
206
- * The contents of this array will vary depending on which handler you are
207
- * using. It may also be just an empty array. Relying on this data will
208
- * couple you to a specific handler, but can give more debug information
209
- * when needed.
210
- *
211
- * @return array
212
- */
213
- public function getHandlerContext()
214
- {
215
- return $this->handlerContext;
216
- }
217
- }
1
+ <?php
2
+ namespace GuzzleHttp\Exception;
3
+
4
+ use Psr\Http\Message\RequestInterface;
5
+ use Psr\Http\Message\ResponseInterface;
6
+ use GuzzleHttp\Promise\PromiseInterface;
7
+ use Psr\Http\Message\UriInterface;
8
+
9
+ /**
10
+ * HTTP Request exception
11
+ */
12
+ class RequestException extends TransferException
13
+ {
14
+ /** @var RequestInterface */
15
+ private $request;
16
+
17
+ /** @var ResponseInterface */
18
+ private $response;
19
+
20
+ /** @var array */
21
+ private $handlerContext;
22
+
23
+ public function __construct(
24
+ $message,
25
+ RequestInterface $request,
26
+ ResponseInterface $response = null,
27
+ \Exception $previous = null,
28
+ array $handlerContext = []
29
+ ) {
30
+ // Set the code of the exception if the response is set and not future.
31
+ $code = $response && !($response instanceof PromiseInterface)
32
+ ? $response->getStatusCode()
33
+ : 0;
34
+ parent::__construct($message, $code, $previous);
35
+ $this->request = $request;
36
+ $this->response = $response;
37
+ $this->handlerContext = $handlerContext;
38
+ }
39
+
40
+ /**
41
+ * Wrap non-RequestExceptions with a RequestException
42
+ *
43
+ * @param RequestInterface $request
44
+ * @param \Exception $e
45
+ *
46
+ * @return RequestException
47
+ */
48
+ public static function wrapException(RequestInterface $request, \Exception $e)
49
+ {
50
+ return $e instanceof RequestException
51
+ ? $e
52
+ : new RequestException($e->getMessage(), $request, null, $e);
53
+ }
54
+
55
+ /**
56
+ * Factory method to create a new exception with a normalized error message
57
+ *
58
+ * @param RequestInterface $request Request
59
+ * @param ResponseInterface $response Response received
60
+ * @param \Exception $previous Previous exception
61
+ * @param array $ctx Optional handler context.
62
+ *
63
+ * @return self
64
+ */
65
+ public static function create(
66
+ RequestInterface $request,
67
+ ResponseInterface $response = null,
68
+ \Exception $previous = null,
69
+ array $ctx = []
70
+ ) {
71
+ if (!$response) {
72
+ return new self(
73
+ 'Error completing request',
74
+ $request,
75
+ null,
76
+ $previous,
77
+ $ctx
78
+ );
79
+ }
80
+
81
+ $level = (int) floor($response->getStatusCode() / 100);
82
+ if ($level === 4) {
83
+ $label = 'Client error';
84
+ $className = ClientException::class;
85
+ } elseif ($level === 5) {
86
+ $label = 'Server error';
87
+ $className = ServerException::class;
88
+ } else {
89
+ $label = 'Unsuccessful request';
90
+ $className = __CLASS__;
91
+ }
92
+
93
+ $uri = $request->getUri();
94
+ $uri = static::obfuscateUri($uri);
95
+
96
+ // Client Error: `GET /` resulted in a `404 Not Found` response:
97
+ // <html> ... (truncated)
98
+ $message = sprintf(
99
+ '%s: `%s %s` resulted in a `%s %s` response',
100
+ $label,
101
+ $request->getMethod(),
102
+ $uri,
103
+ $response->getStatusCode(),
104
+ $response->getReasonPhrase()
105
+ );
106
+
107
+ $summary = static::getResponseBodySummary($response);
108
+
109
+ if ($summary !== null) {
110
+ $message .= ":\n{$summary}\n";
111
+ }
112
+
113
+ return new $className($message, $request, $response, $previous, $ctx);
114
+ }
115
+
116
+ /**
117
+ * Get a short summary of the response
118
+ *
119
+ * Will return `null` if the response is not printable.
120
+ *
121
+ * @param ResponseInterface $response
122
+ *
123
+ * @return string|null
124
+ */
125
+ public static function getResponseBodySummary(ResponseInterface $response)
126
+ {
127
+ $body = $response->getBody();
128
+
129
+ if (!$body->isSeekable()) {
130
+ return null;
131
+ }
132
+
133
+ $size = $body->getSize();
134
+
135
+ if ($size === 0) {
136
+ return null;
137
+ }
138
+
139
+ $summary = $body->read(120);
140
+ $body->rewind();
141
+
142
+ if ($size > 120) {
143
+ $summary .= ' (truncated...)';
144
+ }
145
+
146
+ // Matches any printable character, including unicode characters:
147
+ // letters, marks, numbers, punctuation, spacing, and separators.
148
+ if (preg_match('/[^\pL\pM\pN\pP\pS\pZ\n\r\t]/', $summary)) {
149
+ return null;
150
+ }
151
+
152
+ return $summary;
153
+ }
154
+
155
+ /**
156
+ * Obfuscates URI if there is an username and a password present
157
+ *
158
+ * @param UriInterface $uri
159
+ *
160
+ * @return UriInterface
161
+ */
162
+ private static function obfuscateUri($uri)
163
+ {
164
+ $userInfo = $uri->getUserInfo();
165
+
166
+ if (false !== ($pos = strpos($userInfo, ':'))) {
167
+ return $uri->withUserInfo(substr($userInfo, 0, $pos), '***');
168
+ }
169
+
170
+ return $uri;
171
+ }
172
+
173
+ /**
174
+ * Get the request that caused the exception
175
+ *
176
+ * @return RequestInterface
177
+ */
178
+ public function getRequest()
179
+ {
180
+ return $this->request;
181
+ }
182
+
183
+ /**
184
+ * Get the associated response
185
+ *
186
+ * @return ResponseInterface|null
187
+ */
188
+ public function getResponse()
189
+ {
190
+ return $this->response;
191
+ }
192
+
193
+ /**
194
+ * Check if a response was received
195
+ *
196
+ * @return bool
197
+ */
198
+ public function hasResponse()
199
+ {
200
+ return $this->response !== null;
201
+ }
202
+
203
+ /**
204
+ * Get contextual information about the error from the underlying handler.
205
+ *
206
+ * The contents of this array will vary depending on which handler you are
207
+ * using. It may also be just an empty array. Relying on this data will
208
+ * couple you to a specific handler, but can give more debug information
209
+ * when needed.
210
+ *
211
+ * @return array
212
+ */
213
+ public function getHandlerContext()
214
+ {
215
+ return $this->handlerContext;
216
+ }
217
+ }
vendor/guzzlehttp/guzzle/src/Exception/SeekException.php CHANGED
@@ -1,27 +1,27 @@
1
- <?php
2
- namespace GuzzleHttp\Exception;
3
-
4
- use Psr\Http\Message\StreamInterface;
5
-
6
- /**
7
- * Exception thrown when a seek fails on a stream.
8
- */
9
- class SeekException extends \RuntimeException implements GuzzleException
10
- {
11
- private $stream;
12
-
13
- public function __construct(StreamInterface $stream, $pos = 0, $msg = '')
14
- {
15
- $this->stream = $stream;
16
- $msg = $msg ?: 'Could not seek the stream to position ' . $pos;
17
- parent::__construct($msg);
18
- }
19
-
20
- /**
21
- * @return StreamInterface
22
- */
23
- public function getStream()
24
- {
25
- return $this->stream;
26
- }
27
- }
1
+ <?php
2
+ namespace GuzzleHttp\Exception;
3
+
4
+ use Psr\Http\Message\StreamInterface;
5
+
6
+ /**
7
+ * Exception thrown when a seek fails on a stream.
8
+ */
9
+ class SeekException extends \RuntimeException implements GuzzleException
10
+ {
11
+ private $stream;
12
+
13
+ public function __construct(StreamInterface $stream, $pos = 0, $msg = '')
14
+ {
15
+ $this->stream = $stream;
16
+ $msg = $msg ?: 'Could not seek the stream to position ' . $pos;
17
+ parent::__construct($msg);
18
+ }
19
+
20
+ /**
21
+ * @return StreamInterface
22
+ */
23
+ public function getStream()
24
+ {
25
+ return $this->stream;
26
+ }
27
+ }
vendor/guzzlehttp/guzzle/src/Exception/ServerException.php CHANGED
@@ -1,7 +1,7 @@
1
- <?php
2
- namespace GuzzleHttp\Exception;
3
-
4
- /**
5
- * Exception when a server error is encountered (5xx codes)
6
- */
7
- class ServerException extends BadResponseException {}
1
+ <?php
2
+ namespace GuzzleHttp\Exception;
3
+
4
+ /**
5
+ * Exception when a server error is encountered (5xx codes)
6
+ */
7
+ class ServerException extends BadResponseException {}
vendor/guzzlehttp/guzzle/src/Exception/TooManyRedirectsException.php CHANGED
@@ -1,4 +1,4 @@
1
- <?php
2
- namespace GuzzleHttp\Exception;
3
-
4
- class TooManyRedirectsException extends RequestException {}
1
+ <?php
2
+ namespace GuzzleHttp\Exception;
3
+
4
+ class TooManyRedirectsException extends RequestException {}
vendor/guzzlehttp/guzzle/src/Exception/TransferException.php CHANGED
@@ -1,4 +1,4 @@
1
- <?php
2
- namespace GuzzleHttp\Exception;
3
-
4
- class TransferException extends \RuntimeException implements GuzzleException {}
1
+ <?php
2
+ namespace GuzzleHttp\Exception;
3
+
4
+ class TransferException extends \RuntimeException implements GuzzleException {}
vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php CHANGED
@@ -1,565 +1,565 @@
1
- <?php
2
- namespace GuzzleHttp\Handler;
3
-
4
- use GuzzleHttp\Exception\RequestException;
5
- use GuzzleHttp\Exception\ConnectException;
6
- use GuzzleHttp\Promise\FulfilledPromise;
7
- use GuzzleHttp\Psr7;
8
- use GuzzleHttp\Psr7\LazyOpenStream;
9
- use GuzzleHttp\TransferStats;
10
- use Psr\Http\Message\RequestInterface;
11
-
12
- /**
13
- * Creates curl resources from a request
14
- */
15
- class CurlFactory implements CurlFactoryInterface
16
- {
17
- /** @var array */
18
- private $handles = [];
19
-
20
- /** @var int Total number of idle handles to keep in cache */
21
- private $maxHandles;
22
-
23
- /**
24
- * @param int $maxHandles Maximum number of idle handles.
25
- */
26
- public function __construct($maxHandles)
27
- {
28
- $this->maxHandles = $maxHandles;
29
- }
30
-
31
- public function create(RequestInterface $request, array $options)
32
- {
33
- if (isset($options['curl']['body_as_string'])) {
34
- $options['_body_as_string'] = $options['curl']['body_as_string'];
35
- unset($options['curl']['body_as_string']);
36
- }
37
-
38
- $easy = new EasyHandle;
39
- $easy->request = $request;
40
- $easy->options = $options;
41
- $conf = $this->getDefaultConf($easy);
42
- $this->applyMethod($easy, $conf);
43
- $this->applyHandlerOptions($easy, $conf);
44
- $this->applyHeaders($easy, $conf);
45
- unset($conf['_headers']);
46
-
47
- // Add handler options from the request configuration options
48
- if (isset($options['curl'])) {
49
- $conf = array_replace($conf, $options['curl']);
50
- }
51
-
52
- $conf[CURLOPT_HEADERFUNCTION] = $this->createHeaderFn($easy);
53
- $easy->handle = $this->handles
54
- ? array_pop($this->handles)
55
- : curl_init();
56
- curl_setopt_array($easy->handle, $conf);
57
-
58
- return $easy;
59
- }
60
-
61
- public function release(EasyHandle $easy)
62
- {
63
- $resource = $easy->handle;
64
- unset($easy->handle);
65
-
66
- if (count($this->handles) >= $this->maxHandles) {
67
- curl_close($resource);
68
- } else {
69
- // Remove all callback functions as they can hold onto references
70
- // and are not cleaned up by curl_reset. Using curl_setopt_array
71
- // does not work for some reason, so removing each one
72
- // individually.
73
- curl_setopt($resource, CURLOPT_HEADERFUNCTION, null);
74
- curl_setopt($resource, CURLOPT_READFUNCTION, null);
75
- curl_setopt($resource, CURLOPT_WRITEFUNCTION, null);
76
- curl_setopt($resource, CURLOPT_PROGRESSFUNCTION, null);
77
- curl_reset($resource);
78
- $this->handles[] = $resource;
79
- }
80
- }
81
-
82
- /**
83
- * Completes a cURL transaction, either returning a response promise or a
84
- * rejected promise.
85
- *
86
- * @param callable $handler
87
- * @param EasyHandle $easy
88
- * @param CurlFactoryInterface $factory Dictates how the handle is released
89
- *
90
- * @return \GuzzleHttp\Promise\PromiseInterface
91
- */
92
- public static function finish(
93
- callable $handler,
94
- EasyHandle $easy,
95
- CurlFactoryInterface $factory
96
- ) {
97
- if (isset($easy->options['on_stats'])) {
98
- self::invokeStats($easy);
99
- }
100
-
101
- if (!$easy->response || $easy->errno) {
102
- return self::finishError($handler, $easy, $factory);
103
- }
104
-
105
- // Return the response if it is present and there is no error.
106
- $factory->release($easy);
107
-
108
- // Rewind the body of the response if possible.
109
- $body = $easy->response->getBody();
110
- if ($body->isSeekable()) {
111
- $body->rewind();
112
- }
113
-
114
- return new FulfilledPromise($easy->response);
115
- }
116
-
117
- private static function invokeStats(EasyHandle $easy)
118
- {
119
- $curlStats = curl_getinfo($easy->handle);
120
- $stats = new TransferStats(
121
- $easy->request,
122
- $easy->response,
123
- $curlStats['total_time'],
124
- $easy->errno,
125
- $curlStats
126
- );
127
- call_user_func($easy->options['on_stats'], $stats);
128
- }
129
-
130
- private static function finishError(
131
- callable $handler,
132
- EasyHandle $easy,
133
- CurlFactoryInterface $factory
134
- ) {
135
- // Get error information and release the handle to the factory.
136
- $ctx = [
137
- 'errno' => $easy->errno,
138
- 'error' => curl_error($easy->handle),
139
- ] + curl_getinfo($easy->handle);
140
- $factory->release($easy);
141
-
142
- // Retry when nothing is present or when curl failed to rewind.
143
- if (empty($easy->options['_err_message'])
144
- && (!$easy->errno || $easy->errno == 65)
145
- ) {
146
- return self::retryFailedRewind($handler, $easy, $ctx);
147
- }
148
-
149
- return self::createRejection($easy, $ctx);
150
- }
151
-
152
- private static function createRejection(EasyHandle $easy, array $ctx)
153
- {
154
- static $connectionErrors = [
155
- CURLE_OPERATION_TIMEOUTED => true,
156
- CURLE_COULDNT_RESOLVE_HOST => true,
157
- CURLE_COULDNT_CONNECT => true,
158
- CURLE_SSL_CONNECT_ERROR => true,
159
- CURLE_GOT_NOTHING => true,
160
- ];
161
-
162
- // If an exception was encountered during the onHeaders event, then
163
- // return a rejected promise that wraps that exception.
164
- if ($easy->onHeadersException) {
165
- return \GuzzleHttp\Promise\rejection_for(
166
- new RequestException(
167
- 'An error was encountered during the on_headers event',
168
- $easy->request,
169
- $easy->response,
170
- $easy->onHeadersException,
171
- $ctx
172
- )
173
- );
174
- }
175
-
176
- $message = sprintf(
177
- 'cURL error %s: %s (%s)',
178
- $ctx['errno'],
179
- $ctx['error'],
180
- 'see http://curl.haxx.se/libcurl/c/libcurl-errors.html'
181
- );
182
-
183
- // Create a connection exception if it was a specific error code.
184
- $error = isset($connectionErrors[$easy->errno])
185
- ? new ConnectException($message, $easy->request, null, $ctx)
186
- : new RequestException($message, $easy->request, $easy->response, null, $ctx);
187
-
188
- return \GuzzleHttp\Promise\rejection_for($error);
189
- }
190
-
191
- private function getDefaultConf(EasyHandle $easy)
192
- {
193
- $conf = [
194
- '_headers' => $easy->request->getHeaders(),
195
- CURLOPT_CUSTOMREQUEST => $easy->request->getMethod(),
196
- CURLOPT_URL => (string) $easy->request->getUri()->withFragment(''),
197
- CURLOPT_RETURNTRANSFER => false,
198
- CURLOPT_HEADER => false,
199
- CURLOPT_CONNECTTIMEOUT => 150,
200
- ];
201
-
202
- if (defined('CURLOPT_PROTOCOLS')) {
203
- $conf[CURLOPT_PROTOCOLS] = CURLPROTO_HTTP | CURLPROTO_HTTPS;
204
- }
205
-
206
- $version = $easy->request->getProtocolVersion();
207
- if ($version == 1.1) {
208
- $conf[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_1_1;
209
- } elseif ($version == 2.0) {
210
- $conf[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_2_0;
211
- } else {
212
- $conf[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_1_0;
213
- }
214
-
215
- return $conf;
216
- }
217
-
218
- private function applyMethod(EasyHandle $easy, array &$conf)
219
- {
220
- $body = $easy->request->getBody();
221
- $size = $body->getSize();
222
-
223
- if ($size === null || $size > 0) {
224
- $this->applyBody($easy->request, $easy->options, $conf);
225
- return;
226
- }
227
-
228
- $method = $easy->request->getMethod();
229
- if ($method === 'PUT' || $method === 'POST') {
230
- // See http://tools.ietf.org/html/rfc7230#section-3.3.2
231
- if (!$easy->request->hasHeader('Content-Length')) {
232
- $conf[CURLOPT_HTTPHEADER][] = 'Content-Length: 0';
233
- }
234
- } elseif ($method === 'HEAD') {
235
- $conf[CURLOPT_NOBODY] = true;
236
- unset(
237
- $conf[CURLOPT_WRITEFUNCTION],
238
- $conf[CURLOPT_READFUNCTION],
239
- $conf[CURLOPT_FILE],
240
- $conf[CURLOPT_INFILE]
241
- );
242
- }
243
- }
244
-
245
- private function applyBody(RequestInterface $request, array $options, array &$conf)
246
- {
247
- $size = $request->hasHeader('Content-Length')
248
- ? (int) $request->getHeaderLine('Content-Length')
249
- : null;
250
-
251
- // Send the body as a string if the size is less than 1MB OR if the
252
- // [curl][body_as_string] request value is set.
253
- if (($size !== null && $size < 1000000) ||
254
- !empty($options['_body_as_string'])
255
- ) {
256
- $conf[CURLOPT_POSTFIELDS] = (string) $request->getBody();
257
- // Don't duplicate the Content-Length header
258
- $this->removeHeader('Content-Length', $conf);
259
- $this->removeHeader('Transfer-Encoding', $conf);
260
- } else {
261
- $conf[CURLOPT_UPLOAD] = true;
262
- if ($size !== null) {
263
- $conf[CURLOPT_INFILESIZE] = $size;
264
- $this->removeHeader('Content-Length', $conf);
265
- }
266
- $body = $request->getBody();
267
- if ($body->isSeekable()) {
268
- $body->rewind();
269
- }
270
- $conf[CURLOPT_READFUNCTION] = function ($ch, $fd, $length) use ($body) {
271
- return $body->read($length);
272
- };
273
- }
274
-
275
- // If the Expect header is not present, prevent curl from adding it
276
- if (!$request->hasHeader('Expect')) {
277
- $conf[CURLOPT_HTTPHEADER][] = 'Expect:';
278
- }
279
-
280
- // cURL sometimes adds a content-type by default. Prevent this.
281
- if (!$request->hasHeader('Content-Type')) {
282
- $conf[CURLOPT_HTTPHEADER][] = 'Content-Type:';
283
- }
284
- }
285
-
286
- private function applyHeaders(EasyHandle $easy, array &$conf)
287
- {
288
- foreach ($conf['_headers'] as $name => $values) {
289
- foreach ($values as $value) {
290
- $value = (string) $value;
291
- if ($value === '') {
292
- // cURL requires a special format for empty headers.
293
- // See https://github.com/guzzle/guzzle/issues/1882 for more details.
294
- $conf[CURLOPT_HTTPHEADER][] = "$name;";
295
- } else {
296
- $conf[CURLOPT_HTTPHEADER][] = "$name: $value";
297
- }
298
- }
299
- }
300
-
301
- // Remove the Accept header if one was not set
302
- if (!$easy->request->hasHeader('Accept')) {
303
- $conf[CURLOPT_HTTPHEADER][] = 'Accept:';
304
- }
305
- }
306
-
307
- /**
308
- * Remove a header from the options array.
309
- *
310
- * @param string $name Case-insensitive header to remove
311
- * @param array $options Array of options to modify
312
- */
313
- private function removeHeader($name, array &$options)
314
- {
315
- foreach (array_keys($options['_headers']) as $key) {
316
- if (!strcasecmp($key, $name)) {
317
- unset($options['_headers'][$key]);
318
- return;
319
- }
320
- }
321
- }
322
-
323
- private function applyHandlerOptions(EasyHandle $easy, array &$conf)
324
- {
325
- $options = $easy->options;
326
- if (isset($options['verify'])) {
327
- if ($options['verify'] === false) {
328
- unset($conf[CURLOPT_CAINFO]);
329
- $conf[CURLOPT_SSL_VERIFYHOST] = 0;
330
- $conf[CURLOPT_SSL_VERIFYPEER] = false;
331
- } else {
332
- $conf[CURLOPT_SSL_VERIFYHOST] = 2;
333
- $conf[CURLOPT_SSL_VERIFYPEER] = true;
334
- if (is_string($options['verify'])) {
335
- // Throw an error if the file/folder/link path is not valid or doesn't exist.
336
- if (!file_exists($options['verify'])) {
337
- throw new \InvalidArgumentException(
338
- "SSL CA bundle not found: {$options['verify']}"
339
- );
340
- }
341
- // If it's a directory or a link to a directory use CURLOPT_CAPATH.
342
- // If not, it's probably a file, or a link to a file, so use CURLOPT_CAINFO.
343
- if (is_dir($options['verify']) ||
344
- (is_link($options['verify']) && is_dir(readlink($options['verify'])))) {
345
- $conf[CURLOPT_CAPATH] = $options['verify'];
346
- } else {
347
- $conf[CURLOPT_CAINFO] = $options['verify'];
348
- }
349
- }
350
- }
351
- }
352
-
353
- if (!empty($options['decode_content'])) {
354
- $accept = $easy->request->getHeaderLine('Accept-Encoding');
355
- if ($accept) {
356
- $conf[CURLOPT_ENCODING] = $accept;
357
- } else {
358
- $conf[CURLOPT_ENCODING] = '';
359
- // Don't let curl send the header over the wire
360
- $conf[CURLOPT_HTTPHEADER][] = 'Accept-Encoding:';
361
- }
362
- }
363
-
364
- if (isset($options['sink'])) {
365
- $sink = $options['sink'];
366
- if (!is_string($sink)) {
367
- $sink = \GuzzleHttp\Psr7\stream_for($sink);
368
- } elseif (!is_dir(dirname($sink))) {
369
- // Ensure that the directory exists before failing in curl.
370
- throw new \RuntimeException(sprintf(
371
- 'Directory %s does not exist for sink value of %s',
372
- dirname($sink),
373
- $sink
374
- ));
375
- } else {
376
- $sink = new LazyOpenStream($sink, 'w+');
377
- }
378
- $easy->sink = $sink;
379
- $conf[CURLOPT_WRITEFUNCTION] = function ($ch, $write) use ($sink) {
380
- return $sink->write($write);
381
- };
382
- } else {
383
- // Use a default temp stream if no sink was set.
384
- $conf[CURLOPT_FILE] = fopen('php://temp', 'w+');
385
- $easy->sink = Psr7\stream_for($conf[CURLOPT_FILE]);
386
- }
387
- $timeoutRequiresNoSignal = false;
388
- if (isset($options['timeout'])) {
389
- $timeoutRequiresNoSignal |= $options['timeout'] < 1;
390
- $conf[CURLOPT_TIMEOUT_MS] = $options['timeout'] * 1000;
391
- }
392
-
393
- // CURL default value is CURL_IPRESOLVE_WHATEVER
394
- if (isset($options['force_ip_resolve'])) {
395
- if ('v4' === $options['force_ip_resolve']) {
396
- $conf[CURLOPT_IPRESOLVE] = CURL_IPRESOLVE_V4;
397
- } elseif ('v6' === $options['force_ip_resolve']) {
398
- $conf[CURLOPT_IPRESOLVE] = CURL_IPRESOLVE_V6;
399
- }
400
- }
401
-
402
- if (isset($options['connect_timeout'])) {
403
- $timeoutRequiresNoSignal |= $options['connect_timeout'] < 1;
404
- $conf[CURLOPT_CONNECTTIMEOUT_MS] = $options['connect_timeout'] * 1000;
405
- }
406
-
407
- if ($timeoutRequiresNoSignal && strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') {
408
- $conf[CURLOPT_NOSIGNAL] = true;
409
- }
410
-
411
- if (isset($options['proxy'])) {
412
- if (!is_array($options['proxy'])) {
413
- $conf[CURLOPT_PROXY] = $options['proxy'];
414
- } else {
415
- $scheme = $easy->request->getUri()->getScheme();
416
- if (isset($options['proxy'][$scheme])) {
417
- $host = $easy->request->getUri()->getHost();
418
- if (!isset($options['proxy']['no']) ||
419
- !\GuzzleHttp\is_host_in_noproxy($host, $options['proxy']['no'])
420
- ) {
421
- $conf[CURLOPT_PROXY] = $options['proxy'][$scheme];
422
- }
423
- }
424
- }
425
- }
426
-
427
- if (isset($options['cert'])) {
428
- $cert = $options['cert'];
429
- if (is_array($cert)) {
430
- $conf[CURLOPT_SSLCERTPASSWD] = $cert[1];
431
- $cert = $cert[0];
432
- }
433
- if (!file_exists($cert)) {
434
- throw new \InvalidArgumentException(
435
- "SSL certificate not found: {$cert}"
436
- );
437
- }
438
- $conf[CURLOPT_SSLCERT] = $cert;
439
- }
440
-
441
- if (isset($options['ssl_key'])) {
442
- $sslKey = $options['ssl_key'];
443
- if (is_array($sslKey)) {
444
- $conf[CURLOPT_SSLKEYPASSWD] = $sslKey[1];
445
- $sslKey = $sslKey[0];
446
- }
447
- if (!file_exists($sslKey)) {
448
- throw new \InvalidArgumentException(
449
- "SSL private key not found: {$sslKey}"
450
- );
451
- }
452
- $conf[CURLOPT_SSLKEY] = $sslKey;
453
- }
454
-
455
- if (isset($options['progress'])) {
456
- $progress = $options['progress'];
457
- if (!is_callable($progress)) {
458
- throw new \InvalidArgumentException(
459
- 'progress client option must be callable'
460
- );
461
- }
462
- $conf[CURLOPT_NOPROGRESS] = false;
463
- $conf[CURLOPT_PROGRESSFUNCTION] = function () use ($progress) {
464
- $args = func_get_args();
465
- // PHP 5.5 pushed the handle onto the start of the args
466
- if (is_resource($args[0])) {
467
- array_shift($args);
468
- }
469
- call_user_func_array($progress, $args);
470
- };
471
- }
472
-
473
- if (!empty($options['debug'])) {
474
- $conf[CURLOPT_STDERR] = \GuzzleHttp\debug_resource($options['debug']);
475
- $conf[CURLOPT_VERBOSE] = true;
476
- }
477
- }
478
-
479
- /**
480
- * This function ensures that a response was set on a transaction. If one
481
- * was not set, then the request is retried if possible. This error
482
- * typically means you are sending a payload, curl encountered a
483
- * "Connection died, retrying a fresh connect" error, tried to rewind the
484
- * stream, and then encountered a "necessary data rewind wasn't possible"
485
- * error, causing the request to be sent through curl_multi_info_read()
486
- * without an error status.
487
- */
488
- private static function retryFailedRewind(
489
- callable $handler,
490
- EasyHandle $easy,
491
- array $ctx
492
- ) {
493
- try {
494
- // Only rewind if the body has been read from.
495
- $body = $easy->request->getBody();
496
- if ($body->tell() > 0) {
497
- $body->rewind();
498
- }
499
- } catch (\RuntimeException $e) {
500
- $ctx['error'] = 'The connection unexpectedly failed without '
501
- . 'providing an error. The request would have been retried, '
502
- . 'but attempting to rewind the request body failed. '
503
- . 'Exception: ' . $e;
504
- return self::createRejection($easy, $ctx);
505
- }
506
-
507
- // Retry no more than 3 times before giving up.
508
- if (!isset($easy->options['_curl_retries'])) {
509
- $easy->options['_curl_retries'] = 1;
510
- } elseif ($easy->options['_curl_retries'] == 2) {
511
- $ctx['error'] = 'The cURL request was retried 3 times '
512
- . 'and did not succeed. The most likely reason for the failure '
513
- . 'is that cURL was unable to rewind the body of the request '
514
- . 'and subsequent retries resulted in the same error. Turn on '
515
- . 'the debug option to see what went wrong. See '
516
- . 'https://bugs.php.net/bug.php?id=47204 for more information.';
517
- return self::createRejection($easy, $ctx);
518
- } else {
519
- $easy->options['_curl_retries']++;
520
- }
521
-
522
- return $handler($easy->request, $easy->options);
523
- }
524
-
525
- private function createHeaderFn(EasyHandle $easy)
526
- {
527
- if (isset($easy->options['on_headers'])) {
528
- $onHeaders = $easy->options['on_headers'];
529
-
530
- if (!is_callable($onHeaders)) {
531
- throw new \InvalidArgumentException('on_headers must be callable');
532
- }
533
- } else {
534
- $onHeaders = null;
535
- }
536
-
537
- return function ($ch, $h) use (
538
- $onHeaders,
539
- $easy,
540
- &$startingResponse
541
- ) {
542
- $value = trim($h);
543
- if ($value === '') {
544
- $startingResponse = true;
545
- $easy->createResponse();
546
- if ($onHeaders !== null) {
547
- try {
548
- $onHeaders($easy->response);
549
- } catch (\Exception $e) {
550
- // Associate the exception with the handle and trigger
551
- // a curl header write error by returning 0.
552
- $easy->onHeadersException = $e;
553
- return -1;
554
- }
555
- }
556
- } elseif ($startingResponse) {
557
- $startingResponse = false;
558
- $easy->headers = [$value];
559
- } else {
560
- $easy->headers[] = $value;
561
- }
562
- return strlen($h);
563
- };
564
- }
565
- }
1
+ <?php
2
+ namespace GuzzleHttp\Handler;
3
+
4
+ use GuzzleHttp\Exception\RequestException;
5
+ use GuzzleHttp\Exception\ConnectException;
6
+ use GuzzleHttp\Promise\FulfilledPromise;
7
+ use GuzzleHttp\Psr7;
8
+ use GuzzleHttp\Psr7\LazyOpenStream;
9
+ use GuzzleHttp\TransferStats;
10
+ use Psr\Http\Message\RequestInterface;
11
+
12
+ /**
13
+ * Creates curl resources from a request
14
+ */
15
+ class CurlFactory implements CurlFactoryInterface
16
+ {
17
+ /** @var array */
18
+ private $handles = [];
19
+
20
+ /** @var int Total number of idle handles to keep in cache */
21
+ private $maxHandles;
22
+
23
+ /**
24
+ * @param int $maxHandles Maximum number of idle handles.
25
+ */
26
+ public function __construct($maxHandles)
27
+ {
28
+ $this->maxHandles = $maxHandles;
29
+ }
30
+
31
+ public function create(RequestInterface $request, array $options)
32
+ {
33
+ if (isset($options['curl']['body_as_string'])) {
34
+ $options['_body_as_string'] = $options['curl']['body_as_string'];
35
+ unset($options['curl']['body_as_string']);
36
+ }
37
+
38
+ $easy = new EasyHandle;
39
+ $easy->request = $request;
40
+ $easy->options = $options;
41
+ $conf = $this->getDefaultConf($easy);
42
+ $this->applyMethod($easy, $conf);
43
+ $this->applyHandlerOptions($easy, $conf);
44
+ $this->applyHeaders($easy, $conf);
45
+ unset($conf['_headers']);
46
+
47
+ // Add handler options from the request configuration options
48
+ if (isset($options['curl'])) {
49
+ $conf = array_replace($conf, $options['curl']);
50
+ }
51
+
52
+ $conf[CURLOPT_HEADERFUNCTION] = $this->createHeaderFn($easy);
53
+ $easy->handle = $this->handles
54
+ ? array_pop($this->handles)
55
+ : curl_init();
56
+ curl_setopt_array($easy->handle, $conf);
57
+
58
+ return $easy;
59
+ }
60
+
61
+ public function release(EasyHandle $easy)
62
+ {
63
+ $resource = $easy->handle;
64
+ unset($easy->handle);
65
+
66
+ if (count($this->handles) >= $this->maxHandles) {
67
+ curl_close($resource);
68
+ } else {
69
+ // Remove all callback functions as they can hold onto references
70
+ // and are not cleaned up by curl_reset. Using curl_setopt_array
71
+ // does not work for some reason, so removing each one
72
+ // individually.
73
+ curl_setopt($resource, CURLOPT_HEADERFUNCTION, null);
74
+ curl_setopt($resource, CURLOPT_READFUNCTION, null);
75
+ curl_setopt($resource, CURLOPT_WRITEFUNCTION, null);
76
+ curl_setopt($resource, CURLOPT_PROGRESSFUNCTION, null);
77
+ curl_reset($resource);
78
+ $this->handles[] = $resource;
79
+ }
80
+ }
81
+
82
+ /**
83
+ * Completes a cURL transaction, either returning a response promise or a
84
+ * rejected promise.
85
+ *
86
+ * @param callable $handler
87
+ * @param EasyHandle $easy
88
+ * @param CurlFactoryInterface $factory Dictates how the handle is released
89
+ *
90
+ * @return \GuzzleHttp\Promise\PromiseInterface
91
+ */
92
+ public static function finish(
93
+ callable $handler,
94
+ EasyHandle $easy,
95
+ CurlFactoryInterface $factory
96
+ ) {
97
+ if (isset($easy->options['on_stats'])) {
98
+ self::invokeStats($easy);
99
+ }
100
+
101
+ if (!$easy->response || $easy->errno) {
102
+ return self::finishError($handler, $easy, $factory);
103
+ }
104
+
105
+ // Return the response if it is present and there is no error.
106
+ $factory->release($easy);
107
+
108
+ // Rewind the body of the response if possible.
109
+ $body = $easy->response->getBody();
110
+ if ($body->isSeekable()) {
111
+ $body->rewind();
112
+ }
113
+
114
+ return new FulfilledPromise($easy->response);
115
+ }
116
+
117
+ private static function invokeStats(EasyHandle $easy)
118
+ {
119
+ $curlStats = curl_getinfo($easy->handle);
120
+ $stats = new TransferStats(
121
+ $easy->request,
122
+ $easy->response,
123
+ $curlStats['total_time'],
124
+ $easy->errno,
125
+ $curlStats
126
+ );
127
+ call_user_func($easy->options['on_stats'], $stats);
128
+ }
129
+
130
+ private static function finishError(
131
+ callable $handler,
132
+ EasyHandle $easy,
133
+ CurlFactoryInterface $factory
134
+ ) {
135
+ // Get error information and release the handle to the factory.
136
+ $ctx = [
137
+ 'errno' => $easy->errno,
138
+ 'error' => curl_error($easy->handle),
139
+ ] + curl_getinfo($easy->handle);
140
+ $factory->release($easy);
141
+
142
+ // Retry when nothing is present or when curl failed to rewind.
143
+ if (empty($easy->options['_err_message'])
144
+ && (!$easy->errno || $easy->errno == 65)
145
+ ) {
146
+ return self::retryFailedRewind($handler, $easy, $ctx);
147
+ }
148
+
149
+ return self::createRejection($easy, $ctx);
150
+ }
151
+
152
+ private static function createRejection(EasyHandle $easy, array $ctx)
153
+ {
154
+ static $connectionErrors = [
155
+ CURLE_OPERATION_TIMEOUTED => true,
156
+ CURLE_COULDNT_RESOLVE_HOST => true,
157
+ CURLE_COULDNT_CONNECT => true,
158
+ CURLE_SSL_CONNECT_ERROR => true,
159
+ CURLE_GOT_NOTHING => true,
160
+ ];
161
+
162
+ // If an exception was encountered during the onHeaders event, then
163
+ // return a rejected promise that wraps that exception.
164
+ if ($easy->onHeadersException) {
165
+ return \GuzzleHttp\Promise\rejection_for(
166
+ new RequestException(
167
+ 'An error was encountered during the on_headers event',
168
+ $easy->request,
169
+ $easy->response,
170
+ $easy->onHeadersException,
171
+ $ctx
172
+ )
173
+ );
174
+ }
175
+
176
+ $message = sprintf(
177
+ 'cURL error %s: %s (%s)',
178
+ $ctx['errno'],
179
+ $ctx['error'],
180
+ 'see http://curl.haxx.se/libcurl/c/libcurl-errors.html'
181
+ );
182
+
183
+ // Create a connection exception if it was a specific error code.
184
+ $error = isset($connectionErrors[$easy->errno])
185
+ ? new ConnectException($message, $easy->request, null, $ctx)
186
+ : new RequestException($message, $easy->request, $easy->response, null, $ctx);
187
+
188
+ return \GuzzleHttp\Promise\rejection_for($error);
189
+ }
190
+
191
+ private function getDefaultConf(EasyHandle $easy)
192
+ {
193
+ $conf = [
194
+ '_headers' => $easy->request->getHeaders(),
195
+ CURLOPT_CUSTOMREQUEST => $easy->request->getMethod(),
196
+ CURLOPT_URL => (string) $easy->request->getUri()->withFragment(''),
197
+ CURLOPT_RETURNTRANSFER => false,
198
+ CURLOPT_HEADER => false,
199
+ CURLOPT_CONNECTTIMEOUT => 150,
200
+ ];
201
+
202
+ if (defined('CURLOPT_PROTOCOLS')) {
203
+ $conf[CURLOPT_PROTOCOLS] = CURLPROTO_HTTP | CURLPROTO_HTTPS;
204
+ }
205
+
206
+ $version = $easy->request->getProtocolVersion();
207
+ if ($version == 1.1) {
208
+ $conf[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_1_1;
209
+ } elseif ($version == 2.0) {
210
+ $conf[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_2_0;
211
+ } else {
212
+ $conf[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_1_0;
213
+ }
214
+
215
+ return $conf;
216
+ }
217
+
218
+ private function applyMethod(EasyHandle $easy, array &$conf)
219
+ {
220
+ $body = $easy->request->getBody();
221
+ $size = $body->getSize();
222
+
223
+ if ($size === null || $size > 0) {
224
+ $this->applyBody($easy->request, $easy->options, $conf);
225
+ return;
226
+ }
227
+
228
+ $method = $easy->request->getMethod();
229
+ if ($method === 'PUT' || $method === 'POST') {
230
+ // See http://tools.ietf.org/html/rfc7230#section-3.3.2
231
+ if (!$easy->request->hasHeader('Content-Length')) {
232
+ $conf[CURLOPT_HTTPHEADER][] = 'Content-Length: 0';
233
+ }
234
+ } elseif ($method === 'HEAD') {
235
+ $conf[CURLOPT_NOBODY] = true;
236
+ unset(
237
+ $conf[CURLOPT_WRITEFUNCTION],
238
+ $conf[CURLOPT_READFUNCTION],
239
+ $conf[CURLOPT_FILE],
240
+ $conf[CURLOPT_INFILE]
241
+ );
242
+ }
243
+ }
244
+
245
+ private function applyBody(RequestInterface $request, array $options, array &$conf)
246
+ {
247
+ $size = $request->hasHeader('Content-Length')
248
+ ? (int) $request->getHeaderLine('Content-Length')
249
+ : null;
250
+
251
+ // Send the body as a string if the size is less than 1MB OR if the
252
+ // [curl][body_as_string] request value is set.
253
+ if (($size !== null && $size < 1000000) ||
254
+ !empty($options['_body_as_string'])
255
+ ) {
256
+ $conf[CURLOPT_POSTFIELDS] = (string) $request->getBody();
257
+ // Don't duplicate the Content-Length header
258
+ $this->removeHeader('Content-Length', $conf);
259
+ $this->removeHeader('Transfer-Encoding', $conf);
260
+ } else {
261
+ $conf[CURLOPT_UPLOAD] = true;
262
+ if ($size !== null) {
263
+ $conf[CURLOPT_INFILESIZE] = $size;
264
+ $this->removeHeader('Content-Length', $conf);
265
+ }
266
+ $body = $request->getBody();
267
+ if ($body->isSeekable()) {
268
+ $body->rewind();
269
+ }
270
+ $conf[CURLOPT_READFUNCTION] = function ($ch, $fd, $length) use ($body) {
271
+ return $body->read($length);
272
+ };
273
+ }
274
+
275
+ // If the Expect header is not present, prevent curl from adding it
276
+ if (!$request->hasHeader('Expect')) {
277
+ $conf[CURLOPT_HTTPHEADER][] = 'Expect:';
278
+ }
279
+
280
+ // cURL sometimes adds a content-type by default. Prevent this.
281
+ if (!$request->hasHeader('Content-Type')) {
282
+ $conf[CURLOPT_HTTPHEADER][] = 'Content-Type:';
283
+ }
284
+ }
285
+
286
+ private function applyHeaders(EasyHandle $easy, array &$conf)
287
+ {
288
+ foreach ($conf['_headers'] as $name => $values) {
289
+ foreach ($values as $value) {
290
+ $value = (string) $value;
291
+ if ($value === '') {
292
+ // cURL requires a special format for empty headers.
293
+ // See https://github.com/guzzle/guzzle/issues/1882 for more details.
294
+ $conf[CURLOPT_HTTPHEADER][] = "$name;";
295
+ } else {
296
+ $conf[CURLOPT_HTTPHEADER][] = "$name: $value";
297
+ }
298
+ }
299
+ }
300
+
301
+ // Remove the Accept header if one was not set
302
+ if (!$easy->request->hasHeader('Accept')) {
303
+ $conf[CURLOPT_HTTPHEADER][] = 'Accept:';
304
+ }
305
+ }
306
+
307
+ /**
308
+ * Remove a header from the options array.
309
+ *
310
+ * @param string $name Case-insensitive header to remove
311
+ * @param array $options Array of options to modify
312
+ */
313
+ private function removeHeader($name, array &$options)
314
+ {
315
+ foreach (array_keys($options['_headers']) as $key) {
316
+ if (!strcasecmp($key, $name)) {
317
+ unset($options['_headers'][$key]);
318
+ return;
319
+ }
320
+ }
321
+ }
322
+
323
+ private function applyHandlerOptions(EasyHandle $easy, array &$conf)
324
+ {
325
+ $options = $easy->options;
326
+ if (isset($options['verify'])) {
327
+ if ($options['verify'] === false) {
328
+ unset($conf[CURLOPT_CAINFO]);
329
+ $conf[CURLOPT_SSL_VERIFYHOST] = 0;
330
+ $conf[CURLOPT_SSL_VERIFYPEER] = false;
331
+ } else {
332
+ $conf[CURLOPT_SSL_VERIFYHOST] = 2;
333
+ $conf[CURLOPT_SSL_VERIFYPEER] = true;
334
+ if (is_string($options['verify'])) {
335
+ // Throw an error if the file/folder/link path is not valid or doesn't exist.
336
+ if (!file_exists($options['verify'])) {
337
+ throw new \InvalidArgumentException(
338
+ "SSL CA bundle not found: {$options['verify']}"
339
+ );
340
+ }
341
+ // If it's a directory or a link to a directory use CURLOPT_CAPATH.
342
+ // If not, it's probably a file, or a link to a file, so use CURLOPT_CAINFO.
343
+ if (is_dir($options['verify']) ||
344
+ (is_link($options['verify']) && is_dir(readlink($options['verify'])))) {
345
+ $conf[CURLOPT_CAPATH] = $options['verify'];
346
+ } else {
347
+ $conf[CURLOPT_CAINFO] = $options['verify'];
348
+ }
349
+ }
350
+ }
351
+ }
352
+
353
+ if (!empty($options['decode_content'])) {
354
+ $accept = $easy->request->getHeaderLine('Accept-Encoding');
355
+ if ($accept) {
356
+ $conf[CURLOPT_ENCODING] = $accept;
357
+ } else {
358
+ $conf[CURLOPT_ENCODING] = '';
359
+ // Don't let curl send the header over the wire
360
+ $conf[CURLOPT_HTTPHEADER][] = 'Accept-Encoding:';
361
+ }
362
+ }
363
+
364
+ if (isset($options['sink'])) {
365
+ $sink = $options['sink'];
366
+ if (!is_string($sink)) {
367
+ $sink = \GuzzleHttp\Psr7\stream_for($sink);
368
+ } elseif (!is_dir(dirname($sink))) {
369
+ // Ensure that the directory exists before failing in curl.
370
+ throw new \RuntimeException(sprintf(
371
+ 'Directory %s does not exist for sink value of %s',
372
+ dirname($sink),
373
+ $sink
374
+ ));
375
+ } else {
376
+ $sink = new LazyOpenStream($sink, 'w+');
377
+ }
378
+ $easy->sink = $sink;
379
+ $conf[CURLOPT_WRITEFUNCTION] = function ($ch, $write) use ($sink) {
380
+ return $sink->write($write);
381
+ };
382
+ } else {
383
+ // Use a default temp stream if no sink was set.
384
+ $conf[CURLOPT_FILE] = fopen('php://temp', 'w+');
385
+ $easy->sink = Psr7\stream_for($conf[CURLOPT_FILE]);
386
+ }
387
+ $timeoutRequiresNoSignal = false;
388
+ if (isset($options['timeout'])) {
389
+ $timeoutRequiresNoSignal |= $options['timeout'] < 1;
390
+ $conf[CURLOPT_TIMEOUT_MS] = $options['timeout'] * 1000;
391
+ }
392
+
393
+ // CURL default value is CURL_IPRESOLVE_WHATEVER
394
+ if (isset($options['force_ip_resolve'])) {
395
+ if ('v4' === $options['force_ip_resolve']) {
396
+ $conf[CURLOPT_IPRESOLVE] = CURL_IPRESOLVE_V4;
397
+ } elseif ('v6' === $options['force_ip_resolve']) {
398
+ $conf[CURLOPT_IPRESOLVE] = CURL_IPRESOLVE_V6;
399
+ }
400
+ }
401
+
402
+ if (isset($options['connect_timeout'])) {
403
+ $timeoutRequiresNoSignal |= $options['connect_timeout'] < 1;
404
+ $conf[CURLOPT_CONNECTTIMEOUT_MS] = $options['connect_timeout'] * 1000;
405
+ }
406
+
407
+ if ($timeoutRequiresNoSignal && strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') {
408
+ $conf[CURLOPT_NOSIGNAL] = true;
409
+ }
410
+
411
+ if (isset($options['proxy'])) {
412
+ if (!is_array($options['proxy'])) {
413
+ $conf[CURLOPT_PROXY] = $options['proxy'];
414
+ } else {
415
+ $scheme = $easy->request->getUri()->getScheme();
416
+ if (isset($options['proxy'][$scheme])) {
417
+ $host = $easy->request->getUri()->getHost();
418
+ if (!isset($options['proxy']['no']) ||
419
+ !\GuzzleHttp\is_host_in_noproxy($host, $options['proxy']['no'])
420
+ ) {
421
+ $conf[CURLOPT_PROXY] = $options['proxy'][$scheme];
422
+ }
423
+ }
424
+ }
425
+ }
426
+
427
+ if (isset($options['cert'])) {
428
+ $cert = $options['cert'];
429
+ if (is_array($cert)) {
430
+ $conf[CURLOPT_SSLCERTPASSWD] = $cert[1];
431
+ $cert = $cert[0];
432
+ }
433
+ if (!file_exists($cert)) {
434
+ throw new \InvalidArgumentException(
435
+ "SSL certificate not found: {$cert}"
436
+ );
437
+ }
438
+ $conf[CURLOPT_SSLCERT] = $cert;
439
+ }
440
+
441
+ if (isset($options['ssl_key'])) {
442
+ $sslKey = $options['ssl_key'];
443
+ if (is_array($sslKey)) {
444
+ $conf[CURLOPT_SSLKEYPASSWD] = $sslKey[1];
445
+ $sslKey = $sslKey[0];
446
+ }
447
+ if (!file_exists($sslKey)) {
448
+ throw new \InvalidArgumentException(
449
+ "SSL private key not found: {$sslKey}"
450
+ );
451
+ }
452
+ $conf[CURLOPT_SSLKEY] = $sslKey;
453
+ }
454
+
455
+ if (isset($options['progress'])) {
456
+ $progress = $options['progress'];
457
+ if (!is_callable($progress)) {
458
+ throw new \InvalidArgumentException(
459
+ 'progress client option must be callable'
460
+ );
461
+ }
462
+ $conf[CURLOPT_NOPROGRESS] = false;
463
+ $conf[CURLOPT_PROGRESSFUNCTION] = function () use ($progress) {
464
+ $args = func_get_args();
465
+ // PHP 5.5 pushed the handle onto the start of the args
466
+ if (is_resource($args[0])) {
467
+ array_shift($args);
468
+ }
469
+ call_user_func_array($progress, $args);
470
+ };
471
+ }
472
+
473
+ if (!empty($options['debug'])) {
474
+ $conf[CURLOPT_STDERR] = \GuzzleHttp\debug_resource($options['debug']);
475
+ $conf[CURLOPT_VERBOSE] = true;
476
+ }
477
+ }
478
+
479
+ /**
480
+ * This function ensures that a response was set on a transaction. If one
481
+ * was not set, then the request is retried if possible. This error
482
+ * typically means you are sending a payload, curl encountered a
483
+ * "Connection died, retrying a fresh connect" error, tried to rewind the
484
+ * stream, and then encountered a "necessary data rewind wasn't possible"
485
+ * error, causing the request to be sent through curl_multi_info_read()
486
+ * without an error status.
487
+ */
488
+ private static function retryFailedRewind(
489
+ callable $handler,
490
+ EasyHandle $easy,
491
+ array $ctx
492
+ ) {
493
+ try {
494
+ // Only rewind if the body has been read from.
495
+ $body = $easy->request->getBody();
496
+ if ($body->tell() > 0) {
497
+ $body->rewind();
498
+ }
499
+ } catch (\RuntimeException $e) {
500
+ $ctx['error'] = 'The connection unexpectedly failed without '
501
+ . 'providing an error. The request would have been retried, '
502
+ . 'but attempting to rewind the request body failed. '
503
+ . 'Exception: ' . $e;
504
+ return self::createRejection($easy, $ctx);
505
+ }
506
+
507
+ // Retry no more than 3 times before giving up.
508
+ if (!isset($easy->options['_curl_retries'])) {
509
+ $easy->options['_curl_retries'] = 1;
510
+ } elseif ($easy->options['_curl_retries'] == 2) {
511
+ $ctx['error'] = 'The cURL request was retried 3 times '
512
+ . 'and did not succeed. The most likely reason for the failure '
513
+ . 'is that cURL was unable to rewind the body of the request '
514
+ . 'and subsequent retries resulted in the same error. Turn on '
515
+ . 'the debug option to see what went wrong. See '
516
+ . 'https://bugs.php.net/bug.php?id=47204 for more information.';
517
+ return self::createRejection($easy, $ctx);
518
+ } else {
519
+ $easy->options['_curl_retries']++;
520
+ }
521
+
522
+ return $handler($easy->request, $easy->options);
523
+ }
524
+
525
+ private function createHeaderFn(EasyHandle $easy)
526
+ {
527
+ if (isset($easy->options['on_headers'])) {
528
+ $onHeaders = $easy->options['on_headers'];
529
+
530
+ if (!is_callable($onHeaders)) {
531
+ throw new \InvalidArgumentException('on_headers must be callable');
532
+ }
533
+ } else {
534
+ $onHeaders = null;
535
+ }
536
+
537
+ return function ($ch, $h) use (
538
+ $onHeaders,
539
+ $easy,
540
+ &$startingResponse
541
+ ) {
542
+ $value = trim($h);
543
+ if ($value === '') {
544
+ $startingResponse = true;
545
+ $easy->createResponse();
546
+ if ($onHeaders !== null) {
547
+ try {
548
+ $onHeaders($easy->response);
549
+ } catch (\Exception $e) {
550
+ // Associate the exception with the handle and trigger
551
+ // a curl header write error by returning 0.
552
+ $easy->onHeadersException = $e;
553
+ return -1;
554
+ }
555
+ }
556
+ } elseif ($startingResponse) {
557
+ $startingResponse = false;
558
+ $easy->headers = [$value];
559
+ } else {
560
+ $easy->headers[] = $value;
561
+ }
562
+ return strlen($h);
563
+ };
564
+ }
565
+ }
vendor/guzzlehttp/guzzle/src/Handler/CurlFactoryInterface.php CHANGED
@@ -1,27 +1,27 @@
1
- <?php
2
- namespace GuzzleHttp\Handler;
3
-
4
- use Psr\Http\Message\RequestInterface;
5
-
6
- interface CurlFactoryInterface
7
- {
8
- /**
9
- * Creates a cURL handle resource.
10
- *
11
- * @param RequestInterface $request Request
12
- * @param array $options Transfer options
13
- *
14
- * @return EasyHandle
15
- * @throws \RuntimeException when an option cannot be applied
16
- */
17
- public function create(RequestInterface $request, array $options);
18
-
19
- /**
20
- * Release an easy handle, allowing it to be reused or closed.
21
- *
22
- * This function must call unset on the easy handle's "handle" property.
23
- *
24
- * @param EasyHandle $easy
25
- */
26
- public function release(EasyHandle $easy);
27
- }
1
+ <?php
2
+ namespace GuzzleHttp\Handler;
3
+
4
+ use Psr\Http\Message\RequestInterface;
5
+
6
+ interface CurlFactoryInterface
7
+ {
8
+ /**
9
+ * Creates a cURL handle resource.
10
+ *
11
+ * @param RequestInterface $request Request
12
+ * @param array $options Transfer options
13
+ *
14
+ * @return EasyHandle
15
+ * @throws \RuntimeException when an option cannot be applied
16
+ */
17
+ public function create(RequestInterface $request, array $options);
18
+
19
+ /**
20
+ * Release an easy handle, allowing it to be reused or closed.
21
+ *
22
+ * This function must call unset on the easy handle's "handle" property.
23
+ *
24
+ * @param EasyHandle $easy
25
+ */
26
+ public function release(EasyHandle $easy);
27
+ }
vendor/guzzlehttp/guzzle/src/Handler/CurlHandler.php CHANGED
@@ -1,45 +1,45 @@
1
- <?php
2
- namespace GuzzleHttp\Handler;
3
-
4
- use GuzzleHttp\Psr7;
5
- use Psr\Http\Message\RequestInterface;
6
-
7
- /**
8
- * HTTP handler that uses cURL easy handles as a transport layer.
9
- *
10
- * When using the CurlHandler, custom curl options can be specified as an
11
- * associative array of curl option constants mapping to values in the
12
- * **curl** key of the "client" key of the request.
13
- */
14
- class CurlHandler
15
- {
16
- /** @var CurlFactoryInterface */
17
- private $factory;
18
-
19
- /**
20
- * Accepts an associative array of options:
21
- *
22
- * - factory: Optional curl factory used to create cURL handles.
23
- *
24
- * @param array $options Array of options to use with the handler
25
- */
26
- public function __construct(array $options = [])
27
- {
28
- $this->factory = isset($options['handle_factory'])
29
- ? $options['handle_factory']
30
- : new CurlFactory(3);
31
- }
32
-
33
- public function __invoke(RequestInterface $request, array $options)
34
- {
35
- if (isset($options['delay'])) {
36
- usleep($options['delay'] * 1000);
37
- }
38
-
39
- $easy = $this->factory->create($request, $options);
40
- curl_exec($easy->handle);
41
- $easy->errno = curl_errno($easy->handle);
42
-
43
- return CurlFactory::finish($this, $easy, $this->factory);
44
- }
45
- }
1
+ <?php
2
+ namespace GuzzleHttp\Handler;
3
+
4
+ use GuzzleHttp\Psr7;
5
+ use Psr\Http\Message\RequestInterface;
6
+
7
+ /**
8
+ * HTTP handler that uses cURL easy handles as a transport layer.
9
+ *
10
+ * When using the CurlHandler, custom curl options can be specified as an
11
+ * associative array of curl option constants mapping to values in the
12
+ * **curl** key of the "client" key of the request.
13
+ */
14
+ class CurlHandler
15
+ {
16
+ /** @var CurlFactoryInterface */
17
+ private $factory;
18
+
19
+ /**
20
+ * Accepts an associative array of options:
21
+ *
22
+ * - factory: Optional curl factory used to create cURL handles.
23
+ *
24
+ * @param array $options Array of options to use with the handler
25
+ */
26
+ public function __construct(array $options = [])
27
+ {
28
+ $this->factory = isset($options['handle_factory'])
29
+ ? $options['handle_factory']
30
+ : new CurlFactory(3);
31
+ }
32
+
33
+ public function __invoke(RequestInterface $request, array $options)
34
+ {
35
+ if (isset($options['delay'])) {
36
+ usleep($options['delay'] * 1000);
37
+ }
38
+
39
+ $easy = $this->factory->create($request, $options);
40
+ curl_exec($easy->handle);
41
+ $easy->errno = curl_errno($easy->handle);
42
+
43
+ return CurlFactory::finish($this, $easy, $this->factory);
44
+ }
45
+ }
vendor/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php CHANGED
@@ -1,199 +1,199 @@
1
- <?php
2
- namespace GuzzleHttp\Handler;
3
-
4
- use GuzzleHttp\Promise as P;
5
- use GuzzleHttp\Promise\Promise;
6
- use GuzzleHttp\Psr7;
7
- use Psr\Http\Message\RequestInterface;
8
-
9
- /**
10
- * Returns an asynchronous response using curl_multi_* functions.
11
- *
12
- * When using the CurlMultiHandler, custom curl options can be specified as an
13
- * associative array of curl option constants mapping to values in the
14
- * **curl** key of the provided request options.
15
- *
16
- * @property resource $_mh Internal use only. Lazy loaded multi-handle.
17
- */
18
- class CurlMultiHandler
19
- {
20
- /** @var CurlFactoryInterface */
21
- private $factory;
22
- private $selectTimeout;
23
- private $active;
24
- private $handles = [];
25
- private $delays = [];
26
-
27
- /**
28
- * This handler accepts the following options:
29
- *
30
- * - handle_factory: An optional factory used to create curl handles
31
- * - select_timeout: Optional timeout (in seconds) to block before timing
32
- * out while selecting curl handles. Defaults to 1 second.
33
- *
34
- * @param array $options
35
- */
36
- public function __construct(array $options = [])
37
- {
38
- $this->factory = isset($options['handle_factory'])
39
- ? $options['handle_factory'] : new CurlFactory(50);
40
- $this->selectTimeout = isset($options['select_timeout'])
41
- ? $options['select_timeout'] : 1;
42
- }
43
-
44
- public function __get($name)
45
- {
46
- if ($name === '_mh') {
47
- return $this->_mh = curl_multi_init();
48
- }
49
-
50
- throw new \BadMethodCallException();
51
- }
52
-
53
- public function __destruct()
54
- {
55
- if (isset($this->_mh)) {
56
- curl_multi_close($this->_mh);
57
- unset($this->_mh);
58
- }
59
- }
60
-
61
- public function __invoke(RequestInterface $request, array $options)
62
- {
63
- $easy = $this->factory->create($request, $options);
64
- $id = (int) $easy->handle;
65
-
66
- $promise = new Promise(
67
- [$this, 'execute'],
68
- function () use ($id) {
69
- return $this->cancel($id);
70
- }
71
- );
72
-
73
- $this->addRequest(['easy' => $easy, 'deferred' => $promise]);
74
-
75
- return $promise;
76
- }
77
-
78
- /**
79
- * Ticks the curl event loop.
80
- */
81
- public function tick()
82
- {
83
- // Add any delayed handles if needed.
84
- if ($this->delays) {
85
- $currentTime = microtime(true);
86
- foreach ($this->delays as $id => $delay) {
87
- if ($currentTime >= $delay) {
88
- unset($this->delays[$id]);
89
- curl_multi_add_handle(
90
- $this->_mh,
91
- $this->handles[$id]['easy']->handle
92
- );
93
- }
94
- }
95
- }
96
-
97
- // Step through the task queue which may add additional requests.
98
- P\queue()->run();
99
-
100
- if ($this->active &&
101
- curl_multi_select($this->_mh, $this->selectTimeout) === -1
102
- ) {
103
- // Perform a usleep if a select returns -1.
104
- // See: https://bugs.php.net/bug.php?id=61141
105
- usleep(250);
106
- }
107
-
108
- while (curl_multi_exec($this->_mh, $this->active) === CURLM_CALL_MULTI_PERFORM);
109
-
110
- $this->processMessages();
111
- }
112
-
113
- /**
114
- * Runs until all outstanding connections have completed.
115
- */
116
- public function execute()
117
- {
118
- $queue = P\queue();
119
-
120
- while ($this->handles || !$queue->isEmpty()) {
121
- // If there are no transfers, then sleep for the next delay
122
- if (!$this->active && $this->delays) {
123
- usleep($this->timeToNext());
124
- }
125
- $this->tick();
126
- }
127
- }
128
-
129
- private function addRequest(array $entry)
130
- {
131
- $easy = $entry['easy'];
132
- $id = (int) $easy->handle;
133
- $this->handles[$id] = $entry;
134
- if (empty($easy->options['delay'])) {
135
- curl_multi_add_handle($this->_mh, $easy->handle);
136
- } else {
137
- $this->delays[$id] = microtime(true) + ($easy->options['delay'] / 1000);
138
- }
139
- }
140
-
141
- /**
142
- * Cancels a handle from sending and removes references to it.
143
- *
144
- * @param int $id Handle ID to cancel and remove.
145
- *
146
- * @return bool True on success, false on failure.
147
- */
148
- private function cancel($id)
149
- {
150
- // Cannot cancel if it has been processed.
151
- if (!isset($this->handles[$id])) {
152
- return false;
153
- }
154
-
155
- $handle = $this->handles[$id]['easy']->handle;
156
- unset($this->delays[$id], $this->handles[$id]);
157
- curl_multi_remove_handle($this->_mh, $handle);
158
- curl_close($handle);
159
-
160
- return true;
161
- }
162
-
163
- private function processMessages()
164
- {
165
- while ($done = curl_multi_info_read($this->_mh)) {
166
- $id = (int) $done['handle'];
167
- curl_multi_remove_handle($this->_mh, $done['handle']);
168
-
169
- if (!isset($this->handles[$id])) {
170
- // Probably was cancelled.
171
- continue;
172
- }
173
-
174
- $entry = $this->handles[$id];
175
- unset($this->handles[$id], $this->delays[$id]);
176
- $entry['easy']->errno = $done['result'];
177
- $entry['deferred']->resolve(
178
- CurlFactory::finish(
179
- $this,
180
- $entry['easy'],
181
- $this->factory
182
- )
183
- );
184
- }
185
- }
186
-
187
- private function timeToNext()
188
- {
189
- $currentTime = microtime(true);
190
- $nextTime = PHP_INT_MAX;
191
- foreach ($this->delays as $time) {
192
- if ($time < $nextTime) {
193
- $nextTime = $time;
194
- }
195
- }
196
-
197
- return max(0, $nextTime - $currentTime) * 1000000;
198
- }
199
- }
1
+ <?php
2
+ namespace GuzzleHttp\Handler;
3
+
4
+ use GuzzleHttp\Promise as P;
5
+ use GuzzleHttp\Promise\Promise;
6
+ use GuzzleHttp\Psr7;
7
+ use Psr\Http\Message\RequestInterface;
8
+
9
+ /**
10
+ * Returns an asynchronous response using curl_multi_* functions.
11
+ *
12
+ * When using the CurlMultiHandler, custom curl options can be specified as an
13
+ * associative array of curl option constants mapping to values in the
14
+ * **curl** key of the provided request options.
15
+ *
16
+ * @property resource $_mh Internal use only. Lazy loaded multi-handle.
17
+ */
18
+ class CurlMultiHandler
19
+ {
20
+ /** @var CurlFactoryInterface */
21
+ private $factory;
22
+ private $selectTimeout;
23
+ private $active;
24
+ private $handles = [];
25
+ private $delays = [];
26
+
27
+ /**
28
+ * This handler accepts the following options:
29
+ *
30
+ * - handle_factory: An optional factory used to create curl handles
31
+ * - select_timeout: Optional timeout (in seconds) to block before timing
32
+ * out while selecting curl handles. Defaults to 1 second.
33
+ *
34
+ * @param array $options
35
+ */
36
+ public function __construct(array $options = [])
37
+ {
38
+ $this->factory = isset($options['handle_factory'])
39
+ ? $options['handle_factory'] : new CurlFactory(50);
40
+ $this->selectTimeout = isset($options['select_timeout'])
41
+ ? $options['select_timeout'] : 1;
42
+ }
43
+
44
+ public function __get($name)
45
+ {
46
+ if ($name === '_mh') {
47
+ return $this->_mh = curl_multi_init();
48
+ }
49
+
50
+ throw new \BadMethodCallException();
51
+ }
52
+
53
+ public function __destruct()
54
+ {
55
+ if (isset($this->_mh)) {
56
+ curl_multi_close($this->_mh);
57
+ unset($this->_mh);
58
+ }
59
+ }
60
+
61
+ public function __invoke(RequestInterface $request, array $options)
62
+ {
63
+ $easy = $this->factory->create($request, $options);
64
+ $id = (int) $easy->handle;
65
+
66
+ $promise = new Promise(
67
+ [$this, 'execute'],
68
+ function () use ($id) {
69
+ return $this->cancel($id);
70
+ }
71
+ );
72
+
73
+ $this->addRequest(['easy' => $easy, 'deferred' => $promise]);
74
+
75
+ return $promise;
76
+ }
77
+
78
+ /**
79
+ * Ticks the curl event loop.
80
+ */
81
+ public function tick()
82
+ {
83
+ // Add any delayed handles if needed.
84
+ if ($this->delays) {
85
+ $currentTime = microtime(true);
86
+ foreach ($this->delays as $id => $delay) {
87
+ if ($currentTime >= $delay) {
88
+ unset($this->delays[$id]);
89
+ curl_multi_add_handle(
90
+ $this->_mh,
91
+ $this->handles[$id]['easy']->handle
92
+ );
93
+ }
94
+ }
95
+ }
96
+
97
+ // Step through the task queue which may add additional requests.
98
+ P\queue()->run();
99
+
100
+ if ($this->active &&
101
+ curl_multi_select($this->_mh, $this->selectTimeout) === -1
102
+ ) {
103
+ // Perform a usleep if a select returns -1.
104
+ // See: https://bugs.php.net/bug.php?id=61141
105
+ usleep(250);
106
+ }
107
+
108
+ while (curl_multi_exec($this->_mh, $this->active) === CURLM_CALL_MULTI_PERFORM);
109
+
110
+ $this->processMessages();
111
+ }
112
+
113
+ /**
114
+ * Runs until all outstanding connections have completed.
115
+ */
116
+ public function execute()
117
+ {
118
+ $queue = P\queue();
119
+
120
+ while ($this->handles || !$queue->isEmpty()) {
121
+ // If there are no transfers, then sleep for the next delay
122
+ if (!$this->active && $this->delays) {
123
+ usleep($this->timeToNext());
124
+ }
125
+ $this->tick();
126
+ }
127
+ }
128
+
129
+ private function addRequest(array $entry)
130
+ {
131
+ $easy = $entry['easy'];
132
+ $id = (int) $easy->handle;
133
+ $this->handles[$id] = $entry;
134
+ if (empty($easy->options['delay'])) {
135
+ curl_multi_add_handle($this->_mh, $easy->handle);
136
+ } else {
137
+ $this->delays[$id] = microtime(true) + ($easy->options['delay'] / 1000);
138
+ }
139
+ }
140
+
141
+ /**
142
+ * Cancels a handle from sending and removes references to it.
143
+ *
144
+ * @param int $id Handle ID to cancel and remove.
145
+ *
146
+ * @return bool True on success, false on failure.
147
+ */
148
+ private function cancel($id)
149
+ {
150
+ // Cannot cancel if it has been processed.
151
+ if (!isset($this->handles[$id])) {
152
+ return false;
153
+ }
154
+
155
+ $handle = $this->handles[$id]['easy']->handle;
156
+ unset($this->delays[$id], $this->handles[$id]);
157
+ curl_multi_remove_handle($this->_mh, $handle);
158
+ curl_close($handle);
159
+
160
+ return true;
161
+ }
162
+
163
+ private function processMessages()
164
+ {
165
+ while ($done = curl_multi_info_read($this->_mh)) {
166
+ $id = (int) $done['handle'];
167
+ curl_multi_remove_handle($this->_mh, $done['handle']);
168
+
169
+ if (!isset($this->handles[$id])) {
170
+ // Probably was cancelled.
171
+ continue;
172
+ }
173
+
174
+ $entry = $this->handles[$id];
175
+ unset($this->handles[$id], $this->delays[$id]);
176
+ $entry['easy']->errno = $done['result'];
177
+ $entry['deferred']->resolve(
178
+ CurlFactory::finish(
179
+ $this,
180
+ $entry['easy'],
181
+ $this->factory
182
+ )
183
+ );
184
+ }
185
+ }
186
+
187
+ private function timeToNext()
188
+ {
189
+ $currentTime = microtime(true);
190
+ $nextTime = PHP_INT_MAX;
191
+ foreach ($this->delays as $time) {
192
+ if ($time < $nextTime) {
193
+ $nextTime = $time;
194
+ }
195
+ }
196
+
197
+ return max(0, $nextTime - $currentTime) * 1000000;
198
+ }
199
+ }
vendor/guzzlehttp/guzzle/src/Handler/EasyHandle.php CHANGED
@@ -1,92 +1,92 @@
1
- <?php
2
- namespace GuzzleHttp\Handler;
3
-
4
- use GuzzleHttp\Psr7\Response;
5
- use Psr\Http\Message\RequestInterface;
6
- use Psr\Http\Message\ResponseInterface;
7
- use Psr\Http\Message\StreamInterface;
8
-
9
- /**
10
- * Represents a cURL easy handle and the data it populates.
11
- *
12
- * @internal
13
- */
14
- final class EasyHandle
15
- {
16
- /** @var resource cURL resource */
17
- public $handle;
18
-
19
- /** @var StreamInterface Where data is being written */
20
- public $sink;
21
-
22
- /** @var array Received HTTP headers so far */
23
- public $headers = [];
24
-
25
- /** @var ResponseInterface Received response (if any) */
26
- public $response;
27
-
28
- /** @var RequestInterface Request being sent */
29
- public $request;
30
-
31
- /** @var array Request options */
32
- public $options = [];
33
-
34
- /** @var int cURL error number (if any) */
35
- public $errno = 0;
36
-
37
- /** @var \Exception Exception during on_headers (if any) */
38
- public $onHeadersException;
39
-
40
- /**
41
- * Attach a response to the easy handle based on the received headers.
42
- *
43
- * @throws \RuntimeException if no headers have been received.
44
- */
45
- public function createResponse()
46
- {
47
- if (empty($this->headers)) {
48
- throw new \RuntimeException('No headers have been received');
49
- }
50
-
51
- // HTTP-version SP status-code SP reason-phrase
52
- $startLine = explode(' ', array_shift($this->headers), 3);
53
- $headers = \GuzzleHttp\headers_from_lines($this->headers);
54
- $normalizedKeys = \GuzzleHttp\normalize_header_keys($headers);
55
-
56
- if (!empty($this->options['decode_content'])
57
- && isset($normalizedKeys['content-encoding'])
58
- ) {
59
- $headers['x-encoded-content-encoding']
60
- = $headers[$normalizedKeys['content-encoding']];
61
- unset($headers[$normalizedKeys['content-encoding']]);
62
- if (isset($normalizedKeys['content-length'])) {
63
- $headers['x-encoded-content-length']
64
- = $headers[$normalizedKeys['content-length']];
65
-
66
- $bodyLength = (int) $this->sink->getSize();
67
- if ($bodyLength) {
68
- $headers[$normalizedKeys['content-length']] = $bodyLength;
69
- } else {
70
- unset($headers[$normalizedKeys['content-length']]);
71
- }
72
- }
73
- }
74
-
75
- // Attach a response to the easy handle with the parsed headers.
76
- $this->response = new Response(
77
- $startLine[1],
78
- $headers,
79
- $this->sink,
80
- substr($startLine[0], 5),
81
- isset($startLine[2]) ? (string) $startLine[2] : null
82
- );
83
- }
84
-
85
- public function __get($name)
86
- {
87
- $msg = $name === 'handle'
88
- ? 'The EasyHandle has been released'
89
- : 'Invalid property: ' . $name;
90
- throw new \BadMethodCallException($msg);
91
- }
92
- }
1
+ <?php
2
+ namespace GuzzleHttp\Handler;
3
+
4
+ use GuzzleHttp\Psr7\Response;
5
+ use Psr\Http\Message\RequestInterface;
6
+ use Psr\Http\Message\ResponseInterface;
7
+ use Psr\Http\Message\StreamInterface;
8
+
9
+ /**
10
+ * Represents a cURL easy handle and the data it populates.
11
+ *
12
+ * @internal
13
+ */
14
+ final class EasyHandle
15
+ {
16
+ /** @var resource cURL resource */
17
+ public $handle;
18
+
19
+ /** @var StreamInterface Where data is being written */
20
+ public $sink;
21
+
22
+ /** @var array Received HTTP headers so far */
23
+ public $headers = [];
24
+
25
+ /** @var ResponseInterface Received response (if any) */
26
+ public $response;
27
+
28
+ /** @var RequestInterface Request being sent */
29
+ public $request;
30
+
31
+ /** @var array Request options */
32
+ public $options = [];
33
+
34
+ /** @var int cURL error number (if any) */
35
+ public $errno = 0;
36
+
37
+ /** @var \Exception Exception during on_headers (if any) */
38
+ public $onHeadersException;
39
+
40
+ /**
41
+ * Attach a response to the easy handle based on the received headers.
42
+ *
43
+ * @throws \RuntimeException if no headers have been received.
44
+ */
45
+ public function createResponse()
46
+ {
47
+ if (empty($this->headers)) {
48
+ throw new \RuntimeException('No headers have been received');
49
+ }
50
+
51
+ // HTTP-version SP status-code SP reason-phrase
52
+ $startLine = explode(' ', array_shift($this->headers), 3);
53
+ $headers = \GuzzleHttp\headers_from_lines($this->headers);
54
+ $normalizedKeys = \GuzzleHttp\normalize_header_keys($headers);
55
+
56
+ if (!empty($this->options['decode_content'])
57
+ && isset($normalizedKeys['content-encoding'])
58
+ ) {
59
+ $headers['x-encoded-content-encoding']
60
+ = $headers[$normalizedKeys['content-encoding']];
61
+ unset($headers[$normalizedKeys['content-encoding']]);
62
+ if (isset($normalizedKeys['content-length'])) {
63
+ $headers['x-encoded-content-length']
64
+ = $headers[$normalizedKeys['content-length']];
65
+
66
+ $bodyLength = (int) $this->sink->getSize();
67
+ if ($bodyLength) {
68
+ $headers[$normalizedKeys['content-length']] = $bodyLength;
69
+ } else {
70
+ unset($headers[$normalizedKeys['content-length']]);
71
+ }
72
+ }
73
+ }
74
+
75
+ // Attach a response to the easy handle with the parsed headers.
76
+ $this->response = new Response(
77
+ $startLine[1],
78
+ $headers,
79
+ $this->sink,
80
+ substr($startLine[0], 5),
81
+ isset($startLine[2]) ? (string) $startLine[2] : null
82
+ );
83
+ }
84
+
85
+ public function __get($name)
86
+ {
87
+ $msg = $name === 'handle'
88
+ ? 'The EasyHandle has been released'
89
+ : 'Invalid property: ' . $name;
90
+ throw new \BadMethodCallException($msg);
91
+ }
92
+ }
vendor/guzzlehttp/guzzle/src/Handler/MockHandler.php CHANGED
@@ -1,189 +1,189 @@
1
- <?php
2
- namespace GuzzleHttp\Handler;
3
-
4
- use GuzzleHttp\Exception\RequestException;
5
- use GuzzleHttp\HandlerStack;
6
- use GuzzleHttp\Promise\PromiseInterface;
7
- use GuzzleHttp\Promise\RejectedPromise;
8
- use GuzzleHttp\TransferStats;
9
- use Psr\Http\Message\RequestInterface;
10
- use Psr\Http\Message\ResponseInterface;
11
-
12
- /**
13
- * Handler that returns responses or throw exceptions from a queue.
14
- */
15
- class MockHandler implements \Countable
16
- {
17
- private $queue = [];
18
- private $lastRequest;
19
- private $lastOptions;
20
- private $onFulfilled;
21
- private $onRejected;
22
-
23
- /**
24
- * Creates a new MockHandler that uses the default handler stack list of
25
- * middlewares.
26
- *
27
- * @param array $queue Array of responses, callables, or exceptions.
28
- * @param callable $onFulfilled Callback to invoke when the return value is fulfilled.
29
- * @param callable $onRejected Callback to invoke when the return value is rejected.
30
- *
31
- * @return HandlerStack
32
- */
33
- public static function createWithMiddleware(
34
- array $queue = null,
35
- callable $onFulfilled = null,
36
- callable $onRejected = null
37
- ) {
38
- return HandlerStack::create(new self($queue, $onFulfilled, $onRejected));
39
- }
40
-
41
- /**
42
- * The passed in value must be an array of
43
- * {@see Psr7\Http\Message\ResponseInterface} objects, Exceptions,
44
- * callables, or Promises.
45
- *
46
- * @param array $queue
47
- * @param callable $onFulfilled Callback to invoke when the return value is fulfilled.
48
- * @param callable $onRejected Callback to invoke when the return value is rejected.
49
- */
50
- public function __construct(
51
- array $queue = null,
52
- callable $onFulfilled = null,
53
- callable $onRejected = null
54
- ) {
55
- $this->onFulfilled = $onFulfilled;
56
- $this->onRejected = $onRejected;
57
-
58
- if ($queue) {
59
- call_user_func_array([$this, 'append'], $queue);
60
- }
61
- }
62
-
63
- public function __invoke(RequestInterface $request, array $options)
64
- {
65
- if (!$this->queue) {
66
- throw new \OutOfBoundsException('Mock queue is empty');
67
- }
68
-
69
- if (isset($options['delay'])) {
70
- usleep($options['delay'] * 1000);
71
- }
72
-
73
- $this->lastRequest = $request;
74
- $this->lastOptions = $options;
75
- $response = array_shift($this->queue);
76
-
77
- if (isset($options['on_headers'])) {
78
- if (!is_callable($options['on_headers'])) {
79
- throw new \InvalidArgumentException('on_headers must be callable');
80
- }
81
- try {
82
- $options['on_headers']($response);
83
- } catch (\Exception $e) {
84
- $msg = 'An error was encountered during the on_headers event';
85
- $response = new RequestException($msg, $request, $response, $e);
86
- }
87
- }
88
-
89
- if (is_callable($response)) {
90
- $response = call_user_func($response, $request, $options);
91
- }
92
-
93
- $response = $response instanceof \Exception
94
- ? \GuzzleHttp\Promise\rejection_for($response)
95
- : \GuzzleHttp\Promise\promise_for($response);
96
-
97
- return $response->then(
98
- function ($value) use ($request, $options) {
99
- $this->invokeStats($request, $options, $value);
100
- if ($this->onFulfilled) {
101
- call_user_func($this->onFulfilled, $value);
102
- }
103
- if (isset($options['sink'])) {
104
- $contents = (string) $value->getBody();
105
- $sink = $options['sink'];
106
-
107
- if (is_resource($sink)) {
108
- fwrite($sink, $contents);
109
- } elseif (is_string($sink)) {
110
- file_put_contents($sink, $contents);
111
- } elseif ($sink instanceof \Psr\Http\Message\StreamInterface) {
112
- $sink->write($contents);
113
- }
114
- }
115
-
116
- return $value;
117
- },
118
- function ($reason) use ($request, $options) {
119
- $this->invokeStats($request, $options, null, $reason);
120
- if ($this->onRejected) {
121
- call_user_func($this->onRejected, $reason);
122
- }
123
- return \GuzzleHttp\Promise\rejection_for($reason);
124
- }
125
- );
126
- }
127
-
128
- /**
129
- * Adds one or more variadic requests, exceptions, callables, or promises
130
- * to the queue.
131
- */
132
- public function append()
133
- {
134
- foreach (func_get_args() as $value) {
135
- if ($value instanceof ResponseInterface
136
- || $value instanceof \Exception
137
- || $value instanceof PromiseInterface
138
- || is_callable($value)
139
- ) {
140
- $this->queue[] = $value;
141
- } else {
142
- throw new \InvalidArgumentException('Expected a response or '
143
- . 'exception. Found ' . \GuzzleHttp\describe_type($value));
144
- }
145
- }
146
- }
147
-
148
- /**
149
- * Get the last received request.
150
- *
151
- * @return RequestInterface
152
- */
153
- public function getLastRequest()
154
- {
155
- return $this->lastRequest;
156
- }
157
-
158
- /**
159
- * Get the last received request options.
160
- *
161
- * @return array
162
- */
163
- public function getLastOptions()
164
- {
165
- return $this->lastOptions;
166
- }
167
-
168
- /**
169
- * Returns the number of remaining items in the queue.
170
- *
171
- * @return int
172
- */
173
- public function count()
174
- {
175
- return count($this->queue);
176
- }
177
-
178
- private function invokeStats(
179
- RequestInterface $request,
180
- array $options,
181
- ResponseInterface $response = null,
182
- $reason = null
183
- ) {
184
- if (isset($options['on_stats'])) {
185
- $stats = new TransferStats($request, $response, 0, $reason);
186
- call_user_func($options['on_stats'], $stats);
187
- }
188
- }
189
- }
1
+ <?php
2
+ namespace GuzzleHttp\Handler;
3
+
4
+ use GuzzleHttp\Exception\RequestException;
5
+ use GuzzleHttp\HandlerStack;
6
+ use GuzzleHttp\Promise\PromiseInterface;
7
+ use GuzzleHttp\Promise\RejectedPromise;
8
+ use GuzzleHttp\TransferStats;
9
+ use Psr\Http\Message\RequestInterface;
10
+ use Psr\Http\Message\ResponseInterface;
11
+
12
+ /**
13
+ * Handler that returns responses or throw exceptions from a queue.
14
+ */
15
+ class MockHandler implements \Countable
16
+ {
17
+ private $queue = [];
18
+ private $lastRequest;
19
+ private $lastOptions;
20
+ private $onFulfilled;
21
+ private $onRejected;
22
+
23
+ /**
24
+ * Creates a new MockHandler that uses the default handler stack list of
25
+ * middlewares.
26
+ *
27
+ * @param array $queue Array of responses, callables, or exceptions.
28
+ * @param callable $onFulfilled Callback to invoke when the return value is fulfilled.
29
+ * @param callable $onRejected Callback to invoke when the return value is rejected.
30
+ *
31
+ * @return HandlerStack
32
+ */
33
+ public static function createWithMiddleware(
34
+ array $queue = null,
35
+ callable $onFulfilled = null,
36
+ callable $onRejected = null
37
+ ) {
38
+ return HandlerStack::create(new self($queue, $onFulfilled, $onRejected));
39
+ }
40
+
41
+ /**
42
+ * The passed in value must be an array of
43
+ * {@see Psr7\Http\Message\ResponseInterface} objects, Exceptions,
44
+ * callables, or Promises.
45
+ *
46
+ * @param array $queue
47
+ * @param callable $onFulfilled Callback to invoke when the return value is fulfilled.
48
+ * @param callable $onRejected Callback to invoke when the return value is rejected.
49
+ */
50
+ public function __construct(
51
+ array $queue = null,
52
+ callable $onFulfilled = null,
53
+ callable $onRejected = null
54
+ ) {
55
+ $this->onFulfilled = $onFulfilled;
56
+ $this->onRejected = $onRejected;
57
+
58
+ if ($queue) {
59
+ call_user_func_array([$this, 'append'], $queue);
60
+ }
61
+ }
62
+
63
+ public function __invoke(RequestInterface $request, array $options)
64
+ {
65
+ if (!$this->queue) {
66
+ throw new \OutOfBoundsException('Mock queue is empty');
67
+ }
68
+
69
+ if (isset($options['delay'])) {
70
+ usleep($options['delay'] * 1000);
71
+ }
72
+
73
+ $this->lastRequest = $request;
74
+ $this->lastOptions = $options;
75
+ $response = array_shift($this->queue);
76
+
77
+ if (isset($options['on_headers'])) {
78
+ if (!is_callable($options['on_headers'])) {
79
+ throw new \InvalidArgumentException('on_headers must be callable');
80
+ }
81
+ try {
82
+ $options['on_headers']($response);
83
+ } catch (\Exception $e) {
84
+ $msg = 'An error was encountered during the on_headers event';
85
+ $response = new RequestException($msg, $request, $response, $e);
86
+ }
87
+ }
88
+
89
+ if (is_callable($response)) {
90
+ $response = call_user_func($response, $request, $options);
91
+ }
92
+
93
+ $response = $response instanceof \Exception
94
+ ? \GuzzleHttp\Promise\rejection_for($response)
95
+ : \GuzzleHttp\Promise\promise_for($response);
96
+
97
+ return $response->then(
98
+ function ($value) use ($request, $options) {
99
+ $this->invokeStats($request, $options, $value);
100
+ if ($this->onFulfilled) {
101
+ call_user_func($this->onFulfilled, $value);
102
+ }
103
+ if (isset($options['sink'])) {
104
+ $contents = (string) $value->getBody();
105
+ $sink = $options['sink'];
106
+
107
+ if (is_resource($sink)) {
108
+ fwrite($sink, $contents);
109
+ } elseif (is_string($sink)) {
110
+ file_put_contents($sink, $contents);
111
+ } elseif ($sink instanceof \Psr\Http\Message\StreamInterface) {
112
+ $sink->write($contents);
113
+ }
114
+ }
115
+
116
+ return $value;
117
+ },
118
+ function ($reason) use ($request, $options) {
119
+ $this->invokeStats($request, $options, null, $reason);
120
+ if ($this->onRejected) {
121
+ call_user_func($this->onRejected, $reason);
122
+ }
123
+ return \GuzzleHttp\Promise\rejection_for($reason);
124
+ }
125
+ );
126
+ }
127
+
128
+ /**
129
+ * Adds one or more variadic requests, exceptions, callables, or promises
130
+ * to the queue.
131
+ */
132
+ public function append()
133
+ {
134
+ foreach (func_get_args() as $value) {
135
+ if ($value instanceof ResponseInterface
136
+ || $value instanceof \Exception
137
+ || $value instanceof PromiseInterface
138
+ || is_callable($value)
139
+ ) {
140
+ $this->queue[] = $value;
141
+ } else {
142
+ throw new \InvalidArgumentException('Expected a response or '
143
+ . 'exception. Found ' . \GuzzleHttp\describe_type($value));
144
+ }
145
+ }
146
+ }
147
+
148
+ /**
149
+ * Get the last received request.
150
+ *
151
+ * @return RequestInterface
152
+ */
153
+ public function getLastRequest()
154
+ {
155
+ return $this->lastRequest;
156
+ }
157
+
158
+ /**
159
+ * Get the last received request options.
160
+ *
161
+ * @return array
162
+ */
163
+ public function getLastOptions()
164
+ {
165
+ return $this->lastOptions;
166
+ }
167
+
168
+ /**
169
+ * Returns the number of remaining items in the queue.
170
+ *
171
+ * @return int
172
+ */
173
+ public function count()
174
+ {
175
+ return count($this->queue);
176
+ }
177
+
178
+ private function invokeStats(
179
+ RequestInterface $request,
180
+ array $options,
181
+ ResponseInterface $response = null,
182
+ $reason = null
183
+ ) {
184
+ if (isset($options['on_stats'])) {
185
+ $stats = new TransferStats($request, $response, 0, $reason);
186
+ call_user_func($options['on_stats'], $stats);
187
+ }
188
+ }
189
+ }
vendor/guzzlehttp/guzzle/src/Handler/Proxy.php CHANGED
@@ -1,55 +1,55 @@
1
- <?php
2
- namespace GuzzleHttp\Handler;
3
-
4
- use GuzzleHttp\RequestOptions;
5
- use Psr\Http\Message\RequestInterface;
6
-
7
- /**
8
- * Provides basic proxies for handlers.
9
- */
10
- class Proxy
11
- {
12
- /**
13
- * Sends synchronous requests to a specific handler while sending all other
14
- * requests to another handler.
15
- *
16
- * @param callable $default Handler used for normal responses
17
- * @param callable $sync Handler used for synchronous responses.
18
- *
19
- * @return callable Returns the composed handler.
20
- */
21
- public static function wrapSync(
22
- callable $default,
23
- callable $sync
24
- ) {
25
- return function (RequestInterface $request, array $options) use ($default, $sync) {
26
- return empty($options[RequestOptions::SYNCHRONOUS])
27
- ? $default($request, $options)
28
- : $sync($request, $options);
29
- };
30
- }
31
-
32
- /**
33
- * Sends streaming requests to a streaming compatible handler while sending
34
- * all other requests to a default handler.
35
- *
36
- * This, for example, could be useful for taking advantage of the
37
- * performance benefits of curl while still supporting true streaming
38
- * through the StreamHandler.
39
- *
40
- * @param callable $default Handler used for non-streaming responses
41
- * @param callable $streaming Handler used for streaming responses
42
- *
43
- * @return callable Returns the composed handler.
44
- */
45
- public static function wrapStreaming(
46
- callable $default,
47
- callable $streaming
48
- ) {
49
- return function (RequestInterface $request, array $options) use ($default, $streaming) {
50
- return empty($options['stream'])
51
- ? $default($request, $options)
52
- : $streaming($request, $options);
53
- };
54
- }
55
- }
1
+ <?php
2
+ namespace GuzzleHttp\Handler;
3
+
4
+ use GuzzleHttp\RequestOptions;
5
+ use Psr\Http\Message\RequestInterface;
6
+
7
+ /**
8
+ * Provides basic proxies for handlers.
9
+ */
10
+ class Proxy
11
+ {
12
+ /**
13
+ * Sends synchronous requests to a specific handler while sending all other
14
+ * requests to another handler.
15
+ *
16
+ * @param callable $default Handler used for normal responses
17
+ * @param callable $sync Handler used for synchronous responses.
18
+ *
19
+ * @return callable Returns the composed handler.
20
+ */
21
+ public static function wrapSync(
22
+ callable $default,
23
+ callable $sync
24
+ ) {
25
+ return function (RequestInterface $request, array $options) use ($default, $sync) {
26
+ return empty($options[RequestOptions::SYNCHRONOUS])
27
+ ? $default($request, $options)
28
+ : $sync($request, $options);
29
+ };
30
+ }
31
+
32
+ /**
33
+ * Sends streaming requests to a streaming compatible handler while sending
34
+ * all other requests to a default handler.
35
+ *
36
+ * This, for example, could be useful for taking advantage of the
37
+ * performance benefits of curl while still supporting true streaming
38
+ * through the StreamHandler.
39
+ *
40
+ * @param callable $default Handler used for non-streaming responses
41
+ * @param callable $streaming Handler used for streaming responses
42
+ *
43
+ * @return callable Returns the composed handler.
44
+ */
45
+ public static function wrapStreaming(
46
+ callable $default,
47
+ callable $streaming
48
+ ) {
49
+ return function (RequestInterface $request, array $options) use ($default, $streaming) {
50
+ return empty($options['stream'])
51
+ ? $default($request, $options)
52
+ : $streaming($request, $options);
53
+ };
54
+ }
55
+ }
vendor/guzzlehttp/guzzle/src/Handler/StreamHandler.php CHANGED
@@ -1,532 +1,532 @@
1
- <?php
2
- namespace GuzzleHttp\Handler;
3
-
4
- use GuzzleHttp\Exception\RequestException;
5
- use GuzzleHttp\Exception\ConnectException;
6
- use GuzzleHttp\Promise\FulfilledPromise;
7
- use GuzzleHttp\Promise\PromiseInterface;
8
- use GuzzleHttp\Psr7;
9
- use GuzzleHttp\TransferStats;
10
- use Psr\Http\Message\RequestInterface;
11
- use Psr\Http\Message\ResponseInterface;
12
- use Psr\Http\Message\StreamInterface;
13
-
14
- /**
15
- * HTTP handler that uses PHP's HTTP stream wrapper.
16
- */
17
- class StreamHandler
18
- {
19
- private $lastHeaders = [];
20
-
21
- /**
22
- * Sends an HTTP request.
23
- *
24
- * @param RequestInterface $request Request to send.
25
- * @param array $options Request transfer options.
26
- *
27
- * @return PromiseInterface
28
- */
29
- public function __invoke(RequestInterface $request, array $options)
30
- {
31
- // Sleep if there is a delay specified.
32
- if (isset($options['delay'])) {
33
- usleep($options['delay'] * 1000);
34
- }
35
-
36
- $startTime = isset($options['on_stats']) ? microtime(true) : null;
37
-
38
- try {
39
- // Does not support the expect header.
40
- $request = $request->withoutHeader('Expect');
41
-
42
- // Append a content-length header if body size is zero to match
43
- // cURL's behavior.
44
- if (0 === $request->getBody()->getSize()) {
45
- $request = $request->withHeader('Content-Length', 0);
46
- }
47
-
48
- return $this->createResponse(
49
- $request,
50
- $options,
51
- $this->createStream($request, $options),
52
- $startTime
53
- );
54
- } catch (\InvalidArgumentException $e) {
55
- throw $e;
56
- } catch (\Exception $e) {
57
- // Determine if the error was a networking error.
58
- $message = $e->getMessage();
59
- // This list can probably get more comprehensive.
60
- if (strpos($message, 'getaddrinfo') // DNS lookup failed
61
- || strpos($message, 'Connection refused')
62
- || strpos($message, "couldn't connect to host") // error on HHVM
63
- || strpos($message, "connection attempt failed")
64
- ) {
65
- $e = new ConnectException($e->getMessage(), $request, $e);
66
- }
67
- $e = RequestException::wrapException($request, $e);
68
- $this->invokeStats($options, $request, $startTime, null, $e);
69
-
70
- return \GuzzleHttp\Promise\rejection_for($e);
71
- }
72
- }
73
-
74
- private function invokeStats(
75
- array $options,
76
- RequestInterface $request,
77
- $startTime,
78
- ResponseInterface $response = null,
79
- $error = null
80
- ) {
81
- if (isset($options['on_stats'])) {
82
- $stats = new TransferStats(
83
- $request,
84
- $response,
85
- microtime(true) - $startTime,
86
- $error,
87
- []
88
- );
89
- call_user_func($options['on_stats'], $stats);
90
- }
91
- }
92
-
93
- private function createResponse(
94
- RequestInterface $request,
95
- array $options,
96
- $stream,
97
- $startTime
98
- ) {
99
- $hdrs = $this->lastHeaders;
100
- $this->lastHeaders = [];
101
- $parts = explode(' ', array_shift($hdrs), 3);
102
- $ver = explode('/', $parts[0])[1];
103
- $status = $parts[1];
104
- $reason = isset($parts[2]) ? $parts[2] : null;
105
- $headers = \GuzzleHttp\headers_from_lines($hdrs);
106
- list($stream, $headers) = $this->checkDecode($options, $headers, $stream);
107
- $stream = Psr7\stream_for($stream);
108
- $sink = $stream;
109
-
110
- if (strcasecmp('HEAD', $request->getMethod())) {
111
- $sink = $this->createSink($stream, $options);
112
- }
113
-
114
- $response = new Psr7\Response($status, $headers, $sink, $ver, $reason);
115
-
116
- if (isset($options['on_headers'])) {
117
- try {
118
- $options['on_headers']($response);
119
- } catch (\Exception $e) {
120
- $msg = 'An error was encountered during the on_headers event';
121
- $ex = new RequestException($msg, $request, $response, $e);
122
- return \GuzzleHttp\Promise\rejection_for($ex);
123
- }
124
- }
125
-
126
- // Do not drain when the request is a HEAD request because they have
127
- // no body.
128
- if ($sink !== $stream) {
129
- $this->drain(
130
- $stream,
131
- $sink,
132
- $response->getHeaderLine('Content-Length')
133
- );
134
- }
135
-
136
- $this->invokeStats($options, $request, $startTime, $response, null);
137
-
138
- return new FulfilledPromise($response);
139
- }
140
-
141
- private function createSink(StreamInterface $stream, array $options)
142
- {
143
- if (!empty($options['stream'])) {
144
- return $stream;
145
- }
146
-
147
- $sink = isset($options['sink'])
148
- ? $options['sink']
149
- : fopen('php://temp', 'r+');
150
-
151
- return is_string($sink)
152
- ? new Psr7\LazyOpenStream($sink, 'w+')
153
- : Psr7\stream_for($sink);
154
- }
155
-
156
- private function checkDecode(array $options, array $headers, $stream)
157
- {
158
- // Automatically decode responses when instructed.
159
- if (!empty($options['decode_content'])) {
160
- $normalizedKeys = \GuzzleHttp\normalize_header_keys($headers);
161
- if (isset($normalizedKeys['content-encoding'])) {
162
- $encoding = $headers[$normalizedKeys['content-encoding']];
163
- if ($encoding[0] === 'gzip' || $encoding[0] === 'deflate') {
164
- $stream = new Psr7\InflateStream(
165
- Psr7\stream_for($stream)
166
- );
167
- $headers['x-encoded-content-encoding']
168
- = $headers[$normalizedKeys['content-encoding']];
169
- // Remove content-encoding header
170
- unset($headers[$normalizedKeys['content-encoding']]);
171
- // Fix content-length header
172
- if (isset($normalizedKeys['content-length'])) {
173
- $headers['x-encoded-content-length']
174
- = $headers[$normalizedKeys['content-length']];
175
-
176
- $length = (int) $stream->getSize();
177
- if ($length === 0) {
178
- unset($headers[$normalizedKeys['content-length']]);
179
- } else {
180
- $headers[$normalizedKeys['content-length']] = [$length];
181
- }
182
- }
183
- }
184
- }
185
- }
186
-
187
- return [$stream, $headers];
188
- }
189
-
190
- /**
191
- * Drains the source stream into the "sink" client option.
192
- *
193
- * @param StreamInterface $source
194
- * @param StreamInterface $sink
195
- * @param string $contentLength Header specifying the amount of
196
- * data to read.
197
- *
198
- * @return StreamInterface
199
- * @throws \RuntimeException when the sink option is invalid.
200
- */
201
- private function drain(
202
- StreamInterface $source,
203
- StreamInterface $sink,
204
- $contentLength
205
- ) {
206
- // If a content-length header is provided, then stop reading once
207
- // that number of bytes has been read. This can prevent infinitely
208
- // reading from a stream when dealing with servers that do not honor
209
- // Connection: Close headers.
210
- Psr7\copy_to_stream(
211
- $source,
212
- $sink,
213
- (strlen($contentLength) > 0 && (int) $contentLength > 0) ? (int) $contentLength : -1
214
- );
215
-
216
- $sink->seek(0);
217
- $source->close();
218
-
219
- return $sink;
220
- }
221
-
222
- /**
223
- * Create a resource and check to ensure it was created successfully
224
- *
225
- * @param callable $callback Callable that returns stream resource
226
- *
227
- * @return resource
228
- * @throws \RuntimeException on error
229
- */
230
- private function createResource(callable $callback)
231
- {
232
- $errors = null;
233
- set_error_handler(function ($_, $msg, $file, $line) use (&$errors) {
234
- $errors[] = [
235
- 'message' => $msg,
236
- 'file' => $file,
237
- 'line' => $line
238
- ];
239
- return true;
240
- });
241
-
242
- $resource = $callback();
243
- restore_error_handler();
244
-
245
- if (!$resource) {
246
- $message = 'Error creating resource: ';
247
- foreach ($errors as $err) {
248
- foreach ($err as $key => $value) {
249
- $message .= "[$key] $value" . PHP_EOL;
250
- }
251
- }
252
- throw new \RuntimeException(trim($message));
253
- }
254
-
255
- return $resource;
256
- }
257
-
258
- private function createStream(RequestInterface $request, array $options)
259
- {
260
- static $methods;
261
- if (!$methods) {
262
- $methods = array_flip(get_class_methods(__CLASS__));
263
- }
264
-
265
- // HTTP/1.1 streams using the PHP stream wrapper require a
266
- // Connection: close header
267
- if ($request->getProtocolVersion() == '1.1'
268
- && !$request->hasHeader('Connection')
269
- ) {
270
- $request = $request->withHeader('Connection', 'close');
271
- }
272
-
273
- // Ensure SSL is verified by default
274
- if (!isset($options['verify'])) {
275
- $options['verify'] = true;
276
- }
277
-
278
- $params = [];
279
- $context = $this->getDefaultContext($request);
280
-
281
- if (isset($options['on_headers']) && !is_callable($options['on_headers'])) {
282
- throw new \InvalidArgumentException('on_headers must be callable');
283
- }
284
-
285
- if (!empty($options)) {
286
- foreach ($options as $key => $value) {
287
- $method = "add_{$key}";
288
- if (isset($methods[$method])) {
289
- $this->{$method}($request, $context, $value, $params);
290
- }
291
- }
292
- }
293
-
294
- if (isset($options['stream_context'])) {
295
- if (!is_array($options['stream_context'])) {
296
- throw new \InvalidArgumentException('stream_context must be an array');
297
- }
298
- $context = array_replace_recursive(
299
- $context,
300
- $options['stream_context']
301
- );
302
- }
303
-
304
- // Microsoft NTLM authentication only supported with curl handler
305
- if (isset($options['auth'])
306
- && is_array($options['auth'])
307
- && isset($options['auth'][2])
308
- && 'ntlm' == $options['auth'][2]
309
- ) {
310
- throw new \InvalidArgumentException('Microsoft NTLM authentication only supported with curl handler');
311
- }
312
-
313
- $uri = $this->resolveHost($request, $options);
314
-
315
- $context = $this->createResource(
316
- function () use ($context, $params) {
317
- return stream_context_create($context, $params);
318
- }
319
- );
320
-
321
- return $this->createResource(
322
- function () use ($uri, &$http_response_header, $context, $options) {
323
- $resource = fopen((string) $uri, 'r', null, $context);
324
- $this->lastHeaders = $http_response_header;
325
-
326
- if (isset($options['read_timeout'])) {
327
- $readTimeout = $options['read_timeout'];
328
- $sec = (int) $readTimeout;
329
- $usec = ($readTimeout - $sec) * 100000;
330
- stream_set_timeout($resource, $sec, $usec);
331
- }
332
-
333
- return $resource;
334
- }
335
- );
336
- }
337
-
338
- private function resolveHost(RequestInterface $request, array $options)
339
- {
340
- $uri = $request->getUri();
341
-
342
- if (isset($options['force_ip_resolve']) && !filter_var($uri->getHost(), FILTER_VALIDATE_IP)) {
343
- if ('v4' === $options['force_ip_resolve']) {
344
- $records = dns_get_record($uri->getHost(), DNS_A);
345
- if (!isset($records[0]['ip'])) {
346
- throw new ConnectException(sprintf("Could not resolve IPv4 address for host '%s'", $uri->getHost()), $request);
347
- }
348
- $uri = $uri->withHost($records[0]['ip']);
349
- } elseif ('v6' === $options['force_ip_resolve']) {
350
- $records = dns_get_record($uri->getHost(), DNS_AAAA);
351
- if (!isset($records[0]['ipv6'])) {
352
- throw new ConnectException(sprintf("Could not resolve IPv6 address for host '%s'", $uri->getHost()), $request);
353
- }
354
- $uri = $uri->withHost('[' . $records[0]['ipv6'] . ']');
355
- }
356
- }
357
-
358
- return $uri;
359
- }
360
-
361
- private function getDefaultContext(RequestInterface $request)
362
- {
363
- $headers = '';
364
- foreach ($request->getHeaders() as $name => $value) {
365
- foreach ($value as $val) {
366
- $headers .= "$name: $val\r\n";
367
- }
368
- }
369
-
370
- $context = [
371
- 'http' => [
372
- 'method' => $request->getMethod(),
373
- 'header' => $headers,
374
- 'protocol_version' => $request->getProtocolVersion(),
375
- 'ignore_errors' => true,
376
- 'follow_location' => 0,
377
- ],
378
- ];
379
-
380
- $body = (string) $request->getBody();
381
-
382
- if (!empty($body)) {
383
- $context['http']['content'] = $body;
384
- // Prevent the HTTP handler from adding a Content-Type header.
385
- if (!$request->hasHeader('Content-Type')) {
386
- $context['http']['header'] .= "Content-Type:\r\n";
387
- }
388
- }
389
-
390
- $context['http']['header'] = rtrim($context['http']['header']);
391
-
392
- return $context;
393
- }
394
-
395
- private function add_proxy(RequestInterface $request, &$options, $value, &$params)
396
- {
397
- if (!is_array($value)) {
398
- $options['http']['proxy'] = $value;
399
- } else {
400
- $scheme = $request->getUri()->getScheme();
401
- if (isset($value[$scheme])) {
402
- if (!isset($value['no'])
403
- || !\GuzzleHttp\is_host_in_noproxy(
404
- $request->getUri()->getHost(),
405
- $value['no']
406
- )
407
- ) {
408
- $options['http']['proxy'] = $value[$scheme];
409
- }
410
- }
411
- }
412
- }
413
-
414
- private function add_timeout(RequestInterface $request, &$options, $value, &$params)
415
- {
416
- if ($value > 0) {
417
- $options['http']['timeout'] = $value;
418
- }
419
- }
420
-
421
- private function add_verify(RequestInterface $request, &$options, $value, &$params)
422
- {
423
- if ($value === true) {
424
- // PHP 5.6 or greater will find the system cert by default. When
425
- // < 5.6, use the Guzzle bundled cacert.
426
- if (PHP_VERSION_ID < 50600) {
427
- $options['ssl']['cafile'] = \GuzzleHttp\default_ca_bundle();
428
- }
429
- } elseif (is_string($value)) {
430
- $options['ssl']['cafile'] = $value;
431
- if (!file_exists($value)) {
432
- throw new \RuntimeException("SSL CA bundle not found: $value");
433
- }
434
- } elseif ($value === false) {
435
- $options['ssl']['verify_peer'] = false;
436
- $options['ssl']['verify_peer_name'] = false;
437
- return;
438
- } else {
439
- throw new \InvalidArgumentException('Invalid verify request option');
440
- }
441
-
442
- $options['ssl']['verify_peer'] = true;
443
- $options['ssl']['verify_peer_name'] = true;
444
- $options['ssl']['allow_self_signed'] = false;
445
- }
446
-
447
- private function add_cert(RequestInterface $request, &$options, $value, &$params)
448
- {
449
- if (is_array($value)) {
450
- $options['ssl']['passphrase'] = $value[1];
451
- $value = $value[0];
452
- }
453
-
454
- if (!file_exists($value)) {
455
- throw new \RuntimeException("SSL certificate not found: {$value}");
456
- }
457
-
458
- $options['ssl']['local_cert'] = $value;
459
- }
460
-
461
- private function add_progress(RequestInterface $request, &$options, $value, &$params)
462
- {
463
- $this->addNotification(
464
- $params,
465
- function ($code, $a, $b, $c, $transferred, $total) use ($value) {
466
- if ($code == STREAM_NOTIFY_PROGRESS) {
467
- $value($total, $transferred, null, null);
468
- }
469
- }
470
- );
471
- }
472
-
473
- private function add_debug(RequestInterface $request, &$options, $value, &$params)
474
- {
475
- if ($value === false) {
476
- return;
477
- }
478
-
479
- static $map = [
480
- STREAM_NOTIFY_CONNECT => 'CONNECT',
481
- STREAM_NOTIFY_AUTH_REQUIRED => 'AUTH_REQUIRED',
482
- STREAM_NOTIFY_AUTH_RESULT => 'AUTH_RESULT',
483
- STREAM_NOTIFY_MIME_TYPE_IS => 'MIME_TYPE_IS',
484
- STREAM_NOTIFY_FILE_SIZE_IS => 'FILE_SIZE_IS',
485
- STREAM_NOTIFY_REDIRECTED => 'REDIRECTED',
486
- STREAM_NOTIFY_PROGRESS => 'PROGRESS',
487
- STREAM_NOTIFY_FAILURE => 'FAILURE',
488
- STREAM_NOTIFY_COMPLETED => 'COMPLETED',
489
- STREAM_NOTIFY_RESOLVE => 'RESOLVE',
490
- ];
491
- static $args = ['severity', 'message', 'message_code',
492
- 'bytes_transferred', 'bytes_max'];
493
-
494
- $value = \GuzzleHttp\debug_resource($value);
495
- $ident = $request->getMethod() . ' ' . $request->getUri()->withFragment('');
496
- $this->addNotification(
497
- $params,
498
- function () use ($ident, $value, $map, $args) {
499
- $passed = func_get_args();
500
- $code = array_shift($passed);
501
- fprintf($value, '<%s> [%s] ', $ident, $map[$code]);
502
- foreach (array_filter($passed) as $i => $v) {
503
- fwrite($value, $args[$i] . ': "' . $v . '" ');
504
- }
505
- fwrite($value, "\n");
506
- }
507
- );
508
- }
509
-
510
- private function addNotification(array &$params, callable $notify)
511
- {
512
- // Wrap the existing function if needed.
513
- if (!isset($params['notification'])) {
514
- $params['notification'] = $notify;
515
- } else {
516
- $params['notification'] = $this->callArray([
517
- $params['notification'],
518
- $notify
519
- ]);
520
- }
521
- }
522
-
523
- private function callArray(array $functions)
524
- {
525
- return function () use ($functions) {
526
- $args = func_get_args();
527
- foreach ($functions as $fn) {
528
- call_user_func_array($fn, $args);
529
- }
530
- };
531
- }
532
- }
1
+ <?php
2
+ namespace GuzzleHttp\Handler;
3
+
4
+ use GuzzleHttp\Exception\RequestException;
5
+ use GuzzleHttp\Exception\ConnectException;
6
+ use GuzzleHttp\Promise\FulfilledPromise;
7
+ use GuzzleHttp\Promise\PromiseInterface;
8
+ use GuzzleHttp\Psr7;
9
+ use GuzzleHttp\TransferStats;
10
+ use Psr\Http\Message\RequestInterface;
11
+ use Psr\Http\Message\ResponseInterface;
12
+ use Psr\Http\Message\StreamInterface;
13
+
14
+ /**
15
+ * HTTP handler that uses PHP's HTTP stream wrapper.
16
+ */
17
+ class StreamHandler
18
+ {
19
+ private $lastHeaders = [];
20
+
21
+ /**
22
+ * Sends an HTTP request.
23
+ *
24
+ * @param RequestInterface $request Request to send.
25
+ * @param array $options Request transfer options.
26
+ *
27
+ * @return PromiseInterface
28
+ */
29
+ public function __invoke(RequestInterface $request, array $options)
30
+ {
31
+ // Sleep if there is a delay specified.
32
+ if (isset($options['delay'])) {
33
+ usleep($options['delay'] * 1000);
34
+ }
35
+
36
+ $startTime = isset($options['on_stats']) ? microtime(true) : null;
37
+
38
+ try {
39
+ // Does not support the expect header.
40
+ $request = $request->withoutHeader('Expect');
41
+
42
+ // Append a content-length header if body size is zero to match
43
+ // cURL's behavior.
44
+ if (0 === $request->getBody()->getSize()) {
45
+ $request = $request->withHeader('Content-Length', 0);
46
+ }
47
+
48
+ return $this->createResponse(
49
+ $request,
50
+ $options,
51
+ $this->createStream($request, $options),
52
+ $startTime
53
+ );
54
+ } catch (\InvalidArgumentException $e) {
55
+ throw $e;
56
+ } catch (\Exception $e) {
57
+ // Determine if the error was a networking error.
58
+ $message = $e->getMessage();
59
+ // This list can probably get more comprehensive.
60
+ if (strpos($message, 'getaddrinfo') // DNS lookup failed
61
+ || strpos($message, 'Connection refused')
62
+ || strpos($message, "couldn't connect to host") // error on HHVM
63
+ || strpos($message, "connection attempt failed")
64
+ ) {
65
+ $e = new ConnectException($e->getMessage(), $request, $e);
66
+ }
67
+ $e = RequestException::wrapException($request, $e);
68
+ $this->invokeStats($options, $request, $startTime, null, $e);
69
+
70
+ return \GuzzleHttp\Promise\rejection_for($e);
71
+ }
72
+ }
73
+
74
+ private function invokeStats(
75
+ array $options,
76
+ RequestInterface $request,
77
+ $startTime,
78
+ ResponseInterface $response = null,
79
+ $error = null
80
+ ) {
81
+ if (isset($options['on_stats'])) {
82
+ $stats = new TransferStats(
83
+ $request,
84
+ $response,
85
+ microtime(true) - $startTime,
86
+ $error,
87
+ []
88
+ );
89
+ call_user_func($options['on_stats'], $stats);
90
+ }
91
+ }
92
+
93
+ private function createResponse(
94
+ RequestInterface $request,
95
+ array $options,
96
+ $stream,
97
+ $startTime
98
+ ) {
99
+ $hdrs = $this->lastHeaders;
100
+ $this->lastHeaders = [];
101
+ $parts = explode(' ', array_shift($hdrs), 3);
102
+ $ver = explode('/', $parts[0])[1];
103
+ $status = $parts[1];
104
+ $reason = isset($parts[2]) ? $parts[2] : null;
105
+ $headers = \GuzzleHttp\headers_from_lines($hdrs);
106
+ list($stream, $headers) = $this->checkDecode($options, $headers, $stream);
107
+ $stream = Psr7\stream_for($stream);
108
+ $sink = $stream;
109
+
110
+ if (strcasecmp('HEAD', $request->getMethod())) {
111
+ $sink = $this->createSink($stream, $options);
112
+ }
113
+
114
+ $response = new Psr7\Response($status, $headers, $sink, $ver, $reason);
115
+
116
+ if (isset($options['on_headers'])) {
117
+ try {
118
+ $options['on_headers']($response);
119
+ } catch (\Exception $e) {
120
+ $msg = 'An error was encountered during the on_headers event';
121
+ $ex = new RequestException($msg, $request, $response, $e);
122
+ return \GuzzleHttp\Promise\rejection_for($ex);
123
+ }
124
+ }
125
+
126
+ // Do not drain when the request is a HEAD request because they have
127
+ // no body.
128
+ if ($sink !== $stream) {
129
+ $this->drain(
130
+ $stream,
131
+ $sink,
132
+ $response->getHeaderLine('Content-Length')
133
+ );
134
+ }
135
+
136
+ $this->invokeStats($options, $request, $startTime, $response, null);
137
+
138
+ return new FulfilledPromise($response);
139
+ }
140
+
141
+ private function createSink(StreamInterface $stream, array $options)
142
+ {
143
+ if (!empty($options['stream'])) {
144
+ return $stream;
145
+ }
146
+
147
+ $sink = isset($options['sink'])
148
+ ? $options['sink']
149
+ : fopen('php://temp', 'r+');
150
+
151
+ return is_string($sink)
152
+ ? new Psr7\LazyOpenStream($sink, 'w+')
153
+ : Psr7\stream_for($sink);
154
+ }
155
+
156
+ private function checkDecode(array $options, array $headers, $stream)
157
+ {
158
+ // Automatically decode responses when instructed.
159
+ if (!empty($options['decode_content'])) {
160
+ $normalizedKeys = \GuzzleHttp\normalize_header_keys($headers);
161
+ if (isset($normalizedKeys['content-encoding'])) {
162
+ $encoding = $headers[$normalizedKeys['content-encoding']];
163
+ if ($encoding[0] === 'gzip' || $encoding[0] === 'deflate') {
164
+ $stream = new Psr7\InflateStream(
165
+ Psr7\stream_for($stream)
166
+ );
167
+ $headers['x-encoded-content-encoding']
168
+ = $headers[$normalizedKeys['content-encoding']];
169
+ // Remove content-encoding header
170
+ unset($headers[$normalizedKeys['content-encoding']]);
171
+ // Fix content-length header
172
+ if (isset($normalizedKeys['content-length'])) {
173
+ $headers['x-encoded-content-length']
174
+ = $headers[$normalizedKeys['content-length']];
175
+
176
+ $length = (int) $stream->getSize();
177
+ if ($length === 0) {
178
+ unset($headers[$normalizedKeys['content-length']]);
179
+ } else {
180
+ $headers[$normalizedKeys['content-length']] = [$length];
181
+ }
182
+ }
183
+ }
184
+ }
185
+ }
186
+
187
+ return [$stream, $headers];
188
+ }
189
+
190
+ /**
191
+ * Drains the source stream into the "sink" client option.
192
+ *
193
+ * @param StreamInterface $source
194
+ * @param StreamInterface $sink
195
+ * @param string $contentLength Header specifying the amount of
196
+ * data to read.
197
+ *
198
+ * @return StreamInterface
199
+ * @throws \RuntimeException when the sink option is invalid.
200
+ */
201
+ private function drain(
202
+ StreamInterface $source,
203
+ StreamInterface $sink,
204
+ $contentLength
205
+ ) {
206
+ // If a content-length header is provided, then stop reading once
207
+ // that number of bytes has been read. This can prevent infinitely
208
+ // reading from a stream when dealing with servers that do not honor
209
+ // Connection: Close headers.
210
+ Psr7\copy_to_stream(
211
+ $source,
212
+ $sink,
213
+ (strlen($contentLength) > 0 && (int) $contentLength > 0) ? (int) $contentLength : -1
214
+ );
215
+
216
+ $sink->seek(0);
217
+ $source->close();
218
+
219
+ return $sink;
220
+ }
221
+
222
+ /**
223
+ * Create a resource and check to ensure it was created successfully
224
+ *
225
+ * @param callable $callback Callable that returns stream resource
226
+ *
227
+ * @return resource
228
+ * @throws \RuntimeException on error
229
+ */
230
+ private function createResource(callable $callback)
231
+ {
232
+ $errors = null;
233
+ set_error_handler(function ($_, $msg, $file, $line) use (&$errors) {
234
+ $errors[] = [
235
+ 'message' => $msg,
236
+ 'file' => $file,
237
+ 'line' => $line
238
+ ];
239
+ return true;
240
+ });
241
+
242
+ $resource = $callback();
243
+ restore_error_handler();
244
+
245
+ if (!$resource) {
246
+ $message = 'Error creating resource: ';
247
+ foreach ($errors as $err) {
248
+ foreach ($err as $key => $value) {
249
+ $message .= "[$key] $value" . PHP_EOL;
250
+ }
251
+ }
252
+ throw new \RuntimeException(trim($message));
253
+ }
254
+
255
+ return $resource;
256
+ }
257
+
258
+ private function createStream(RequestInterface $request, array $options)
259
+ {
260
+ static $methods;
261
+ if (!$methods) {
262
+ $methods = array_flip(get_class_methods(__CLASS__));
263
+ }
264
+
265
+ // HTTP/1.1 streams using the PHP stream wrapper require a
266
+ // Connection: close header
267
+ if ($request->getProtocolVersion() == '1.1'
268
+ && !$request->hasHeader('Connection')
269
+ ) {
270
+ $request = $request->withHeader('Connection', 'close');
271
+ }
272
+
273
+ // Ensure SSL is verified by default
274
+ if (!isset($options['verify'])) {
275
+ $options['verify'] = true;
276
+ }
277
+
278
+ $params = [];
279
+ $context = $this->getDefaultContext($request);
280
+
281
+ if (isset($options['on_headers']) && !is_callable($options['on_headers'])) {
282
+ throw new \InvalidArgumentException('on_headers must be callable');
283
+ }
284
+
285
+ if (!empty($options)) {
286
+ foreach ($options as $key => $value) {
287
+ $method = "add_{$key}";
288
+ if (isset($methods[$method])) {
289
+ $this->{$method}($request, $context, $value, $params);
290
+ }
291
+ }
292
+ }
293
+
294
+ if (isset($options['stream_context'])) {
295
+ if (!is_array($options['stream_context'])) {
296
+ throw new \InvalidArgumentException('stream_context must be an array');
297
+ }
298
+ $context = array_replace_recursive(
299
+ $context,
300
+ $options['stream_context']
301
+ );
302
+ }
303
+
304
+ // Microsoft NTLM authentication only supported with curl handler
305
+ if (isset($options['auth'])
306
+ && is_array($options['auth'])
307
+ && isset($options['auth'][2])
308
+ && 'ntlm' == $options['auth'][2]
309
+ ) {
310
+ throw new \InvalidArgumentException('Microsoft NTLM authentication only supported with curl handler');
311
+ }
312
+
313
+ $uri = $this->resolveHost($request, $options);
314
+
315
+ $context = $this->createResource(
316
+ function () use ($context, $params) {
317
+ return stream_context_create($context, $params);
318
+ }
319
+ );
320
+
321
+ return $this->createResource(
322
+ function () use ($uri, &$http_response_header, $context, $options) {
323
+ $resource = fopen((string) $uri, 'r', null, $context);
324
+ $this->lastHeaders = $http_response_header;
325
+
326
+ if (isset($options['read_timeout'])) {
327
+ $readTimeout = $options['read_timeout'];
328
+ $sec = (int) $readTimeout;
329
+ $usec = ($readTimeout - $sec) * 100000;
330
+ stream_set_timeout($resource, $sec, $usec);
331
+ }
332
+
333
+ return $resource;
334
+ }
335
+ );
336
+ }
337
+
338
+ private function resolveHost(RequestInterface $request, array $options)
339
+ {
340
+ $uri = $request->getUri();
341
+
342
+ if (isset($options['force_ip_resolve']) && !filter_var($uri->getHost(), FILTER_VALIDATE_IP)) {
343
+ if ('v4' === $options['force_ip_resolve']) {
344
+ $records = dns_get_record($uri->getHost(), DNS_A);
345
+ if (!isset($records[0]['ip'])) {
346
+ throw new ConnectException(sprintf("Could not resolve IPv4 address for host '%s'", $uri->getHost()), $request);
347
+ }
348
+ $uri = $uri->withHost($records[0]['ip']);
349
+ } elseif ('v6' === $options['force_ip_resolve']) {
350
+ $records = dns_get_record($uri->getHost(), DNS_AAAA);
351
+ if (!isset($records[0]['ipv6'])) {
352
+ throw new ConnectException(sprintf("Could not resolve IPv6 address for host '%s'", $uri->getHost()), $request);
353
+ }
354
+ $uri = $uri->withHost('[' . $records[0]['ipv6'] . ']');
355
+ }
356
+ }
357
+
358
+ return $uri;
359
+ }
360
+
361
+ private function getDefaultContext(RequestInterface $request)
362
+ {
363
+ $headers = '';
364
+ foreach ($request->getHeaders() as $name => $value) {
365
+ foreach ($value as $val) {
366
+ $headers .= "$name: $val\r\n";
367
+ }
368
+ }
369
+
370
+ $context = [
371
+ 'http' => [
372
+ 'method' => $request->getMethod(),
373
+ 'header' => $headers,
374
+ 'protocol_version' => $request->getProtocolVersion(),
375
+ 'ignore_errors' => true,
376
+ 'follow_location' => 0,
377
+ ],
378
+ ];
379
+
380
+ $body = (string) $request->getBody();
381
+
382
+ if (!empty($body)) {
383
+ $context['http']['content'] = $body;
384
+ // Prevent the HTTP handler from adding a Content-Type header.
385
+ if (!$request->hasHeader('Content-Type')) {
386
+ $context['http']['header'] .= "Content-Type:\r\n";
387
+ }
388
+ }
389
+
390
+ $context['http']['header'] = rtrim($context['http']['header']);
391
+
392
+ return $context;
393
+ }
394
+
395
+ private function add_proxy(RequestInterface $request, &$options, $value, &$params)
396
+ {
397
+ if (!is_array($value)) {
398
+ $options['http']['proxy'] = $value;
399
+ } else {
400
+ $scheme = $request->getUri()->getScheme();
401
+ if (isset($value[$scheme])) {
402
+ if (!isset($value['no'])
403
+ || !\GuzzleHttp\is_host_in_noproxy(
404
+ $request->getUri()->getHost(),
405
+ $value['no']
406
+ )
407
+ ) {
408
+ $options['http']['proxy'] = $value[$scheme];
409
+ }
410
+ }
411
+ }
412
+ }
413
+
414
+ private function add_timeout(RequestInterface $request, &$options, $value, &$params)
415
+ {
416
+ if ($value > 0) {
417
+ $options['http']['timeout'] = $value;
418
+ }
419
+ }
420
+
421
+ private function add_verify(RequestInterface $request, &$options, $value, &$params)
422
+ {
423
+ if ($value === true) {
424
+ // PHP 5.6 or greater will find the system cert by default. When
425
+ // < 5.6, use the Guzzle bundled cacert.
426
+ if (PHP_VERSION_ID < 50600) {
427
+ $options['ssl']['cafile'] = \GuzzleHttp\default_ca_bundle();
428
+ }
429
+ } elseif (is_string($value)) {
430
+ $options['ssl']['cafile'] = $value;
431
+ if (!file_exists($value)) {
432
+ throw new \RuntimeException("SSL CA bundle not found: $value");
433
+ }
434
+ } elseif ($value === false) {
435
+ $options['ssl']['verify_peer'] = false;
436
+ $options['ssl']['verify_peer_name'] = false;
437
+ return;
438
+ } else {
439
+ throw new \InvalidArgumentException('Invalid verify request option');
440
+ }
441
+
442
+ $options['ssl']['verify_peer'] = true;
443
+ $options['ssl']['verify_peer_name'] = true;
444
+ $options['ssl']['allow_self_signed'] = false;
445
+ }
446
+
447
+ private function add_cert(RequestInterface $request, &$options, $value, &$params)
448
+ {
449
+ if (is_array($value)) {
450
+ $options['ssl']['passphrase'] = $value[1];
451
+ $value = $value[0];
452
+ }
453
+
454
+ if (!file_exists($value)) {
455
+ throw new \RuntimeException("SSL certificate not found: {$value}");
456
+ }
457
+
458
+ $options['ssl']['local_cert'] = $value;
459
+ }
460
+
461
+ private function add_progress(RequestInterface $request, &$options, $value, &$params)
462
+ {
463
+ $this->addNotification(
464
+ $params,
465
+ function ($code, $a, $b, $c, $transferred, $total) use ($value) {
466
+ if ($code == STREAM_NOTIFY_PROGRESS) {
467
+ $value($total, $transferred, null, null);
468
+ }
469
+ }
470
+ );
471
+ }
472
+
473
+ private function add_debug(RequestInterface $request, &$options, $value, &$params)
474
+ {
475
+ if ($value === false) {
476
+ return;
477
+ }
478
+
479
+ static $map = [
480
+ STREAM_NOTIFY_CONNECT => 'CONNECT',
481
+ STREAM_NOTIFY_AUTH_REQUIRED => 'AUTH_REQUIRED',
482
+ STREAM_NOTIFY_AUTH_RESULT => 'AUTH_RESULT',
483
+ STREAM_NOTIFY_MIME_TYPE_IS => 'MIME_TYPE_IS',
484
+ STREAM_NOTIFY_FILE_SIZE_IS => 'FILE_SIZE_IS',
485
+ STREAM_NOTIFY_REDIRECTED => 'REDIRECTED',
486
+ STREAM_NOTIFY_PROGRESS => 'PROGRESS',
487
+ STREAM_NOTIFY_FAILURE => 'FAILURE',
488
+ STREAM_NOTIFY_COMPLETED => 'COMPLETED',
489
+ STREAM_NOTIFY_RESOLVE => 'RESOLVE',
490
+ ];
491
+ static $args = ['severity', 'message', 'message_code',
492
+ 'bytes_transferred', 'bytes_max'];
493
+
494
+ $value = \GuzzleHttp\debug_resource($value);
495
+ $ident = $request->getMethod() . ' ' . $request->getUri()->withFragment('');
496
+ $this->addNotification(
497
+ $params,
498
+ function () use ($ident, $value, $map, $args) {
499
+ $passed = func_get_args();
500
+ $code = array_shift($passed);
501
+ fprintf($value, '<%s> [%s] ', $ident, $map[$code]);
502
+ foreach (array_filter($passed) as $i => $v) {
503
+ fwrite($value, $args[$i] . ': "' . $v . '" ');
504
+ }
505
+ fwrite($value, "\n");
506
+ }
507
+ );
508
+ }
509
+
510
+ private function addNotification(array &$params, callable $notify)
511
+ {
512
+ // Wrap the existing function if needed.
513
+ if (!isset($params['notification'])) {
514
+ $params['notification'] = $notify;
515
+ } else {
516
+ $params['notification'] = $this->callArray([
517
+ $params['notification'],
518
+ $notify
519
+ ]);
520
+ }
521
+ }
522
+
523
+ private function callArray(array $functions)
524
+ {
525
+ return function () use ($functions) {
526
+ $args = func_get_args();
527
+ foreach ($functions as $fn) {
528
+ call_user_func_array($fn, $args);
529
+ }
530
+ };
531
+ }
532
+ }
vendor/guzzlehttp/guzzle/src/HandlerStack.php CHANGED
@@ -1,273 +1,273 @@
1
- <?php
2
- namespace GuzzleHttp;
3
-
4
- use Psr\Http\Message\RequestInterface;
5
-
6
- /**
7
- * Creates a composed Guzzle handler function by stacking middlewares on top of
8
- * an HTTP handler function.
9
- */
10
- class HandlerStack
11
- {
12
- /** @var callable */
13
- private $handler;
14
-
15
- /** @var array */
16
- private $stack = [];
17
-
18
- /** @var callable|null */
19
- private $cached;
20
-
21
- /**
22
- * Creates a default handler stack that can be used by clients.
23
- *
24
- * The returned handler will wrap the provided handler or use the most
25
- * appropriate default handler for your system. The returned HandlerStack has
26
- * support for cookies, redirects, HTTP error exceptions, and preparing a body
27
- * before sending.
28
- *
29
- * The returned handler stack can be passed to a client in the "handler"
30
- * option.
31
- *
32
- * @param callable $handler HTTP handler function to use with the stack. If no
33
- * handler is provided, the best handler for your
34
- * system will be utilized.
35
- *
36
- * @return HandlerStack
37
- */
38
- public static function create(callable $handler = null)
39
- {
40
- $stack = new self($handler ?: choose_handler());
41
- $stack->push(Middleware::httpErrors(), 'http_errors');
42
- $stack->push(Middleware::redirect(), 'allow_redirects');
43
- $stack->push(Middleware::cookies(), 'cookies');
44
- $stack->push(Middleware::prepareBody(), 'prepare_body');
45
-
46
- return $stack;
47
- }
48
-
49
- /**
50
- * @param callable $handler Underlying HTTP handler.
51
- */
52
- public function __construct(callable $handler = null)
53
- {
54
- $this->handler = $handler;
55
- }
56
-
57
- /**
58
- * Invokes the handler stack as a composed handler
59
- *
60
- * @param RequestInterface $request
61
- * @param array $options
62
- */
63
- public function __invoke(RequestInterface $request, array $options)
64
- {
65
- $handler = $this->resolve();
66
-
67
- return $handler($request, $options);
68
- }
69
-
70
- /**
71
- * Dumps a string representation of the stack.
72
- *
73
- * @return string
74
- */
75
- public function __toString()
76
- {
77
- $depth = 0;
78
- $stack = [];
79
- if ($this->handler) {
80
- $stack[] = "0) Handler: " . $this->debugCallable($this->handler);
81
- }
82
-
83
- $result = '';
84
- foreach (array_reverse($this->stack) as $tuple) {
85
- $depth++;
86
- $str = "{$depth}) Name: '{$tuple[1]}', ";
87
- $str .= "Function: " . $this->debugCallable($tuple[0]);
88
- $result = "> {$str}\n{$result}";
89
- $stack[] = $str;
90
- }
91
-
92
- foreach (array_keys($stack) as $k) {
93
- $result .= "< {$stack[$k]}\n";
94
- }
95
-
96
- return $result;
97
- }
98
-
99
- /**
100
- * Set the HTTP handler that actually returns a promise.
101
- *
102
- * @param callable $handler Accepts a request and array of options and
103
- * returns a Promise.
104
- */
105
- public function setHandler(callable $handler)
106
- {
107
- $this->handler = $handler;
108
- $this->cached = null;
109
- }
110
-
111
- /**
112
- * Returns true if the builder has a handler.
113
- *
114
- * @return bool
115
- */
116
- public function hasHandler()
117
- {
118
- return (bool) $this->handler;
119
- }
120
-
121
- /**
122
- * Unshift a middleware to the bottom of the stack.
123
- *
124
- * @param callable $middleware Middleware function
125
- * @param string $name Name to register for this middleware.
126
- */
127
- public function unshift(callable $middleware, $name = null)
128
- {
129
- array_unshift($this->stack, [$middleware, $name]);
130
- $this->cached = null;
131
- }
132
-
133
- /**
134
- * Push a middleware to the top of the stack.
135
- *
136
- * @param callable $middleware Middleware function
137
- * @param string $name Name to register for this middleware.
138
- */
139
- public function push(callable $middleware, $name = '')
140
- {
141
- $this->stack[] = [$middleware, $name];
142
- $this->cached = null;
143
- }
144
-
145
- /**
146
- * Add a middleware before another middleware by name.
147
- *
148
- * @param string $findName Middleware to find
149
- * @param callable $middleware Middleware function
150
- * @param string $withName Name to register for this middleware.
151
- */
152
- public function before($findName, callable $middleware, $withName = '')
153
- {
154
- $this->splice($findName, $withName, $middleware, true);
155
- }
156
-
157
- /**
158
- * Add a middleware after another middleware by name.
159
- *
160
- * @param string $findName Middleware to find
161
- * @param callable $middleware Middleware function
162
- * @param string $withName Name to register for this middleware.
163
- */
164
- public function after($findName, callable $middleware, $withName = '')
165
- {
166
- $this->splice($findName, $withName, $middleware, false);
167
- }
168
-
169
- /**
170
- * Remove a middleware by instance or name from the stack.
171
- *
172
- * @param callable|string $remove Middleware to remove by instance or name.
173
- */
174
- public function remove($remove)
175
- {
176
- $this->cached = null;
177
- $idx = is_callable($remove) ? 0 : 1;
178
- $this->stack = array_values(array_filter(
179
- $this->stack,
180
- function ($tuple) use ($idx, $remove) {
181
- return $tuple[$idx] !== $remove;
182
- }
183
- ));
184
- }
185
-
186
- /**
187
- * Compose the middleware and handler into a single callable function.
188
- *
189
- * @return callable
190
- */
191
- public function resolve()
192
- {
193
- if (!$this->cached) {
194
- if (!($prev = $this->handler)) {
195
- throw new \LogicException('No handler has been specified');
196
- }
197
-
198
- foreach (array_reverse($this->stack) as $fn) {
199
- $prev = $fn[0]($prev);
200
- }
201
-
202
- $this->cached = $prev;
203
- }
204
-
205
- return $this->cached;
206
- }
207
-
208
- /**
209
- * @param $name
210
- * @return int
211
- */
212
- private function findByName($name)
213
- {
214
- foreach ($this->stack as $k => $v) {
215
- if ($v[1] === $name) {
216
- return $k;
217
- }
218
- }
219
-
220
- throw new \InvalidArgumentException("Middleware not found: $name");
221
- }
222
-
223
- /**
224
- * Splices a function into the middleware list at a specific position.
225
- *
226
- * @param $findName
227
- * @param $withName
228
- * @param callable $middleware
229
- * @param $before
230
- */
231
- private function splice($findName, $withName, callable $middleware, $before)
232
- {
233
- $this->cached = null;
234
- $idx = $this->findByName($findName);
235
- $tuple = [$middleware, $withName];
236
-
237
- if ($before) {
238
- if ($idx === 0) {
239
- array_unshift($this->stack, $tuple);
240
- } else {
241
- $replacement = [$tuple, $this->stack[$idx]];
242
- array_splice($this->stack, $idx, 1, $replacement);
243
- }
244
- } elseif ($idx === count($this->stack) - 1) {
245
- $this->stack[] = $tuple;
246
- } else {
247
- $replacement = [$this->stack[$idx], $tuple];
248
- array_splice($this->stack, $idx, 1, $replacement);
249
- }
250
- }
251
-
252
- /**
253
- * Provides a debug string for a given callable.
254
- *
255
- * @param array|callable $fn Function to write as a string.
256
- *
257
- * @return string
258
- */
259
- private function debugCallable($fn)
260
- {
261
- if (is_string($fn)) {
262
- return "callable({$fn})";
263
- }
264
-
265
- if (is_array($fn)) {
266
- return is_string($fn[0])
267
- ? "callable({$fn[0]}::{$fn[1]})"
268
- : "callable(['" . get_class($fn[0]) . "', '{$fn[1]}'])";
269
- }
270
-
271
- return 'callable(' . spl_object_hash($fn) . ')';
272
- }
273
- }
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ use Psr\Http\Message\RequestInterface;
5
+
6
+ /**
7
+ * Creates a composed Guzzle handler function by stacking middlewares on top of
8
+ * an HTTP handler function.
9
+ */
10
+ class HandlerStack
11
+ {
12
+ /** @var callable */
13
+ private $handler;
14
+
15
+ /** @var array */
16
+ private $stack = [];
17
+
18
+ /** @var callable|null */
19
+ private $cached;
20
+
21
+ /**
22
+ * Creates a default handler stack that can be used by clients.
23
+ *
24
+ * The returned handler will wrap the provided handler or use the most
25
+ * appropriate default handler for your system. The returned HandlerStack has
26
+ * support for cookies, redirects, HTTP error exceptions, and preparing a body
27
+ * before sending.
28
+ *
29
+ * The returned handler stack can be passed to a client in the "handler"
30
+ * option.
31
+ *
32
+ * @param callable $handler HTTP handler function to use with the stack. If no
33
+ * handler is provided, the best handler for your
34
+ * system will be utilized.
35
+ *
36
+ * @return HandlerStack
37
+ */
38
+ public static function create(callable $handler = null)
39
+ {
40
+ $stack = new self($handler ?: choose_handler());
41
+ $stack->push(Middleware::httpErrors(), 'http_errors');
42
+ $stack->push(Middleware::redirect(), 'allow_redirects');
43
+ $stack->push(Middleware::cookies(), 'cookies');
44
+ $stack->push(Middleware::prepareBody(), 'prepare_body');
45
+
46
+ return $stack;
47
+ }
48
+
49
+ /**
50
+ * @param callable $handler Underlying HTTP handler.
51
+ */
52
+ public function __construct(callable $handler = null)
53
+ {
54
+ $this->handler = $handler;
55
+ }
56
+
57
+ /**
58
+ * Invokes the handler stack as a composed handler
59
+ *
60
+ * @param RequestInterface $request
61
+ * @param array $options
62
+ */
63
+ public function __invoke(RequestInterface $request, array $options)
64
+ {
65
+ $handler = $this->resolve();
66
+
67
+ return $handler($request, $options);
68
+ }
69
+
70
+ /**
71
+ * Dumps a string representation of the stack.
72
+ *
73
+ * @return string
74
+ */
75
+ public function __toString()
76
+ {
77
+ $depth = 0;
78
+ $stack = [];
79
+ if ($this->handler) {
80
+ $stack[] = "0) Handler: " . $this->debugCallable($this->handler);
81
+ }
82
+
83
+ $result = '';
84
+ foreach (array_reverse($this->stack) as $tuple) {
85
+ $depth++;
86
+ $str = "{$depth}) Name: '{$tuple[1]}', ";
87
+ $str .= "Function: " . $this->debugCallable($tuple[0]);
88
+ $result = "> {$str}\n{$result}";
89
+ $stack[] = $str;
90
+ }
91
+
92
+ foreach (array_keys($stack) as $k) {
93
+ $result .= "< {$stack[$k]}\n";
94
+ }
95
+
96
+ return $result;
97
+ }
98
+
99
+ /**
100
+ * Set the HTTP handler that actually returns a promise.
101
+ *
102
+ * @param callable $handler Accepts a request and array of options and
103
+ * returns a Promise.
104
+ */
105
+ public function setHandler(callable $handler)
106
+ {
107
+ $this->handler = $handler;
108
+ $this->cached = null;
109
+ }
110
+
111
+ /**
112
+ * Returns true if the builder has a handler.
113
+ *
114
+ * @return bool
115
+ */
116
+ public function hasHandler()
117
+ {
118
+ return (bool) $this->handler;
119
+ }
120
+
121
+ /**
122
+ * Unshift a middleware to the bottom of the stack.
123
+ *
124
+ * @param callable $middleware Middleware function
125
+ * @param string $name Name to register for this middleware.
126
+ */
127
+ public function unshift(callable $middleware, $name = null)
128
+ {
129
+ array_unshift($this->stack, [$middleware, $name]);
130
+ $this->cached = null;
131
+ }
132
+
133
+ /**
134
+ * Push a middleware to the top of the stack.
135
+ *
136
+ * @param callable $middleware Middleware function
137
+ * @param string $name Name to register for this middleware.
138
+ */
139
+ public function push(callable $middleware, $name = '')
140
+ {
141
+ $this->stack[] = [$middleware, $name];
142
+ $this->cached = null;
143
+ }
144
+
145
+ /**
146
+ * Add a middleware before another middleware by name.
147
+ *
148
+ * @param string $findName Middleware to find
149
+ * @param callable $middleware Middleware function
150
+ * @param string $withName Name to register for this middleware.
151
+ */
152
+ public function before($findName, callable $middleware, $withName = '')
153
+ {
154
+ $this->splice($findName, $withName, $middleware, true);
155
+ }
156
+
157
+ /**
158
+ * Add a middleware after another middleware by name.
159
+ *
160
+ * @param string $findName Middleware to find
161
+ * @param callable $middleware Middleware function
162
+ * @param string $withName Name to register for this middleware.
163
+ */
164
+ public function after($findName, callable $middleware, $withName = '')
165
+ {
166
+ $this->splice($findName, $withName, $middleware, false);
167
+ }
168
+
169
+ /**
170
+ * Remove a middleware by instance or name from the stack.
171
+ *
172
+ * @param callable|string $remove Middleware to remove by instance or name.
173
+ */
174
+ public function remove($remove)
175
+ {
176
+ $this->cached = null;
177
+ $idx = is_callable($remove) ? 0 : 1;
178
+ $this->stack = array_values(array_filter(
179
+ $this->stack,
180
+ function ($tuple) use ($idx, $remove) {
181
+ return $tuple[$idx] !== $remove;
182
+ }
183
+ ));
184
+ }
185
+
186
+ /**
187
+ * Compose the middleware and handler into a single callable function.
188
+ *
189
+ * @return callable
190
+ */
191
+ public function resolve()
192
+ {
193
+ if (!$this->cached) {
194
+ if (!($prev = $this->handler)) {
195
+ throw new \LogicException('No handler has been specified');
196
+ }
197
+
198
+ foreach (array_reverse($this->stack) as $fn) {
199
+ $prev = $fn[0]($prev);
200
+ }
201
+
202
+ $this->cached = $prev;
203
+ }
204
+
205
+ return $this->cached;
206
+ }
207
+
208
+ /**
209
+ * @param $name
210
+ * @return int
211
+ */
212
+ private function findByName($name)
213
+ {
214
+ foreach ($this->stack as $k => $v) {
215
+ if ($v[1] === $name) {
216
+ return $k;
217
+ }
218
+ }
219
+
220
+ throw new \InvalidArgumentException("Middleware not found: $name");
221
+ }
222
+
223
+ /**
224
+ * Splices a function into the middleware list at a specific position.
225
+ *
226
+ * @param $findName
227
+ * @param $withName
228
+ * @param callable $middleware
229
+ * @param $before
230
+ */
231
+ private function splice($findName, $withName, callable $middleware, $before)
232
+ {
233
+ $this->cached = null;
234
+ $idx = $this->findByName($findName);
235
+ $tuple = [$middleware, $withName];
236
+
237
+ if ($before) {
238
+ if ($idx === 0) {
239
+ array_unshift($this->stack, $tuple);
240
+ } else {
241
+ $replacement = [$tuple, $this->stack[$idx]];
242
+ array_splice($this->stack, $idx, 1, $replacement);
243
+ }
244
+ } elseif ($idx === count($this->stack) - 1) {
245
+ $this->stack[] = $tuple;
246
+ } else {
247
+ $replacement = [$this->stack[$idx], $tuple];
248
+ array_splice($this->stack, $idx, 1, $replacement);
249
+ }
250
+ }
251
+
252
+ /**
253
+ * Provides a debug string for a given callable.
254
+ *
255
+ * @param array|callable $fn Function to write as a string.
256
+ *
257
+ * @return string
258
+ */
259
+ private function debugCallable($fn)
260
+ {
261
+ if (is_string($fn)) {
262
+ return "callable({$fn})";
263
+ }
264
+
265
+ if (is_array($fn)) {
266
+ return is_string($fn[0])
267
+ ? "callable({$fn[0]}::{$fn[1]})"
268
+ : "callable(['" . get_class($fn[0]) . "', '{$fn[1]}'])";
269
+ }
270
+
271
+ return 'callable(' . spl_object_hash($fn) . ')';
272
+ }
273
+ }
vendor/guzzlehttp/guzzle/src/MessageFormatter.php CHANGED
@@ -1,180 +1,180 @@
1
- <?php
2
- namespace GuzzleHttp;
3
-
4
- use Psr\Http\Message\MessageInterface;
5
- use Psr\Http\Message\RequestInterface;
6
- use Psr\Http\Message\ResponseInterface;
7
-
8
- /**
9
- * Formats log messages using variable substitutions for requests, responses,
10
- * and other transactional data.
11
- *
12
- * The following variable substitutions are supported:
13
- *
14
- * - {request}: Full HTTP request message
15
- * - {response}: Full HTTP response message
16
- * - {ts}: ISO 8601 date in GMT
17
- * - {date_iso_8601} ISO 8601 date in GMT
18
- * - {date_common_log} Apache common log date using the configured timezone.
19
- * - {host}: Host of the request
20
- * - {method}: Method of the request
21
- * - {uri}: URI of the request
22
- * - {version}: Protocol version
23
- * - {target}: Request target of the request (path + query + fragment)
24
- * - {hostname}: Hostname of the machine that sent the request
25
- * - {code}: Status code of the response (if available)
26
- * - {phrase}: Reason phrase of the response (if available)
27
- * - {error}: Any error messages (if available)
28
- * - {req_header_*}: Replace `*` with the lowercased name of a request header to add to the message
29
- * - {res_header_*}: Replace `*` with the lowercased name of a response header to add to the message
30
- * - {req_headers}: Request headers
31
- * - {res_headers}: Response headers
32
- * - {req_body}: Request body
33
- * - {res_body}: Response body
34
- */
35
- class MessageFormatter
36
- {
37
- /**
38
- * Apache Common Log Format.
39
- * @link http://httpd.apache.org/docs/2.4/logs.html#common
40
- * @var string
41
- */
42
- const CLF = "{hostname} {req_header_User-Agent} - [{date_common_log}] \"{method} {target} HTTP/{version}\" {code} {res_header_Content-Length}";
43
- const DEBUG = ">>>>>>>>\n{request}\n<<<<<<<<\n{response}\n--------\n{error}";
44
- const SHORT = '[{ts}] "{method} {target} HTTP/{version}" {code}';
45
-
46
- /** @var string Template used to format log messages */
47
- private $template;
48
-
49
- /**
50
- * @param string $template Log message template
51
- */
52
- public function __construct($template = self::CLF)
53
- {
54
- $this->template = $template ?: self::CLF;
55
- }
56
-
57
- /**
58
- * Returns a formatted message string.
59
- *
60
- * @param RequestInterface $request Request that was sent
61
- * @param ResponseInterface $response Response that was received
62
- * @param \Exception $error Exception that was received
63
- *
64
- * @return string
65
- */
66
- public function format(
67
- RequestInterface $request,
68
- ResponseInterface $response = null,
69
- \Exception $error = null
70
- ) {
71
- $cache = [];
72
-
73
- return preg_replace_callback(
74
- '/{\s*([A-Za-z_\-\.0-9]+)\s*}/',
75
- function (array $matches) use ($request, $response, $error, &$cache) {
76
- if (isset($cache[$matches[1]])) {
77
- return $cache[$matches[1]];
78
- }
79
-
80
- $result = '';
81
- switch ($matches[1]) {
82
- case 'request':
83
- $result = Psr7\str($request);
84
- break;
85
- case 'response':
86
- $result = $response ? Psr7\str($response) : '';
87
- break;
88
- case 'req_headers':
89
- $result = trim($request->getMethod()
90
- . ' ' . $request->getRequestTarget())
91
- . ' HTTP/' . $request->getProtocolVersion() . "\r\n"
92
- . $this->headers($request);
93
- break;
94
- case 'res_headers':
95
- $result = $response ?
96
- sprintf(
97
- 'HTTP/%s %d %s',
98
- $response->getProtocolVersion(),
99
- $response->getStatusCode(),
100
- $response->getReasonPhrase()
101
- ) . "\r\n" . $this->headers($response)
102
- : 'NULL';
103
- break;
104
- case 'req_body':
105
- $result = $request->getBody();
106
- break;
107
- case 'res_body':
108
- $result = $response ? $response->getBody() : 'NULL';
109
- break;
110
- case 'ts':
111
- case 'date_iso_8601':
112
- $result = gmdate('c');
113
- break;
114
- case 'date_common_log':
115
- $result = date('d/M/Y:H:i:s O');
116
- break;
117
- case 'method':
118
- $result = $request->getMethod();
119
- break;
120
- case 'version':
121
- $result = $request->getProtocolVersion();
122
- break;
123
- case 'uri':
124
- case 'url':
125
- $result = $request->getUri();
126
- break;
127
- case 'target':
128
- $result = $request->getRequestTarget();
129
- break;
130
- case 'req_version':
131
- $result = $request->getProtocolVersion();
132
- break;
133
- case 'res_version':
134
- $result = $response
135
- ? $response->getProtocolVersion()
136
- : 'NULL';
137
- break;
138
- case 'host':
139
- $result = $request->getHeaderLine('Host');
140
- break;
141
- case 'hostname':
142
- $result = gethostname();
143
- break;
144
- case 'code':
145
- $result = $response ? $response->getStatusCode() : 'NULL';
146
- break;
147
- case 'phrase':
148
- $result = $response ? $response->getReasonPhrase() : 'NULL';
149
- break;
150
- case 'error':
151
- $result = $error ? $error->getMessage() : 'NULL';
152
- break;
153
- default:
154
- // handle prefixed dynamic headers
155
- if (strpos($matches[1], 'req_header_') === 0) {
156
- $result = $request->getHeaderLine(substr($matches[1], 11));
157
- } elseif (strpos($matches[1], 'res_header_') === 0) {
158
- $result = $response
159
- ? $response->getHeaderLine(substr($matches[1], 11))
160
- : 'NULL';
161
- }
162
- }
163
-
164
- $cache[$matches[1]] = $result;
165
- return $result;
166
- },
167
- $this->template
168
- );
169
- }
170
-
171
- private function headers(MessageInterface $message)
172
- {
173
- $result = '';
174
- foreach ($message->getHeaders() as $name => $values) {
175
- $result .= $name . ': ' . implode(', ', $values) . "\r\n";
176
- }
177
-
178
- return trim($result);
179
- }
180
- }
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ use Psr\Http\Message\MessageInterface;
5
+ use Psr\Http\Message\RequestInterface;
6
+ use Psr\Http\Message\ResponseInterface;
7
+
8
+ /**
9
+ * Formats log messages using variable substitutions for requests, responses,
10
+ * and other transactional data.
11
+ *
12
+ * The following variable substitutions are supported:
13
+ *
14
+ * - {request}: Full HTTP request message
15
+ * - {response}: Full HTTP response message
16
+ * - {ts}: ISO 8601 date in GMT
17
+ * - {date_iso_8601} ISO 8601 date in GMT
18
+ * - {date_common_log} Apache common log date using the configured timezone.
19
+ * - {host}: Host of the request
20
+ * - {method}: Method of the request
21
+ * - {uri}: URI of the request
22
+ * - {version}: Protocol version
23
+ * - {target}: Request target of the request (path + query + fragment)
24
+ * - {hostname}: Hostname of the machine that sent the request
25
+ * - {code}: Status code of the response (if available)
26
+ * - {phrase}: Reason phrase of the response (if available)
27
+ * - {error}: Any error messages (if available)
28
+ * - {req_header_*}: Replace `*` with the lowercased name of a request header to add to the message
29
+ * - {res_header_*}: Replace `*` with the lowercased name of a response header to add to the message
30
+ * - {req_headers}: Request headers
31
+ * - {res_headers}: Response headers
32
+ * - {req_body}: Request body
33
+ * - {res_body}: Response body
34
+ */
35
+ class MessageFormatter
36
+ {
37
+ /**
38
+ * Apache Common Log Format.
39
+ * @link http://httpd.apache.org/docs/2.4/logs.html#common
40
+ * @var string
41
+ */
42
+ const CLF = "{hostname} {req_header_User-Agent} - [{date_common_log}] \"{method} {target} HTTP/{version}\" {code} {res_header_Content-Length}";
43
+ const DEBUG = ">>>>>>>>\n{request}\n<<<<<<<<\n{response}\n--------\n{error}";
44
+ const SHORT = '[{ts}] "{method} {target} HTTP/{version}" {code}';
45
+
46
+ /** @var string Template used to format log messages */
47
+ private $template;
48
+
49
+ /**
50
+ * @param string $template Log message template
51
+ */
52
+ public function __construct($template = self::CLF)
53
+ {
54
+ $this->template = $template ?: self::CLF;
55
+ }
56
+
57
+ /**
58
+ * Returns a formatted message string.
59
+ *
60
+ * @param RequestInterface $request Request that was sent
61
+ * @param ResponseInterface $response Response that was received
62
+ * @param \Exception $error Exception that was received
63
+ *
64
+ * @return string
65
+ */
66
+ public function format(
67
+ RequestInterface $request,
68
+ ResponseInterface $response = null,
69
+ \Exception $error = null
70
+ ) {
71
+ $cache = [];
72
+
73
+ return preg_replace_callback(
74
+ '/{\s*([A-Za-z_\-\.0-9]+)\s*}/',
75
+ function (array $matches) use ($request, $response, $error, &$cache) {
76
+ if (isset($cache[$matches[1]])) {
77
+ return $cache[$matches[1]];
78
+ }
79
+
80
+ $result = '';
81
+ switch ($matches[1]) {
82
+ case 'request':
83
+ $result = Psr7\str($request);
84
+ break;
85
+ case 'response':
86
+ $result = $response ? Psr7\str($response) : '';
87
+ break;
88
+ case 'req_headers':
89
+ $result = trim($request->getMethod()
90
+ . ' ' . $request->getRequestTarget())
91
+ . ' HTTP/' . $request->getProtocolVersion() . "\r\n"
92
+ . $this->headers($request);
93
+ break;
94
+ case 'res_headers':
95
+ $result = $response ?
96
+ sprintf(
97
+ 'HTTP/%s %d %s',
98
+ $response->getProtocolVersion(),
99
+ $response->getStatusCode(),
100
+ $response->getReasonPhrase()
101
+ ) . "\r\n" . $this->headers($response)
102
+ : 'NULL';
103
+ break;
104
+ case 'req_body':
105
+ $result = $request->getBody();
106
+ break;
107
+ case 'res_body':
108
+ $result = $response ? $response->getBody() : 'NULL';
109
+ break;
110
+ case 'ts':
111
+ case 'date_iso_8601':
112
+ $result = gmdate('c');
113
+ break;
114
+ case 'date_common_log':
115
+ $result = date('d/M/Y:H:i:s O');
116
+ break;
117
+ case 'method':
118
+ $result = $request->getMethod();
119
+ break;
120
+ case 'version':
121
+ $result = $request->getProtocolVersion();
122
+ break;
123
+ case 'uri':
124
+ case 'url':
125
+ $result = $request->getUri();
126
+ break;
127
+ case 'target':
128
+ $result = $request->getRequestTarget();
129
+ break;
130
+ case 'req_version':
131
+ $result = $request->getProtocolVersion();
132
+ break;
133
+ case 'res_version':
134
+ $result = $response
135
+ ? $response->getProtocolVersion()
136
+ : 'NULL';
137
+ break;
138
+ case 'host':
139
+ $result = $request->getHeaderLine('Host');
140
+ break;
141
+ case 'hostname':
142
+ $result = gethostname();
143
+ break;
144
+ case 'code':
145
+ $result = $response ? $response->getStatusCode() : 'NULL';
146
+ break;
147
+ case 'phrase':
148
+ $result = $response ? $response->getReasonPhrase() : 'NULL';
149
+ break;
150
+ case 'error':
151
+ $result = $error ? $error->getMessage() : 'NULL';
152
+ break;
153
+ default:
154
+ // handle prefixed dynamic headers
155
+ if (strpos($matches[1], 'req_header_') === 0) {
156
+ $result = $request->getHeaderLine(substr($matches[1], 11));
157
+ } elseif (strpos($matches[1], 'res_header_') === 0) {
158
+ $result = $response
159
+ ? $response->getHeaderLine(substr($matches[1], 11))
160
+ : 'NULL';
161
+ }
162
+ }
163
+
164
+ $cache[$matches[1]] = $result;
165
+ return $result;
166
+ },
167
+ $this->template
168
+ );
169
+ }
170
+
171
+ private function headers(MessageInterface $message)
172
+ {
173
+ $result = '';
174
+ foreach ($message->getHeaders() as $name => $values) {
175
+ $result .= $name . ': ' . implode(', ', $values) . "\r\n";
176
+ }
177
+
178
+ return trim($result);
179
+ }
180
+ }
vendor/guzzlehttp/guzzle/src/Middleware.php CHANGED
@@ -1,255 +1,255 @@
1
- <?php
2
- namespace GuzzleHttp;
3
-
4
- use GuzzleHttp\Cookie\CookieJarInterface;
5
- use GuzzleHttp\Exception\RequestException;
6
- use GuzzleHttp\Promise\RejectedPromise;
7
- use GuzzleHttp\Psr7;
8
- use Psr\Http\Message\ResponseInterface;
9
- use Psr\Log\LoggerInterface;
10
- use Psr\Log\LogLevel;
11
-
12
- /**
13
- * Functions used to create and wrap handlers with handler middleware.
14
- */
15
- final class Middleware
16
- {
17
- /**
18
- * Middleware that adds cookies to requests.
19
- *
20
- * The options array must be set to a CookieJarInterface in order to use
21
- * cookies. This is typically handled for you by a client.
22
- *
23
- * @return callable Returns a function that accepts the next handler.
24
- */
25
- public static function cookies()
26
- {
27
- return function (callable $handler) {
28
- return function ($request, array $options) use ($handler) {
29
- if (empty($options['cookies'])) {
30
- return $handler($request, $options);
31
- } elseif (!($options['cookies'] instanceof CookieJarInterface)) {
32
- throw new \InvalidArgumentException('cookies must be an instance of GuzzleHttp\Cookie\CookieJarInterface');
33
- }
34
- $cookieJar = $options['cookies'];
35
- $request = $cookieJar->withCookieHeader($request);
36
- return $handler($request, $options)
37
- ->then(
38
- function ($response) use ($cookieJar, $request) {
39
- $cookieJar->extractCookies($request, $response);
40
- return $response;
41
- }
42
- );
43
- };
44
- };
45
- }
46
-
47
- /**
48
- * Middleware that throws exceptions for 4xx or 5xx responses when the
49
- * "http_error" request option is set to true.
50
- *
51
- * @return callable Returns a function that accepts the next handler.
52
- */
53
- public static function httpErrors()
54
- {
55
- return function (callable $handler) {
56
- return function ($request, array $options) use ($handler) {
57
- if (empty($options['http_errors'])) {
58
- return $handler($request, $options);
59
- }
60
- return $handler($request, $options)->then(
61
- function (ResponseInterface $response) use ($request, $handler) {
62
- $code = $response->getStatusCode();
63
- if ($code < 400) {
64
- return $response;
65
- }
66
- throw RequestException::create($request, $response);
67
- }
68
- );
69
- };
70
- };
71
- }
72
-
73
- /**
74
- * Middleware that pushes history data to an ArrayAccess container.
75
- *
76
- * @param array|\ArrayAccess $container Container to hold the history (by reference).
77
- *
78
- * @return callable Returns a function that accepts the next handler.
79
- * @throws \InvalidArgumentException if container is not an array or ArrayAccess.
80
- */
81
- public static function history(&$container)
82
- {
83
- if (!is_array($container) && !$container instanceof \ArrayAccess) {
84
- throw new \InvalidArgumentException('history container must be an array or object implementing ArrayAccess');
85
- }
86
-
87
- return function (callable $handler) use (&$container) {
88
- return function ($request, array $options) use ($handler, &$container) {
89
- return $handler($request, $options)->then(
90
- function ($value) use ($request, &$container, $options) {
91
- $container[] = [
92
- 'request' => $request,
93
- 'response' => $value,
94
- 'error' => null,
95
- 'options' => $options
96
- ];
97
- return $value;
98
- },
99
- function ($reason) use ($request, &$container, $options) {
100
- $container[] = [
101
- 'request' => $request,
102
- 'response' => null,
103
- 'error' => $reason,
104
- 'options' => $options
105
- ];
106
- return \GuzzleHttp\Promise\rejection_for($reason);
107
- }
108
- );
109
- };
110
- };
111
- }
112
-
113
- /**
114
- * Middleware that invokes a callback before and after sending a request.
115
- *
116
- * The provided listener cannot modify or alter the response. It simply
117
- * "taps" into the chain to be notified before returning the promise. The
118
- * before listener accepts a request and options array, and the after
119
- * listener accepts a request, options array, and response promise.
120
- *
121
- * @param callable $before Function to invoke before forwarding the request.
122
- * @param callable $after Function invoked after forwarding.
123
- *
124
- * @return callable Returns a function that accepts the next handler.
125
- */
126
- public static function tap(callable $before = null, callable $after = null)
127
- {
128
- return function (callable $handler) use ($before, $after) {
129
- return function ($request, array $options) use ($handler, $before, $after) {
130
- if ($before) {
131
- $before($request, $options);
132
- }
133
- $response = $handler($request, $options);
134
- if ($after) {
135
- $after($request, $options, $response);
136
- }
137
- return $response;
138
- };
139
- };
140
- }
141
-
142
- /**
143
- * Middleware that handles request redirects.
144
- *
145
- * @return callable Returns a function that accepts the next handler.
146
- */
147
- public static function redirect()
148
- {
149
- return function (callable $handler) {
150
- return new RedirectMiddleware($handler);
151
- };
152
- }
153
-
154
- /**
155
- * Middleware that retries requests based on the boolean result of
156
- * invoking the provided "decider" function.
157
- *
158
- * If no delay function is provided, a simple implementation of exponential
159
- * backoff will be utilized.
160
- *
161
- * @param callable $decider Function that accepts the number of retries,
162
- * a request, [response], and [exception] and
163
- * returns true if the request is to be retried.
164
- * @param callable $delay Function that accepts the number of retries and
165
- * returns the number of milliseconds to delay.
166
- *
167
- * @return callable Returns a function that accepts the next handler.
168
- */
169
- public static function retry(callable $decider, callable $delay = null)
170
- {
171
- return function (callable $handler) use ($decider, $delay) {
172
- return new RetryMiddleware($decider, $handler, $delay);
173
- };
174
- }
175
-
176
- /**
177
- * Middleware that logs requests, responses, and errors using a message
178
- * formatter.
179
- *
180
- * @param LoggerInterface $logger Logs messages.
181
- * @param MessageFormatter $formatter Formatter used to create message strings.
182
- * @param string $logLevel Level at which to log requests.
183
- *
184
- * @return callable Returns a function that accepts the next handler.
185
- */
186
- public static function log(LoggerInterface $logger, MessageFormatter $formatter, $logLevel = LogLevel::INFO)
187
- {
188
- return function (callable $handler) use ($logger, $formatter, $logLevel) {
189
- return function ($request, array $options) use ($handler, $logger, $formatter, $logLevel) {
190
- return $handler($request, $options)->then(
191
- function ($response) use ($logger, $request, $formatter, $logLevel) {
192
- $message = $formatter->format($request, $response);
193
- $logger->log($logLevel, $message);
194
- return $response;
195
- },
196
- function ($reason) use ($logger, $request, $formatter) {
197
- $response = $reason instanceof RequestException
198
- ? $reason->getResponse()
199
- : null;
200
- $message = $formatter->format($request, $response, $reason);
201
- $logger->notice($message);
202
- return \GuzzleHttp\Promise\rejection_for($reason);
203
- }
204
- );
205
- };
206
- };
207
- }
208
-
209
- /**
210
- * This middleware adds a default content-type if possible, a default
211
- * content-length or transfer-encoding header, and the expect header.
212
- *
213
- * @return callable
214
- */
215
- public static function prepareBody()
216
- {
217
- return function (callable $handler) {
218
- return new PrepareBodyMiddleware($handler);
219
- };
220
- }
221
-
222
- /**
223
- * Middleware that applies a map function to the request before passing to
224
- * the next handler.
225
- *
226
- * @param callable $fn Function that accepts a RequestInterface and returns
227
- * a RequestInterface.
228
- * @return callable
229
- */
230
- public static function mapRequest(callable $fn)
231
- {
232
- return function (callable $handler) use ($fn) {
233
- return function ($request, array $options) use ($handler, $fn) {
234
- return $handler($fn($request), $options);
235
- };
236
- };
237
- }
238
-
239
- /**
240
- * Middleware that applies a map function to the resolved promise's
241
- * response.
242
- *
243
- * @param callable $fn Function that accepts a ResponseInterface and
244
- * returns a ResponseInterface.
245
- * @return callable
246
- */
247
- public static function mapResponse(callable $fn)
248
- {
249
- return function (callable $handler) use ($fn) {
250
- return function ($request, array $options) use ($handler, $fn) {
251
- return $handler($request, $options)->then($fn);
252
- };
253
- };
254
- }
255
- }
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ use GuzzleHttp\Cookie\CookieJarInterface;
5
+ use GuzzleHttp\Exception\RequestException;
6
+ use GuzzleHttp\Promise\RejectedPromise;
7
+ use GuzzleHttp\Psr7;
8
+ use Psr\Http\Message\ResponseInterface;
9
+ use Psr\Log\LoggerInterface;
10
+ use Psr\Log\LogLevel;
11
+
12
+ /**
13
+ * Functions used to create and wrap handlers with handler middleware.
14
+ */
15
+ final class Middleware
16
+ {
17
+ /**
18
+ * Middleware that adds cookies to requests.
19
+ *
20
+ * The options array must be set to a CookieJarInterface in order to use
21
+ * cookies. This is typically handled for you by a client.
22
+ *
23
+ * @return callable Returns a function that accepts the next handler.
24
+ */
25
+ public static function cookies()
26
+ {
27
+ return function (callable $handler) {
28
+ return function ($request, array $options) use ($handler) {
29
+ if (empty($options['cookies'])) {
30
+ return $handler($request, $options);
31
+ } elseif (!($options['cookies'] instanceof CookieJarInterface)) {
32
+ throw new \InvalidArgumentException('cookies must be an instance of GuzzleHttp\Cookie\CookieJarInterface');
33
+ }
34
+ $cookieJar = $options['cookies'];
35
+ $request = $cookieJar->withCookieHeader($request);
36
+ return $handler($request, $options)
37
+ ->then(
38
+ function ($response) use ($cookieJar, $request) {
39
+ $cookieJar->extractCookies($request, $response);
40
+ return $response;
41
+ }
42
+ );
43
+ };
44
+ };
45
+ }
46
+
47
+ /**
48
+ * Middleware that throws exceptions for 4xx or 5xx responses when the
49
+ * "http_error" request option is set to true.
50
+ *
51
+ * @return callable Returns a function that accepts the next handler.
52
+ */
53
+ public static function httpErrors()
54
+ {
55
+ return function (callable $handler) {
56
+ return function ($request, array $options) use ($handler) {
57
+ if (empty($options['http_errors'])) {
58
+ return $handler($request, $options);
59
+ }
60
+ return $handler($request, $options)->then(
61
+ function (ResponseInterface $response) use ($request, $handler) {
62
+ $code = $response->getStatusCode();
63
+ if ($code < 400) {
64
+ return $response;
65
+ }
66
+ throw RequestException::create($request, $response);
67
+ }
68
+ );
69
+ };
70
+ };
71
+ }
72
+
73
+ /**
74
+ * Middleware that pushes history data to an ArrayAccess container.
75
+ *
76
+ * @param array|\ArrayAccess $container Container to hold the history (by reference).
77
+ *
78
+ * @return callable Returns a function that accepts the next handler.
79
+ * @throws \InvalidArgumentException if container is not an array or ArrayAccess.
80
+ */
81
+ public static function history(&$container)
82
+ {
83
+ if (!is_array($container) && !$container instanceof \ArrayAccess) {
84
+ throw new \InvalidArgumentException('history container must be an array or object implementing ArrayAccess');
85
+ }
86
+
87
+ return function (callable $handler) use (&$container) {
88
+ return function ($request, array $options) use ($handler, &$container) {
89
+ return $handler($request, $options)->then(
90
+ function ($value) use ($request, &$container, $options) {
91
+ $container[] = [
92
+ 'request' => $request,
93
+ 'response' => $value,
94
+ 'error' => null,
95
+ 'options' => $options
96
+ ];
97
+ return $value;
98
+ },
99
+ function ($reason) use ($request, &$container, $options) {
100
+ $container[] = [
101
+ 'request' => $request,
102
+ 'response' => null,
103
+ 'error' => $reason,
104
+ 'options' => $options
105
+ ];
106
+ return \GuzzleHttp\Promise\rejection_for($reason);
107
+ }
108
+ );
109
+ };
110
+ };
111
+ }
112
+
113
+ /**
114
+ * Middleware that invokes a callback before and after sending a request.
115
+ *
116
+ * The provided listener cannot modify or alter the response. It simply
117
+ * "taps" into the chain to be notified before returning the promise. The
118
+ * before listener accepts a request and options array, and the after
119
+ * listener accepts a request, options array, and response promise.
120
+ *
121
+ * @param callable $before Function to invoke before forwarding the request.
122
+ * @param callable $after Function invoked after forwarding.
123
+ *
124
+ * @return callable Returns a function that accepts the next handler.
125
+ */
126
+ public static function tap(callable $before = null, callable $after = null)
127
+ {
128
+ return function (callable $handler) use ($before, $after) {
129
+ return function ($request, array $options) use ($handler, $before, $after) {
130
+ if ($before) {
131
+ $before($request, $options);
132
+ }
133
+ $response = $handler($request, $options);
134
+ if ($after) {
135
+ $after($request, $options, $response);
136
+ }
137
+ return $response;
138
+ };
139
+ };
140
+ }
141
+
142
+ /**
143
+ * Middleware that handles request redirects.
144
+ *
145
+ * @return callable Returns a function that accepts the next handler.
146
+ */
147
+ public static function redirect()
148
+ {
149
+ return function (callable $handler) {
150
+ return new RedirectMiddleware($handler);
151
+ };
152
+ }
153
+
154
+ /**
155
+ * Middleware that retries requests based on the boolean result of
156
+ * invoking the provided "decider" function.
157
+ *
158
+ * If no delay function is provided, a simple implementation of exponential
159
+ * backoff will be utilized.
160
+ *
161
+ * @param callable $decider Function that accepts the number of retries,
162
+ * a request, [response], and [exception] and
163
+ * returns true if the request is to be retried.
164
+ * @param callable $delay Function that accepts the number of retries and
165
+ * returns the number of milliseconds to delay.
166
+ *
167
+ * @return callable Returns a function that accepts the next handler.
168
+ */
169
+ public static function retry(callable $decider, callable $delay = null)
170
+ {
171
+ return function (callable $handler) use ($decider, $delay) {
172
+ return new RetryMiddleware($decider, $handler, $delay);
173
+ };
174
+ }
175
+
176
+ /**
177
+ * Middleware that logs requests, responses, and errors using a message
178
+ * formatter.
179
+ *
180
+ * @param LoggerInterface $logger Logs messages.
181
+ * @param MessageFormatter $formatter Formatter used to create message strings.
182
+ * @param string $logLevel Level at which to log requests.
183
+ *
184
+ * @return callable Returns a function that accepts the next handler.
185
+ */
186
+ public static function log(LoggerInterface $logger, MessageFormatter $formatter, $logLevel = LogLevel::INFO)
187
+ {
188
+ return function (callable $handler) use ($logger, $formatter, $logLevel) {
189
+ return function ($request, array $options) use ($handler, $logger, $formatter, $logLevel) {
190
+ return $handler($request, $options)->then(
191
+ function ($response) use ($logger, $request, $formatter, $logLevel) {
192
+ $message = $formatter->format($request, $response);
193
+ $logger->log($logLevel, $message);
194
+ return $response;
195
+ },
196
+ function ($reason) use ($logger, $request, $formatter) {
197
+ $response = $reason instanceof RequestException
198
+ ? $reason->getResponse()
199
+ : null;
200
+ $message = $formatter->format($request, $response, $reason);
201
+ $logger->notice($message);
202
+ return \GuzzleHttp\Promise\rejection_for($reason);
203
+ }
204
+ );
205
+ };
206
+ };
207
+ }
208
+
209
+ /**
210
+ * This middleware adds a default content-type if possible, a default
211
+ * content-length or transfer-encoding header, and the expect header.
212
+ *
213
+ * @return callable
214
+ */
215
+ public static function prepareBody()
216
+ {
217
+ return function (callable $handler) {
218
+ return new PrepareBodyMiddleware($handler);
219
+ };
220
+ }
221
+
222
+ /**
223
+ * Middleware that applies a map function to the request before passing to
224
+ * the next handler.
225
+ *
226
+ * @param callable $fn Function that accepts a RequestInterface and returns
227
+ * a RequestInterface.
228
+ * @return callable
229
+ */
230
+ public static function mapRequest(callable $fn)
231
+ {
232
+ return function (callable $handler) use ($fn) {
233
+ return function ($request, array $options) use ($handler, $fn) {
234
+ return $handler($fn($request), $options);
235
+ };
236
+ };
237
+ }
238
+
239
+ /**
240
+ * Middleware that applies a map function to the resolved promise's
241
+ * response.
242
+ *
243
+ * @param callable $fn Function that accepts a ResponseInterface and
244
+ * returns a ResponseInterface.
245
+ * @return callable
246
+ */
247
+ public static function mapResponse(callable $fn)
248
+ {
249
+ return function (callable $handler) use ($fn) {
250
+ return function ($request, array $options) use ($handler, $fn) {
251
+ return $handler($request, $options)->then($fn);
252
+ };
253
+ };
254
+ }
255
+ }
vendor/guzzlehttp/guzzle/src/Pool.php CHANGED
@@ -1,123 +1,123 @@
1
- <?php
2
- namespace GuzzleHttp;
3
-
4
- use GuzzleHttp\Promise\PromisorInterface;
5
- use Psr\Http\Message\RequestInterface;
6
- use GuzzleHttp\Promise\EachPromise;
7
-
8
- /**
9
- * Sends and iterator of requests concurrently using a capped pool size.
10
- *
11
- * The pool will read from an iterator until it is cancelled or until the
12
- * iterator is consumed. When a request is yielded, the request is sent after
13
- * applying the "request_options" request options (if provided in the ctor).
14
- *
15
- * When a function is yielded by the iterator, the function is provided the
16
- * "request_options" array that should be merged on top of any existing
17
- * options, and the function MUST then return a wait-able promise.
18
- */
19
- class Pool implements PromisorInterface
20
- {
21
- /** @var EachPromise */
22
- private $each;
23
-
24
- /**
25
- * @param ClientInterface $client Client used to send the requests.
26
- * @param array|\Iterator $requests Requests or functions that return
27
- * requests to send concurrently.
28
- * @param array $config Associative array of options
29
- * - concurrency: (int) Maximum number of requests to send concurrently
30
- * - options: Array of request options to apply to each request.
31
- * - fulfilled: (callable) Function to invoke when a request completes.
32
- * - rejected: (callable) Function to invoke when a request is rejected.
33
- */
34
- public function __construct(
35
- ClientInterface $client,
36
- $requests,
37
- array $config = []
38
- ) {
39
- // Backwards compatibility.
40
- if (isset($config['pool_size'])) {
41
- $config['concurrency'] = $config['pool_size'];
42
- } elseif (!isset($config['concurrency'])) {
43
- $config['concurrency'] = 25;
44
- }
45
-
46
- if (isset($config['options'])) {
47
- $opts = $config['options'];
48
- unset($config['options']);
49
- } else {
50
- $opts = [];
51
- }
52
-
53
- $iterable = \GuzzleHttp\Promise\iter_for($requests);
54
- $requests = function () use ($iterable, $client, $opts) {
55
- foreach ($iterable as $key => $rfn) {
56
- if ($rfn instanceof RequestInterface) {
57
- yield $key => $client->sendAsync($rfn, $opts);
58
- } elseif (is_callable($rfn)) {
59
- yield $key => $rfn($opts);
60
- } else {
61
- throw new \InvalidArgumentException('Each value yielded by '
62
- . 'the iterator must be a Psr7\Http\Message\RequestInterface '
63
- . 'or a callable that returns a promise that fulfills '
64
- . 'with a Psr7\Message\Http\ResponseInterface object.');
65
- }
66
- }
67
- };
68
-
69
- $this->each = new EachPromise($requests(), $config);
70
- }
71
-
72
- public function promise()
73
- {
74
- return $this->each->promise();
75
- }
76
-
77
- /**
78
- * Sends multiple requests concurrently and returns an array of responses
79
- * and exceptions that uses the same ordering as the provided requests.
80
- *
81
- * IMPORTANT: This method keeps every request and response in memory, and
82
- * as such, is NOT recommended when sending a large number or an
83
- * indeterminate number of requests concurrently.
84
- *
85
- * @param ClientInterface $client Client used to send the requests
86
- * @param array|\Iterator $requests Requests to send concurrently.
87
- * @param array $options Passes through the options available in
88
- * {@see GuzzleHttp\Pool::__construct}
89
- *
90
- * @return array Returns an array containing the response or an exception
91
- * in the same order that the requests were sent.
92
- * @throws \InvalidArgumentException if the event format is incorrect.
93
- */
94
- public static function batch(
95
- ClientInterface $client,
96
- $requests,
97
- array $options = []
98
- ) {
99
- $res = [];
100
- self::cmpCallback($options, 'fulfilled', $res);
101
- self::cmpCallback($options, 'rejected', $res);
102
- $pool = new static($client, $requests, $options);
103
- $pool->promise()->wait();
104
- ksort($res);
105
-
106
- return $res;
107
- }
108
-
109
- private static function cmpCallback(array &$options, $name, array &$results)
110
- {
111
- if (!isset($options[$name])) {
112
- $options[$name] = function ($v, $k) use (&$results) {
113
- $results[$k] = $v;
114
- };
115
- } else {
116
- $currentFn = $options[$name];
117
- $options[$name] = function ($v, $k) use (&$results, $currentFn) {
118
- $currentFn($v, $k);
119
- $results[$k] = $v;
120
- };
121
- }
122
- }
123
- }
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ use GuzzleHttp\Promise\PromisorInterface;
5
+ use Psr\Http\Message\RequestInterface;
6
+ use GuzzleHttp\Promise\EachPromise;
7
+
8
+ /**
9
+ * Sends and iterator of requests concurrently using a capped pool size.
10
+ *
11
+ * The pool will read from an iterator until it is cancelled or until the
12
+ * iterator is consumed. When a request is yielded, the request is sent after
13
+ * applying the "request_options" request options (if provided in the ctor).
14
+ *
15
+ * When a function is yielded by the iterator, the function is provided the
16
+ * "request_options" array that should be merged on top of any existing
17
+ * options, and the function MUST then return a wait-able promise.
18
+ */
19
+ class Pool implements PromisorInterface
20
+ {
21
+ /** @var EachPromise */
22
+ private $each;
23
+
24
+ /**
25
+ * @param ClientInterface $client Client used to send the requests.
26
+ * @param array|\Iterator $requests Requests or functions that return
27
+ * requests to send concurrently.
28
+ * @param array $config Associative array of options
29
+ * - concurrency: (int) Maximum number of requests to send concurrently
30
+ * - options: Array of request options to apply to each request.
31
+ * - fulfilled: (callable) Function to invoke when a request completes.
32
+ * - rejected: (callable) Function to invoke when a request is rejected.
33
+ */
34
+ public function __construct(
35
+ ClientInterface $client,
36
+ $requests,
37
+ array $config = []
38
+ ) {
39
+ // Backwards compatibility.
40
+ if (isset($config['pool_size'])) {
41
+ $config['concurrency'] = $config['pool_size'];
42
+ } elseif (!isset($config['concurrency'])) {
43
+ $config['concurrency'] = 25;
44
+ }
45
+
46
+ if (isset($config['options'])) {
47
+ $opts = $config['options'];
48
+ unset($config['options']);
49
+ } else {
50
+ $opts = [];
51
+ }
52
+
53
+ $iterable = \GuzzleHttp\Promise\iter_for($requests);
54
+ $requests = function () use ($iterable, $client, $opts) {
55
+ foreach ($iterable as $key => $rfn) {
56
+ if ($rfn instanceof RequestInterface) {
57
+ yield $key => $client->sendAsync($rfn, $opts);
58
+ } elseif (is_callable($rfn)) {
59
+ yield $key => $rfn($opts);
60
+ } else {
61
+ throw new \InvalidArgumentException('Each value yielded by '
62
+ . 'the iterator must be a Psr7\Http\Message\RequestInterface '
63
+ . 'or a callable that returns a promise that fulfills '
64
+ . 'with a Psr7\Message\Http\ResponseInterface object.');
65
+ }
66
+ }
67
+ };
68
+
69
+ $this->each = new EachPromise($requests(), $config);
70
+ }
71
+
72
+ public function promise()
73
+ {
74
+ return $this->each->promise();
75
+ }
76
+
77
+ /**
78
+ * Sends multiple requests concurrently and returns an array of responses
79
+ * and exceptions that uses the same ordering as the provided requests.
80
+ *
81
+ * IMPORTANT: This method keeps every request and response in memory, and
82
+ * as such, is NOT recommended when sending a large number or an
83
+ * indeterminate number of requests concurrently.
84
+ *
85
+ * @param ClientInterface $client Client used to send the requests
86
+ * @param array|\Iterator $requests Requests to send concurrently.
87
+ * @param array $options Passes through the options available in
88
+ * {@see GuzzleHttp\Pool::__construct}
89
+ *
90
+ * @return array Returns an array containing the response or an exception
91
+ * in the same order that the requests were sent.
92
+ * @throws \InvalidArgumentException if the event format is incorrect.
93
+ */
94
+ public static function batch(
95
+ ClientInterface $client,
96
+ $requests,
97
+ array $options = []
98
+ ) {
99
+ $res = [];
100
+ self::cmpCallback($options, 'fulfilled', $res);
101
+ self::cmpCallback($options, 'rejected', $res);
102
+ $pool = new static($client, $requests, $options);
103
+ $pool->promise()->wait();
104
+ ksort($res);
105
+
106
+ return $res;
107
+ }
108
+
109
+ private static function cmpCallback(array &$options, $name, array &$results)
110
+ {
111
+ if (!isset($options[$name])) {
112
+ $options[$name] = function ($v, $k) use (&$results) {
113
+ $results[$k] = $v;
114
+ };
115
+ } else {
116
+ $currentFn = $options[$name];
117
+ $options[$name] = function ($v, $k) use (&$results, $currentFn) {
118
+ $currentFn($v, $k);
119
+ $results[$k] = $v;
120
+ };
121
+ }
122
+ }
123
+ }
vendor/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php CHANGED
@@ -1,106 +1,106 @@
1
- <?php
2
- namespace GuzzleHttp;
3
-
4
- use GuzzleHttp\Promise\PromiseInterface;
5
- use GuzzleHttp\Psr7;
6
- use Psr\Http\Message\RequestInterface;
7
-
8
- /**
9
- * Prepares requests that contain a body, adding the Content-Length,
10
- * Content-Type, and Expect headers.
11
- */
12
- class PrepareBodyMiddleware
13
- {
14
- /** @var callable */
15
- private $nextHandler;
16
-
17
- /**
18
- * @param callable $nextHandler Next handler to invoke.
19
- */
20
- public function __construct(callable $nextHandler)
21
- {
22
- $this->nextHandler = $nextHandler;
23
- }
24
-
25
- /**
26
- * @param RequestInterface $request
27
- * @param array $options
28
- *
29
- * @return PromiseInterface
30
- */
31
- public function __invoke(RequestInterface $request, array $options)
32
- {
33
- $fn = $this->nextHandler;
34
-
35
- // Don't do anything if the request has no body.
36
- if ($request->getBody()->getSize() === 0) {
37
- return $fn($request, $options);
38
- }
39
-
40
- $modify = [];
41
-
42
- // Add a default content-type if possible.
43
- if (!$request->hasHeader('Content-Type')) {
44
- if ($uri = $request->getBody()->getMetadata('uri')) {
45
- if ($type = Psr7\mimetype_from_filename($uri)) {
46
- $modify['set_headers']['Content-Type'] = $type;
47
- }
48
- }
49
- }
50
-
51
- // Add a default content-length or transfer-encoding header.
52
- if (!$request->hasHeader('Content-Length')
53
- && !$request->hasHeader('Transfer-Encoding')
54
- ) {
55
- $size = $request->getBody()->getSize();
56
- if ($size !== null) {
57
- $modify['set_headers']['Content-Length'] = $size;
58
- } else {
59
- $modify['set_headers']['Transfer-Encoding'] = 'chunked';
60
- }
61
- }
62
-
63
- // Add the expect header if needed.
64
- $this->addExpectHeader($request, $options, $modify);
65
-
66
- return $fn(Psr7\modify_request($request, $modify), $options);
67
- }
68
-
69
- private function addExpectHeader(
70
- RequestInterface $request,
71
- array $options,
72
- array &$modify
73
- ) {
74
- // Determine if the Expect header should be used
75
- if ($request->hasHeader('Expect')) {
76
- return;
77
- }
78
-
79
- $expect = isset($options['expect']) ? $options['expect'] : null;
80
-
81
- // Return if disabled or if you're not using HTTP/1.1 or HTTP/2.0
82
- if ($expect === false || $request->getProtocolVersion() < 1.1) {
83
- return;
84
- }
85
-
86
- // The expect header is unconditionally enabled
87
- if ($expect === true) {
88
- $modify['set_headers']['Expect'] = '100-Continue';
89
- return;
90
- }
91
-
92
- // By default, send the expect header when the payload is > 1mb
93
- if ($expect === null) {
94
- $expect = 1048576;
95
- }
96
-
97
- // Always add if the body cannot be rewound, the size cannot be
98
- // determined, or the size is greater than the cutoff threshold
99
- $body = $request->getBody();
100
- $size = $body->getSize();
101
-
102
- if ($size === null || $size >= (int) $expect || !$body->isSeekable()) {
103
- $modify['set_headers']['Expect'] = '100-Continue';
104
- }
105
- }
106
- }
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ use GuzzleHttp\Promise\PromiseInterface;
5
+ use GuzzleHttp\Psr7;
6
+ use Psr\Http\Message\RequestInterface;
7
+
8
+ /**
9
+ * Prepares requests that contain a body, adding the Content-Length,
10
+ * Content-Type, and Expect headers.
11
+ */
12
+ class PrepareBodyMiddleware
13
+ {
14
+ /** @var callable */
15
+ private $nextHandler;
16
+
17
+ /**
18
+ * @param callable $nextHandler Next handler to invoke.
19
+ */
20
+ public function __construct(callable $nextHandler)
21
+ {
22
+ $this->nextHandler = $nextHandler;
23
+ }
24
+
25
+ /**
26
+ * @param RequestInterface $request
27
+ * @param array $options
28
+ *
29
+ * @return PromiseInterface
30
+ */
31
+ public function __invoke(RequestInterface $request, array $options)
32
+ {
33
+ $fn = $this->nextHandler;
34
+
35
+ // Don't do anything if the request has no body.
36
+ if ($request->getBody()->getSize() === 0) {
37
+ return $fn($request, $options);
38
+ }
39
+
40
+ $modify = [];
41
+
42
+ // Add a default content-type if possible.
43
+ if (!$request->hasHeader('Content-Type')) {
44
+ if ($uri = $request->getBody()->getMetadata('uri')) {
45
+ if ($type = Psr7\mimetype_from_filename($uri)) {
46
+ $modify['set_headers']['Content-Type'] = $type;
47
+ }
48
+ }
49
+ }
50
+
51
+ // Add a default content-length or transfer-encoding header.
52
+ if (!$request->hasHeader('Content-Length')
53
+ && !$request->hasHeader('Transfer-Encoding')
54
+ ) {
55
+ $size = $request->getBody()->getSize();
56
+ if ($size !== null) {
57
+ $modify['set_headers']['Content-Length'] = $size;
58
+ } else {
59
+ $modify['set_headers']['Transfer-Encoding'] = 'chunked';
60
+ }
61
+ }
62
+
63
+ // Add the expect header if needed.
64
+ $this->addExpectHeader($request, $options, $modify);
65
+
66
+ return $fn(Psr7\modify_request($request, $modify), $options);
67
+ }
68
+
69
+ private function addExpectHeader(
70
+ RequestInterface $request,
71
+ array $options,
72
+ array &$modify
73
+ ) {
74
+ // Determine if the Expect header should be used
75
+ if ($request->hasHeader('Expect')) {
76
+ return;
77
+ }
78
+
79
+ $expect = isset($options['expect']) ? $options['expect'] : null;
80
+
81
+ // Return if disabled or if you're not using HTTP/1.1 or HTTP/2.0
82
+ if ($expect === false || $request->getProtocolVersion() < 1.1) {
83
+ return;
84
+ }
85
+
86
+ // The expect header is unconditionally enabled
87
+ if ($expect === true) {
88
+ $modify['set_headers']['Expect'] = '100-Continue';
89
+ return;
90
+ }
91
+
92
+ // By default, send the expect header when the payload is > 1mb
93
+ if ($expect === null) {
94
+ $expect = 1048576;
95
+ }
96
+
97
+ // Always add if the body cannot be rewound, the size cannot be
98
+ // determined, or the size is greater than the cutoff threshold
99
+ $body = $request->getBody();
100
+ $size = $body->getSize();
101
+
102
+ if ($size === null || $size >= (int) $expect || !$body->isSeekable()) {
103
+ $modify['set_headers']['Expect'] = '100-Continue';
104
+ }
105
+ }
106
+ }
vendor/guzzlehttp/guzzle/src/RedirectMiddleware.php CHANGED
@@ -1,237 +1,237 @@
1
- <?php
2
- namespace GuzzleHttp;
3
-
4
- use GuzzleHttp\Exception\BadResponseException;
5
- use GuzzleHttp\Exception\TooManyRedirectsException;
6
- use GuzzleHttp\Promise\PromiseInterface;
7
- use GuzzleHttp\Psr7;
8
- use Psr\Http\Message\RequestInterface;
9
- use Psr\Http\Message\ResponseInterface;
10
- use Psr\Http\Message\UriInterface;
11
-
12
- /**
13
- * Request redirect middleware.
14
- *
15
- * Apply this middleware like other middleware using
16
- * {@see GuzzleHttp\Middleware::redirect()}.
17
- */
18
- class RedirectMiddleware
19
- {
20
- const HISTORY_HEADER = 'X-Guzzle-Redirect-History';
21
-
22
- const STATUS_HISTORY_HEADER = 'X-Guzzle-Redirect-Status-History';
23
-
24
- public static $defaultSettings = [
25
- 'max' => 5,
26
- 'protocols' => ['http', 'https'],
27
- 'strict' => false,
28
- 'referer' => false,
29
- 'track_redirects' => false,
30
- ];
31
-
32
- /** @var callable */
33
- private $nextHandler;
34
-
35
- /**
36
- * @param callable $nextHandler Next handler to invoke.
37
- */
38
- public function __construct(callable $nextHandler)
39
- {
40
- $this->nextHandler = $nextHandler;
41
- }
42
-
43
- /**
44
- * @param RequestInterface $request
45
- * @param array $options
46
- *
47
- * @return PromiseInterface
48
- */
49
- public function __invoke(RequestInterface $request, array $options)
50
- {
51
- $fn = $this->nextHandler;
52
-
53
- if (empty($options['allow_redirects'])) {
54
- return $fn($request, $options);
55
- }
56
-
57
- if ($options['allow_redirects'] === true) {
58
- $options['allow_redirects'] = self::$defaultSettings;
59
- } elseif (!is_array($options['allow_redirects'])) {
60
- throw new \InvalidArgumentException('allow_redirects must be true, false, or array');
61
- } else {
62
- // Merge the default settings with the provided settings
63
- $options['allow_redirects'] += self::$defaultSettings;
64
- }
65
-
66
- if (empty($options['allow_redirects']['max'])) {
67
- return $fn($request, $options);
68
- }
69
-
70
- return $fn($request, $options)
71
- ->then(function (ResponseInterface $response) use ($request, $options) {
72
- return $this->checkRedirect($request, $options, $response);
73
- });
74
- }
75
-
76
- /**
77
- * @param RequestInterface $request
78
- * @param array $options
79
- * @param ResponseInterface|PromiseInterface $response
80
- *
81
- * @return ResponseInterface|PromiseInterface
82
- */
83
- public function checkRedirect(
84
- RequestInterface $request,
85
- array $options,
86
- ResponseInterface $response
87
- ) {
88
- if (substr($response->getStatusCode(), 0, 1) != '3'
89
- || !$response->hasHeader('Location')
90
- ) {
91
- return $response;
92
- }
93
-
94
- $this->guardMax($request, $options);
95
- $nextRequest = $this->modifyRequest($request, $options, $response);
96
-
97
- if (isset($options['allow_redirects']['on_redirect'])) {
98
- call_user_func(
99
- $options['allow_redirects']['on_redirect'],
100
- $request,
101
- $response,
102
- $nextRequest->getUri()
103
- );
104
- }
105
-
106
- /** @var PromiseInterface|ResponseInterface $promise */
107
- $promise = $this($nextRequest, $options);
108
-
109
- // Add headers to be able to track history of redirects.
110
- if (!empty($options['allow_redirects']['track_redirects'])) {
111
- return $this->withTracking(
112
- $promise,
113
- (string) $nextRequest->getUri(),
114
- $response->getStatusCode()
115
- );
116
- }
117
-
118
- return $promise;
119
- }
120
-
121
- private function withTracking(PromiseInterface $promise, $uri, $statusCode)
122
- {
123
- return $promise->then(
124
- function (ResponseInterface $response) use ($uri, $statusCode) {
125
- // Note that we are pushing to the front of the list as this
126
- // would be an earlier response than what is currently present
127
- // in the history header.
128
- $historyHeader = $response->getHeader(self::HISTORY_HEADER);
129
- $statusHeader = $response->getHeader(self::STATUS_HISTORY_HEADER);
130
- array_unshift($historyHeader, $uri);
131
- array_unshift($statusHeader, $statusCode);
132
- return $response->withHeader(self::HISTORY_HEADER, $historyHeader)
133
- ->withHeader(self::STATUS_HISTORY_HEADER, $statusHeader);
134
- }
135
- );
136
- }
137
-
138
- private function guardMax(RequestInterface $request, array &$options)
139
- {
140
- $current = isset($options['__redirect_count'])
141
- ? $options['__redirect_count']
142
- : 0;
143
- $options['__redirect_count'] = $current + 1;
144
- $max = $options['allow_redirects']['max'];
145
-
146
- if ($options['__redirect_count'] > $max) {
147
- throw new TooManyRedirectsException(
148
- "Will not follow more than {$max} redirects",
149
- $request
150
- );
151
- }
152
- }
153
-
154
- /**
155
- * @param RequestInterface $request
156
- * @param array $options
157
- * @param ResponseInterface $response
158
- *
159
- * @return RequestInterface
160
- */
161
- public function modifyRequest(
162
- RequestInterface $request,
163
- array $options,
164
- ResponseInterface $response
165
- ) {
166
- // Request modifications to apply.
167
- $modify = [];
168
- $protocols = $options['allow_redirects']['protocols'];
169
-
170
- // Use a GET request if this is an entity enclosing request and we are
171
- // not forcing RFC compliance, but rather emulating what all browsers
172
- // would do.
173
- $statusCode = $response->getStatusCode();
174
- if ($statusCode == 303 ||
175
- ($statusCode <= 302 && $request->getBody() && !$options['allow_redirects']['strict'])
176
- ) {
177
- $modify['method'] = 'GET';
178
- $modify['body'] = '';
179
- }
180
-
181
- $modify['uri'] = $this->redirectUri($request, $response, $protocols);
182
- Psr7\rewind_body($request);
183
-
184
- // Add the Referer header if it is told to do so and only
185
- // add the header if we are not redirecting from https to http.
186
- if ($options['allow_redirects']['referer']
187
- && $modify['uri']->getScheme() === $request->getUri()->getScheme()
188
- ) {
189
- $uri = $request->getUri()->withUserInfo('', '');
190
- $modify['set_headers']['Referer'] = (string) $uri;
191
- } else {
192
- $modify['remove_headers'][] = 'Referer';
193
- }
194
-
195
- // Remove Authorization header if host is different.
196
- if ($request->getUri()->getHost() !== $modify['uri']->getHost()) {
197
- $modify['remove_headers'][] = 'Authorization';
198
- }
199
-
200
- return Psr7\modify_request($request, $modify);
201
- }
202
-
203
- /**
204
- * Set the appropriate URL on the request based on the location header
205
- *
206
- * @param RequestInterface $request
207
- * @param ResponseInterface $response
208
- * @param array $protocols
209
- *
210
- * @return UriInterface
211
- */
212
- private function redirectUri(
213
- RequestInterface $request,
214
- ResponseInterface $response,
215
- array $protocols
216
- ) {
217
- $location = Psr7\UriResolver::resolve(
218
- $request->getUri(),
219
- new Psr7\Uri($response->getHeaderLine('Location'))
220
- );
221
-
222
- // Ensure that the redirect URI is allowed based on the protocols.
223
- if (!in_array($location->getScheme(), $protocols)) {
224
- throw new BadResponseException(
225
- sprintf(
226
- 'Redirect URI, %s, does not use one of the allowed redirect protocols: %s',
227
- $location,
228
- implode(', ', $protocols)
229
- ),
230
- $request,
231
- $response
232
- );
233
- }
234
-
235
- return $location;
236
- }
237
- }
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ use GuzzleHttp\Exception\BadResponseException;
5
+ use GuzzleHttp\Exception\TooManyRedirectsException;
6
+ use GuzzleHttp\Promise\PromiseInterface;
7
+ use GuzzleHttp\Psr7;
8
+ use Psr\Http\Message\RequestInterface;
9
+ use Psr\Http\Message\ResponseInterface;
10
+ use Psr\Http\Message\UriInterface;
11
+
12
+ /**
13
+ * Request redirect middleware.
14
+ *
15
+ * Apply this middleware like other middleware using
16
+ * {@see GuzzleHttp\Middleware::redirect()}.
17
+ */
18
+ class RedirectMiddleware
19
+ {
20
+ const HISTORY_HEADER = 'X-Guzzle-Redirect-History';
21
+
22
+ const STATUS_HISTORY_HEADER = 'X-Guzzle-Redirect-Status-History';
23
+
24
+ public static $defaultSettings = [
25
+ 'max' => 5,
26
+ 'protocols' => ['http', 'https'],
27
+ 'strict' => false,
28
+ 'referer' => false,
29
+ 'track_redirects' => false,
30
+ ];
31
+
32
+ /** @var callable */
33
+ private $nextHandler;
34
+
35
+ /**
36
+ * @param callable $nextHandler Next handler to invoke.
37
+ */
38
+ public function __construct(callable $nextHandler)
39
+ {
40
+ $this->nextHandler = $nextHandler;
41
+ }
42
+
43
+ /**
44
+ * @param RequestInterface $request
45
+ * @param array $options
46
+ *
47
+ * @return PromiseInterface
48
+ */
49
+ public function __invoke(RequestInterface $request, array $options)
50
+ {
51
+ $fn = $this->nextHandler;
52
+
53
+ if (empty($options['allow_redirects'])) {
54
+ return $fn($request, $options);
55
+ }
56
+
57
+ if ($options['allow_redirects'] === true) {
58
+ $options['allow_redirects'] = self::$defaultSettings;
59
+ } elseif (!is_array($options['allow_redirects'])) {
60
+ throw new \InvalidArgumentException('allow_redirects must be true, false, or array');
61
+ } else {
62
+ // Merge the default settings with the provided settings
63
+ $options['allow_redirects'] += self::$defaultSettings;
64
+ }
65
+
66
+ if (empty($options['allow_redirects']['max'])) {
67
+ return $fn($request, $options);
68
+ }
69
+
70
+ return $fn($request, $options)
71
+ ->then(function (ResponseInterface $response) use ($request, $options) {
72
+ return $this->checkRedirect($request, $options, $response);
73
+ });
74
+ }
75
+
76
+ /**
77
+ * @param RequestInterface $request
78
+ * @param array $options
79
+ * @param ResponseInterface|PromiseInterface $response
80
+ *
81
+ * @return ResponseInterface|PromiseInterface
82
+ */
83
+ public function checkRedirect(
84
+ RequestInterface $request,
85
+ array $options,
86
+ ResponseInterface $response
87
+ ) {
88
+ if (substr($response->getStatusCode(), 0, 1) != '3'
89
+ || !$response->hasHeader('Location')
90
+ ) {
91
+ return $response;
92
+ }
93
+
94
+ $this->guardMax($request, $options);
95
+ $nextRequest = $this->modifyRequest($request, $options, $response);
96
+
97
+ if (isset($options['allow_redirects']['on_redirect'])) {
98
+ call_user_func(
99
+ $options['allow_redirects']['on_redirect'],
100
+ $request,
101
+ $response,
102
+ $nextRequest->getUri()
103
+ );
104
+ }
105
+
106
+ /** @var PromiseInterface|ResponseInterface $promise */
107
+ $promise = $this($nextRequest, $options);
108
+
109
+ // Add headers to be able to track history of redirects.
110
+ if (!empty($options['allow_redirects']['track_redirects'])) {
111
+ return $this->withTracking(
112
+ $promise,
113
+ (string) $nextRequest->getUri(),
114
+ $response->getStatusCode()
115
+ );
116
+ }
117
+
118
+ return $promise;
119
+ }
120
+
121
+ private function withTracking(PromiseInterface $promise, $uri, $statusCode)
122
+ {
123
+ return $promise->then(
124
+ function (ResponseInterface $response) use ($uri, $statusCode) {
125
+ // Note that we are pushing to the front of the list as this
126
+ // would be an earlier response than what is currently present
127
+ // in the history header.
128
+ $historyHeader = $response->getHeader(self::HISTORY_HEADER);
129
+ $statusHeader = $response->getHeader(self::STATUS_HISTORY_HEADER);
130
+ array_unshift($historyHeader, $uri);
131
+ array_unshift($statusHeader, $statusCode);
132
+ return $response->withHeader(self::HISTORY_HEADER, $historyHeader)
133
+ ->withHeader(self::STATUS_HISTORY_HEADER, $statusHeader);
134
+ }
135
+ );
136
+ }
137
+
138
+ private function guardMax(RequestInterface $request, array &$options)
139
+ {
140
+ $current = isset($options['__redirect_count'])
141
+ ? $options['__redirect_count']
142
+ : 0;
143
+ $options['__redirect_count'] = $current + 1;
144
+ $max = $options['allow_redirects']['max'];
145
+
146
+ if ($options['__redirect_count'] > $max) {
147
+ throw new TooManyRedirectsException(
148
+ "Will not follow more than {$max} redirects",
149
+ $request
150
+ );
151
+ }
152
+ }
153
+
154
+ /**
155
+ * @param RequestInterface $request
156
+ * @param array $options
157
+ * @param ResponseInterface $response
158
+ *
159
+ * @return RequestInterface
160
+ */
161
+ public function modifyRequest(
162
+ RequestInterface $request,
163
+ array $options,
164
+ ResponseInterface $response
165
+ ) {
166
+ // Request modifications to apply.
167
+ $modify = [];
168
+ $protocols = $options['allow_redirects']['protocols'];
169
+
170
+ // Use a GET request if this is an entity enclosing request and we are
171
+ // not forcing RFC compliance, but rather emulating what all browsers
172
+ // would do.
173
+ $statusCode = $response->getStatusCode();
174
+ if ($statusCode == 303 ||
175
+ ($statusCode <= 302 && $request->getBody() && !$options['allow_redirects']['strict'])
176
+ ) {
177
+ $modify['method'] = 'GET';
178
+ $modify['body'] = '';
179
+ }
180
+
181
+ $modify['uri'] = $this->redirectUri($request, $response, $protocols);
182
+ Psr7\rewind_body($request);
183
+
184
+ // Add the Referer header if it is told to do so and only
185
+ // add the header if we are not redirecting from https to http.
186
+ if ($options['allow_redirects']['referer']
187
+ && $modify['uri']->getScheme() === $request->getUri()->getScheme()
188
+ ) {
189
+ $uri = $request->getUri()->withUserInfo('', '');
190
+ $modify['set_headers']['Referer'] = (string) $uri;
191
+ } else {
192
+ $modify['remove_headers'][] = 'Referer';
193
+ }
194
+
195
+ // Remove Authorization header if host is different.
196
+ if ($request->getUri()->getHost() !== $modify['uri']->getHost()) {
197
+ $modify['remove_headers'][] = 'Authorization';
198
+ }
199
+
200
+ return Psr7\modify_request($request, $modify);
201
+ }
202
+
203
+ /**
204
+ * Set the appropriate URL on the request based on the location header
205
+ *
206
+ * @param RequestInterface $request
207
+ * @param ResponseInterface $response
208
+ * @param array $protocols
209
+ *
210
+ * @return UriInterface
211
+ */
212
+ private function redirectUri(
213
+ RequestInterface $request,
214
+ ResponseInterface $response,
215
+ array $protocols
216
+ ) {
217
+ $location = Psr7\UriResolver::resolve(
218
+ $request->getUri(),
219
+ new Psr7\Uri($response->getHeaderLine('Location'))
220
+ );
221
+
222
+ // Ensure that the redirect URI is allowed based on the protocols.
223
+ if (!in_array($location->getScheme(), $protocols)) {
224
+ throw new BadResponseException(
225
+ sprintf(
226
+ 'Redirect URI, %s, does not use one of the allowed redirect protocols: %s',
227
+ $location,
228
+ implode(', ', $protocols)
229
+ ),
230
+ $request,
231
+ $response
232
+ );
233
+ }
234
+
235
+ return $location;
236
+ }
237
+ }
vendor/guzzlehttp/guzzle/src/RequestOptions.php CHANGED
@@ -1,255 +1,255 @@
1
- <?php
2
- namespace GuzzleHttp;
3
-
4
- /**
5
- * This class contains a list of built-in Guzzle request options.
6
- *
7
- * More documentation for each option can be found at http://guzzlephp.org/.
8
- *
9
- * @link http://docs.guzzlephp.org/en/v6/request-options.html
10
- */
11
- final class RequestOptions
12
- {
13
- /**
14
- * allow_redirects: (bool|array) Controls redirect behavior. Pass false
15
- * to disable redirects, pass true to enable redirects, pass an
16
- * associative to provide custom redirect settings. Defaults to "false".
17
- * This option only works if your handler has the RedirectMiddleware. When
18
- * passing an associative array, you can provide the following key value
19
- * pairs:
20
- *
21
- * - max: (int, default=5) maximum number of allowed redirects.
22
- * - strict: (bool, default=false) Set to true to use strict redirects
23
- * meaning redirect POST requests with POST requests vs. doing what most
24
- * browsers do which is redirect POST requests with GET requests
25
- * - referer: (bool, default=true) Set to false to disable the Referer
26
- * header.
27
- * - protocols: (array, default=['http', 'https']) Allowed redirect
28
- * protocols.
29
- * - on_redirect: (callable) PHP callable that is invoked when a redirect
30
- * is encountered. The callable is invoked with the request, the redirect
31
- * response that was received, and the effective URI. Any return value
32
- * from the on_redirect function is ignored.
33
- */
34
- const ALLOW_REDIRECTS = 'allow_redirects';
35
-
36
- /**
37
- * auth: (array) Pass an array of HTTP authentication parameters to use
38
- * with the request. The array must contain the username in index [0],
39
- * the password in index [1], and you can optionally provide a built-in
40
- * authentication type in index [2]. Pass null to disable authentication
41
- * for a request.
42
- */
43
- const AUTH = 'auth';
44
-
45
- /**
46
- * body: (resource|string|null|int|float|StreamInterface|callable|\Iterator)
47
- * Body to send in the request.
48
- */
49
- const BODY = 'body';
50
-
51
- /**
52
- * cert: (string|array) Set to a string to specify the path to a file
53
- * containing a PEM formatted SSL client side certificate. If a password
54
- * is required, then set cert to an array containing the path to the PEM
55
- * file in the first array element followed by the certificate password
56
- * in the second array element.
57
- */
58
- const CERT = 'cert';
59
-
60
- /**
61
- * cookies: (bool|GuzzleHttp\Cookie\CookieJarInterface, default=false)
62
- * Specifies whether or not cookies are used in a request or what cookie
63
- * jar to use or what cookies to send. This option only works if your
64
- * handler has the `cookie` middleware. Valid values are `false` and
65
- * an instance of {@see GuzzleHttp\Cookie\CookieJarInterface}.
66
- */
67
- const COOKIES = 'cookies';
68
-
69
- /**
70
- * connect_timeout: (float, default=0) Float describing the number of
71
- * seconds to wait while trying to connect to a server. Use 0 to wait
72
- * indefinitely (the default behavior).
73
- */
74
- const CONNECT_TIMEOUT = 'connect_timeout';
75
-
76
- /**
77
- * debug: (bool|resource) Set to true or set to a PHP stream returned by
78
- * fopen() enable debug output with the HTTP handler used to send a
79
- * request.
80
- */
81
- const DEBUG = 'debug';
82
-
83
- /**
84
- * decode_content: (bool, default=true) Specify whether or not
85
- * Content-Encoding responses (gzip, deflate, etc.) are automatically
86
- * decoded.
87
- */
88
- const DECODE_CONTENT = 'decode_content';
89
-
90
- /**
91
- * delay: (int) The amount of time to delay before sending in milliseconds.
92
- */
93
- const DELAY = 'delay';
94
-
95
- /**
96
- * expect: (bool|integer) Controls the behavior of the
97
- * "Expect: 100-Continue" header.
98
- *
99
- * Set to `true` to enable the "Expect: 100-Continue" header for all
100
- * requests that sends a body. Set to `false` to disable the
101
- * "Expect: 100-Continue" header for all requests. Set to a number so that
102
- * the size of the payload must be greater than the number in order to send
103
- * the Expect header. Setting to a number will send the Expect header for
104
- * all requests in which the size of the payload cannot be determined or
105
- * where the body is not rewindable.
106
- *
107
- * By default, Guzzle will add the "Expect: 100-Continue" header when the
108
- * size of the body of a request is greater than 1 MB and a request is
109
- * using HTTP/1.1.
110
- */
111
- const EXPECT = 'expect';
112
-
113
- /**
114
- * form_params: (array) Associative array of form field names to values
115
- * where each value is a string or array of strings. Sets the Content-Type
116
- * header to application/x-www-form-urlencoded when no Content-Type header
117
- * is already present.
118
- */
119
- const FORM_PARAMS = 'form_params';
120
-
121
- /**
122
- * headers: (array) Associative array of HTTP headers. Each value MUST be
123
- * a string or array of strings.
124
- */
125
- const HEADERS = 'headers';
126
-
127
- /**
128
- * http_errors: (bool, default=true) Set to false to disable exceptions
129
- * when a non- successful HTTP response is received. By default,
130
- * exceptions will be thrown for 4xx and 5xx responses. This option only
131
- * works if your handler has the `httpErrors` middleware.
132
- */
133
- const HTTP_ERRORS = 'http_errors';
134
-
135
- /**
136
- * json: (mixed) Adds JSON data to a request. The provided value is JSON
137
- * encoded and a Content-Type header of application/json will be added to
138
- * the request if no Content-Type header is already present.
139
- */
140
- const JSON = 'json';
141
-
142
- /**
143
- * multipart: (array) Array of associative arrays, each containing a
144
- * required "name" key mapping to the form field, name, a required
145
- * "contents" key mapping to a StreamInterface|resource|string, an
146
- * optional "headers" associative array of custom headers, and an
147
- * optional "filename" key mapping to a string to send as the filename in
148
- * the part. If no "filename" key is present, then no "filename" attribute
149
- * will be added to the part.
150
- */
151
- const MULTIPART = 'multipart';
152
-
153
- /**
154
- * on_headers: (callable) A callable that is invoked when the HTTP headers
155
- * of the response have been received but the body has not yet begun to
156
- * download.
157
- */
158
- const ON_HEADERS = 'on_headers';
159
-
160
- /**
161
- * on_stats: (callable) allows you to get access to transfer statistics of
162
- * a request and access the lower level transfer details of the handler
163
- * associated with your client. ``on_stats`` is a callable that is invoked
164
- * when a handler has finished sending a request. The callback is invoked
165
- * with transfer statistics about the request, the response received, or
166
- * the error encountered. Included in the data is the total amount of time
167
- * taken to send the request.
168
- */
169
- const ON_STATS = 'on_stats';
170
-
171
- /**
172
- * progress: (callable) Defines a function to invoke when transfer
173
- * progress is made. The function accepts the following positional
174
- * arguments: the total number of bytes expected to be downloaded, the
175
- * number of bytes downloaded so far, the number of bytes expected to be
176
- * uploaded, the number of bytes uploaded so far.
177
- */
178
- const PROGRESS = 'progress';
179
-
180
- /**
181
- * proxy: (string|array) Pass a string to specify an HTTP proxy, or an
182
- * array to specify different proxies for different protocols (where the
183
- * key is the protocol and the value is a proxy string).
184
- */
185
- const PROXY = 'proxy';
186
-
187
- /**
188
- * query: (array|string) Associative array of query string values to add
189
- * to the request. This option uses PHP's http_build_query() to create
190
- * the string representation. Pass a string value if you need more
191
- * control than what this method provides
192
- */
193
- const QUERY = 'query';
194
-
195
- /**
196
- * sink: (resource|string|StreamInterface) Where the data of the
197
- * response is written to. Defaults to a PHP temp stream. Providing a
198
- * string will write data to a file by the given name.
199
- */
200
- const SINK = 'sink';
201
-
202
- /**
203
- * synchronous: (bool) Set to true to inform HTTP handlers that you intend
204
- * on waiting on the response. This can be useful for optimizations. Note
205
- * that a promise is still returned if you are using one of the async
206
- * client methods.
207
- */
208
- const SYNCHRONOUS = 'synchronous';
209
-
210
- /**
211
- * ssl_key: (array|string) Specify the path to a file containing a private
212
- * SSL key in PEM format. If a password is required, then set to an array
213
- * containing the path to the SSL key in the first array element followed
214
- * by the password required for the certificate in the second element.
215
- */
216
- const SSL_KEY = 'ssl_key';
217
-
218
- /**
219
- * stream: Set to true to attempt to stream a response rather than
220
- * download it all up-front.
221
- */
222
- const STREAM = 'stream';
223
-
224
- /**
225
- * verify: (bool|string, default=true) Describes the SSL certificate
226
- * verification behavior of a request. Set to true to enable SSL
227
- * certificate verification using the system CA bundle when available
228
- * (the default). Set to false to disable certificate verification (this
229
- * is insecure!). Set to a string to provide the path to a CA bundle on
230
- * disk to enable verification using a custom certificate.
231
- */
232
- const VERIFY = 'verify';
233
-
234
- /**
235
- * timeout: (float, default=0) Float describing the timeout of the
236
- * request in seconds. Use 0 to wait indefinitely (the default behavior).
237
- */
238
- const TIMEOUT = 'timeout';
239
-
240
- /**
241
- * read_timeout: (float, default=default_socket_timeout ini setting) Float describing
242
- * the body read timeout, for stream requests.
243
- */
244
- const READ_TIMEOUT = 'read_timeout';
245
-
246
- /**
247
- * version: (float) Specifies the HTTP protocol version to attempt to use.
248
- */
249
- const VERSION = 'version';
250
-
251
- /**
252
- * force_ip_resolve: (bool) Force client to use only ipv4 or ipv6 protocol
253
- */
254
- const FORCE_IP_RESOLVE = 'force_ip_resolve';
255
- }
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ /**
5
+ * This class contains a list of built-in Guzzle request options.
6
+ *
7
+ * More documentation for each option can be found at http://guzzlephp.org/.
8
+ *
9
+ * @link http://docs.guzzlephp.org/en/v6/request-options.html
10
+ */
11
+ final class RequestOptions
12
+ {
13
+ /**
14
+ * allow_redirects: (bool|array) Controls redirect behavior. Pass false
15
+ * to disable redirects, pass true to enable redirects, pass an
16
+ * associative to provide custom redirect settings. Defaults to "false".
17
+ * This option only works if your handler has the RedirectMiddleware. When
18
+ * passing an associative array, you can provide the following key value
19
+ * pairs:
20
+ *
21
+ * - max: (int, default=5) maximum number of allowed redirects.
22
+ * - strict: (bool, default=false) Set to true to use strict redirects
23
+ * meaning redirect POST requests with POST requests vs. doing what most
24
+ * browsers do which is redirect POST requests with GET requests
25
+ * - referer: (bool, default=true) Set to false to disable the Referer
26
+ * header.
27
+ * - protocols: (array, default=['http', 'https']) Allowed redirect
28
+ * protocols.
29
+ * - on_redirect: (callable) PHP callable that is invoked when a redirect
30
+ * is encountered. The callable is invoked with the request, the redirect
31
+ * response that was received, and the effective URI. Any return value
32
+ * from the on_redirect function is ignored.
33
+ */
34
+ const ALLOW_REDIRECTS = 'allow_redirects';
35
+
36
+ /**
37
+ * auth: (array) Pass an array of HTTP authentication parameters to use
38
+ * with the request. The array must contain the username in index [0],
39
+ * the password in index [1], and you can optionally provide a built-in
40
+ * authentication type in index [2]. Pass null to disable authentication
41
+ * for a request.
42
+ */
43
+ const AUTH = 'auth';
44
+
45
+ /**
46
+ * body: (resource|string|null|int|float|StreamInterface|callable|\Iterator)
47
+ * Body to send in the request.
48
+ */
49
+ const BODY = 'body';
50
+
51
+ /**
52
+ * cert: (string|array) Set to a string to specify the path to a file
53
+ * containing a PEM formatted SSL client side certificate. If a password
54
+ * is required, then set cert to an array containing the path to the PEM
55
+ * file in the first array element followed by the certificate password
56
+ * in the second array element.
57
+ */
58
+ const CERT = 'cert';
59
+
60
+ /**
61
+ * cookies: (bool|GuzzleHttp\Cookie\CookieJarInterface, default=false)
62
+ * Specifies whether or not cookies are used in a request or what cookie
63
+ * jar to use or what cookies to send. This option only works if your
64
+ * handler has the `cookie` middleware. Valid values are `false` and
65
+ * an instance of {@see GuzzleHttp\Cookie\CookieJarInterface}.
66
+ */
67
+ const COOKIES = 'cookies';
68
+
69
+ /**
70
+ * connect_timeout: (float, default=0) Float describing the number of
71
+ * seconds to wait while trying to connect to a server. Use 0 to wait
72
+ * indefinitely (the default behavior).
73
+ */
74
+ const CONNECT_TIMEOUT = 'connect_timeout';
75
+
76
+ /**
77
+ * debug: (bool|resource) Set to true or set to a PHP stream returned by
78
+ * fopen() enable debug output with the HTTP handler used to send a
79
+ * request.
80
+ */
81
+ const DEBUG = 'debug';
82
+
83
+ /**
84
+ * decode_content: (bool, default=true) Specify whether or not
85
+ * Content-Encoding responses (gzip, deflate, etc.) are automatically
86
+ * decoded.
87
+ */
88
+ const DECODE_CONTENT = 'decode_content';
89
+
90
+ /**
91
+ * delay: (int) The amount of time to delay before sending in milliseconds.
92
+ */
93
+ const DELAY = 'delay';
94
+
95
+ /**
96
+ * expect: (bool|integer) Controls the behavior of the
97
+ * "Expect: 100-Continue" header.
98
+ *
99
+ * Set to `true` to enable the "Expect: 100-Continue" header for all
100
+ * requests that sends a body. Set to `false` to disable the
101
+ * "Expect: 100-Continue" header for all requests. Set to a number so that
102
+ * the size of the payload must be greater than the number in order to send
103
+ * the Expect header. Setting to a number will send the Expect header for
104
+ * all requests in which the size of the payload cannot be determined or
105
+ * where the body is not rewindable.
106
+ *
107
+ * By default, Guzzle will add the "Expect: 100-Continue" header when the
108
+ * size of the body of a request is greater than 1 MB and a request is
109
+ * using HTTP/1.1.
110
+ */
111
+ const EXPECT = 'expect';
112
+
113
+ /**
114
+ * form_params: (array) Associative array of form field names to values
115
+ * where each value is a string or array of strings. Sets the Content-Type
116
+ * header to application/x-www-form-urlencoded when no Content-Type header
117
+ * is already present.
118
+ */
119
+ const FORM_PARAMS = 'form_params';
120
+
121
+ /**
122
+ * headers: (array) Associative array of HTTP headers. Each value MUST be
123
+ * a string or array of strings.
124
+ */
125
+ const HEADERS = 'headers';
126
+
127
+ /**
128
+ * http_errors: (bool, default=true) Set to false to disable exceptions
129
+ * when a non- successful HTTP response is received. By default,
130
+ * exceptions will be thrown for 4xx and 5xx responses. This option only
131
+ * works if your handler has the `httpErrors` middleware.
132
+ */
133
+ const HTTP_ERRORS = 'http_errors';
134
+
135
+ /**
136
+ * json: (mixed) Adds JSON data to a request. The provided value is JSON
137
+ * encoded and a Content-Type header of application/json will be added to
138
+ * the request if no Content-Type header is already present.
139
+ */
140
+ const JSON = 'json';
141
+
142
+ /**
143
+ * multipart: (array) Array of associative arrays, each containing a
144
+ * required "name" key mapping to the form field, name, a required
145
+ * "contents" key mapping to a StreamInterface|resource|string, an
146
+ * optional "headers" associative array of custom headers, and an
147
+ * optional "filename" key mapping to a string to send as the filename in
148
+ * the part. If no "filename" key is present, then no "filename" attribute
149
+ * will be added to the part.
150
+ */
151
+ const MULTIPART = 'multipart';
152
+
153
+ /**
154
+ * on_headers: (callable) A callable that is invoked when the HTTP headers
155
+ * of the response have been received but the body has not yet begun to
156
+ * download.
157
+ */
158
+ const ON_HEADERS = 'on_headers';
159
+
160
+ /**
161
+ * on_stats: (callable) allows you to get access to transfer statistics of
162
+ * a request and access the lower level transfer details of the handler
163
+ * associated with your client. ``on_stats`` is a callable that is invoked
164
+ * when a handler has finished sending a request. The callback is invoked
165
+ * with transfer statistics about the request, the response received, or
166
+ * the error encountered. Included in the data is the total amount of time
167
+ * taken to send the request.
168
+ */
169
+ const ON_STATS = 'on_stats';
170
+
171
+ /**
172
+ * progress: (callable) Defines a function to invoke when transfer
173
+ * progress is made. The function accepts the following positional
174
+ * arguments: the total number of bytes expected to be downloaded, the
175
+ * number of bytes downloaded so far, the number of bytes expected to be
176
+ * uploaded, the number of bytes uploaded so far.
177
+ */
178
+ const PROGRESS = 'progress';
179
+
180
+ /**
181
+ * proxy: (string|array) Pass a string to specify an HTTP proxy, or an
182
+ * array to specify different proxies for different protocols (where the
183
+ * key is the protocol and the value is a proxy string).
184
+ */
185
+ const PROXY = 'proxy';
186
+
187
+ /**
188
+ * query: (array|string) Associative array of query string values to add
189
+ * to the request. This option uses PHP's http_build_query() to create
190
+ * the string representation. Pass a string value if you need more
191
+ * control than what this method provides
192
+ */
193
+ const QUERY = 'query';
194
+
195
+ /**
196
+ * sink: (resource|string|StreamInterface) Where the data of the
197
+ * response is written to. Defaults to a PHP temp stream. Providing a
198
+ * string will write data to a file by the given name.
199
+ */
200
+ const SINK = 'sink';
201
+
202
+ /**
203
+ * synchronous: (bool) Set to true to inform HTTP handlers that you intend
204
+ * on waiting on the response. This can be useful for optimizations. Note
205
+ * that a promise is still returned if you are using one of the async
206
+ * client methods.
207
+ */
208
+ const SYNCHRONOUS = 'synchronous';
209
+
210
+ /**
211
+ * ssl_key: (array|string) Specify the path to a file containing a private
212
+ * SSL key in PEM format. If a password is required, then set to an array
213
+ * containing the path to the SSL key in the first array element followed
214
+ * by the password required for the certificate in the second element.
215
+ */
216
+ const SSL_KEY = 'ssl_key';
217
+
218
+ /**
219
+ * stream: Set to true to attempt to stream a response rather than
220
+ * download it all up-front.
221
+ */
222
+ const STREAM = 'stream';
223
+
224
+ /**
225
+ * verify: (bool|string, default=true) Describes the SSL certificate
226
+ * verification behavior of a request. Set to true to enable SSL
227
+ * certificate verification using the system CA bundle when available
228
+ * (the default). Set to false to disable certificate verification (this
229
+ * is insecure!). Set to a string to provide the path to a CA bundle on
230
+ * disk to enable verification using a custom certificate.
231
+ */
232
+ const VERIFY = 'verify';
233
+
234
+ /**
235
+ * timeout: (float, default=0) Float describing the timeout of the
236
+ * request in seconds. Use 0 to wait indefinitely (the default behavior).
237
+ */
238
+ const TIMEOUT = 'timeout';
239
+
240
+ /**
241
+ * read_timeout: (float, default=default_socket_timeout ini setting) Float describing
242
+ * the body read timeout, for stream requests.
243
+ */
244
+ const READ_TIMEOUT = 'read_timeout';
245
+
246
+ /**
247
+ * version: (float) Specifies the HTTP protocol version to attempt to use.
248
+ */
249
+ const VERSION = 'version';
250
+
251
+ /**
252
+ * force_ip_resolve: (bool) Force client to use only ipv4 or ipv6 protocol
253
+ */
254
+ const FORCE_IP_RESOLVE = 'force_ip_resolve';
255
+ }
vendor/guzzlehttp/guzzle/src/RetryMiddleware.php CHANGED
@@ -1,112 +1,112 @@
1
- <?php
2
- namespace GuzzleHttp;
3
-
4
- use GuzzleHttp\Promise\PromiseInterface;
5
- use GuzzleHttp\Promise\RejectedPromise;
6
- use GuzzleHttp\Psr7;
7
- use Psr\Http\Message\RequestInterface;
8
- use Psr\Http\Message\ResponseInterface;
9
-
10
- /**
11
- * Middleware that retries requests based on the boolean result of
12
- * invoking the provided "decider" function.
13
- */
14
- class RetryMiddleware
15
- {
16
- /** @var callable */
17
- private $nextHandler;
18
-
19
- /** @var callable */
20
- private $decider;
21
-
22
- /**
23
- * @param callable $decider Function that accepts the number of retries,
24
- * a request, [response], and [exception] and
25
- * returns true if the request is to be
26
- * retried.
27
- * @param callable $nextHandler Next handler to invoke.
28
- * @param callable $delay Function that accepts the number of retries
29
- * and [response] and returns the number of
30
- * milliseconds to delay.
31
- */
32
- public function __construct(
33
- callable $decider,
34
- callable $nextHandler,
35
- callable $delay = null
36
- ) {
37
- $this->decider = $decider;
38
- $this->nextHandler = $nextHandler;
39
- $this->delay = $delay ?: __CLASS__ . '::exponentialDelay';
40
- }
41
-
42
- /**
43
- * Default exponential backoff delay function.
44
- *
45
- * @param $retries
46
- *
47
- * @return int
48
- */
49
- public static function exponentialDelay($retries)
50
- {
51
- return (int) pow(2, $retries - 1);
52
- }
53
-
54
- /**
55
- * @param RequestInterface $request
56
- * @param array $options
57
- *
58
- * @return PromiseInterface
59
- */
60
- public function __invoke(RequestInterface $request, array $options)
61
- {
62
- if (!isset($options['retries'])) {
63
- $options['retries'] = 0;
64
- }
65
-
66
- $fn = $this->nextHandler;
67
- return $fn($request, $options)
68
- ->then(
69
- $this->onFulfilled($request, $options),
70
- $this->onRejected($request, $options)
71
- );
72
- }
73
-
74
- private function onFulfilled(RequestInterface $req, array $options)
75
- {
76
- return function ($value) use ($req, $options) {
77
- if (!call_user_func(
78
- $this->decider,
79
- $options['retries'],
80
- $req,
81
- $value,
82
- null
83
- )) {
84
- return $value;
85
- }
86
- return $this->doRetry($req, $options, $value);
87
- };
88
- }
89
-
90
- private function onRejected(RequestInterface $req, array $options)
91
- {
92
- return function ($reason) use ($req, $options) {
93
- if (!call_user_func(
94
- $this->decider,
95
- $options['retries'],
96
- $req,
97
- null,
98
- $reason
99
- )) {
100
- return \GuzzleHttp\Promise\rejection_for($reason);
101
- }
102
- return $this->doRetry($req, $options);
103
- };
104
- }
105
-
106
- private function doRetry(RequestInterface $request, array $options, ResponseInterface $response = null)
107
- {
108
- $options['delay'] = call_user_func($this->delay, ++$options['retries'], $response);
109
-
110
- return $this($request, $options);
111
- }
112
- }
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ use GuzzleHttp\Promise\PromiseInterface;
5
+ use GuzzleHttp\Promise\RejectedPromise;
6
+ use GuzzleHttp\Psr7;
7
+ use Psr\Http\Message\RequestInterface;
8
+ use Psr\Http\Message\ResponseInterface;
9
+
10
+ /**
11
+ * Middleware that retries requests based on the boolean result of
12
+ * invoking the provided "decider" function.
13
+ */
14
+ class RetryMiddleware
15
+ {
16
+ /** @var callable */
17
+ private $nextHandler;
18
+
19
+ /** @var callable */
20
+ private $decider;
21
+
22
+ /**
23
+ * @param callable $decider Function that accepts the number of retries,
24
+ * a request, [response], and [exception] and
25
+ * returns true if the request is to be
26
+ * retried.
27
+ * @param callable $nextHandler Next handler to invoke.
28
+ * @param callable $delay Function that accepts the number of retries
29
+ * and [response] and returns the number of
30
+ * milliseconds to delay.
31
+ */
32
+ public function __construct(
33
+ callable $decider,
34
+ callable $nextHandler,
35
+ callable $delay = null
36
+ ) {
37
+ $this->decider = $decider;
38
+ $this->nextHandler = $nextHandler;
39
+ $this->delay = $delay ?: __CLASS__ . '::exponentialDelay';
40
+ }
41
+
42
+ /**
43
+ * Default exponential backoff delay function.
44
+ *
45
+ * @param $retries
46
+ *
47
+ * @return int
48
+ */
49
+ public static function exponentialDelay($retries)
50
+ {
51
+ return (int) pow(2, $retries - 1);
52
+ }
53
+
54
+ /**
55
+ * @param RequestInterface $request
56
+ * @param array $options
57
+ *
58
+ * @return PromiseInterface
59
+ */
60
+ public function __invoke(RequestInterface $request, array $options)
61
+ {
62
+ if (!isset($options['retries'])) {
63
+ $options['retries'] = 0;
64
+ }
65
+
66
+ $fn = $this->nextHandler;
67
+ return $fn($request, $options)
68
+ ->then(
69
+ $this->onFulfilled($request, $options),
70
+ $this->onRejected($request, $options)
71
+ );
72
+ }
73
+
74
+ private function onFulfilled(RequestInterface $req, array $options)
75
+ {
76
+ return function ($value) use ($req, $options) {
77
+ if (!call_user_func(
78
+ $this->decider,
79
+ $options['retries'],
80
+ $req,
81
+ $value,
82
+ null
83
+ )) {
84
+ return $value;
85
+ }
86
+ return $this->doRetry($req, $options, $value);
87
+ };
88
+ }
89
+
90
+ private function onRejected(RequestInterface $req, array $options)
91
+ {
92
+ return function ($reason) use ($req, $options) {
93
+ if (!call_user_func(
94
+ $this->decider,
95
+ $options['retries'],
96
+ $req,
97
+ null,
98
+ $reason
99
+ )) {
100
+ return \GuzzleHttp\Promise\rejection_for($reason);
101
+ }
102
+ return $this->doRetry($req, $options);
103
+ };
104
+ }
105
+
106
+ private function doRetry(RequestInterface $request, array $options, ResponseInterface $response = null)
107
+ {
108
+ $options['delay'] = call_user_func($this->delay, ++$options['retries'], $response);
109
+
110
+ return $this($request, $options);
111
+ }
112
+ }
vendor/guzzlehttp/guzzle/src/TransferStats.php CHANGED
@@ -1,126 +1,126 @@
1
- <?php
2
- namespace GuzzleHttp;
3
-
4
- use Psr\Http\Message\RequestInterface;
5
- use Psr\Http\Message\ResponseInterface;
6
- use Psr\Http\Message\UriInterface;
7
-
8
- /**
9
- * Represents data at the point after it was transferred either successfully
10
- * or after a network error.
11
- */
12
- final class TransferStats
13
- {
14
- private $request;
15
- private $response;
16
- private $transferTime;
17
- private $handlerStats;
18
- private $handlerErrorData;
19
-
20
- /**
21
- * @param RequestInterface $request Request that was sent.
22
- * @param ResponseInterface $response Response received (if any)
23
- * @param null $transferTime Total handler transfer time.
24
- * @param mixed $handlerErrorData Handler error data.
25
- * @param array $handlerStats Handler specific stats.
26
- */
27
- public function __construct(
28
- RequestInterface $request,
29
- ResponseInterface $response = null,
30
- $transferTime = null,
31
- $handlerErrorData = null,
32
- $handlerStats = []
33
- ) {
34
- $this->request = $request;
35
- $this->response = $response;
36
- $this->transferTime = $transferTime;
37
- $this->handlerErrorData = $handlerErrorData;
38
- $this->handlerStats = $handlerStats;
39
- }
40
-
41
- /**
42
- * @return RequestInterface
43
- */
44
- public function getRequest()
45
- {
46
- return $this->request;
47
- }
48
-
49
- /**
50
- * Returns the response that was received (if any).
51
- *
52
- * @return ResponseInterface|null
53
- */
54
- public function getResponse()
55
- {
56
- return $this->response;
57
- }
58
-
59
- /**
60
- * Returns true if a response was received.
61
- *
62
- * @return bool
63
- */
64
- public function hasResponse()
65
- {
66
- return $this->response !== null;
67
- }
68
-
69
- /**
70
- * Gets handler specific error data.
71
- *
72
- * This might be an exception, a integer representing an error code, or
73
- * anything else. Relying on this value assumes that you know what handler
74
- * you are using.
75
- *
76
- * @return mixed
77
- */
78
- public function getHandlerErrorData()
79
- {
80
- return $this->handlerErrorData;
81
- }
82
-
83
- /**
84
- * Get the effective URI the request was sent to.
85
- *
86
- * @return UriInterface
87
- */
88
- public function getEffectiveUri()
89
- {
90
- return $this->request->getUri();
91
- }
92
-
93
- /**
94
- * Get the estimated time the request was being transferred by the handler.
95
- *
96
- * @return float Time in seconds.
97
- */
98
- public function getTransferTime()
99
- {
100
- return $this->transferTime;
101
- }
102
-
103
- /**
104
- * Gets an array of all of the handler specific transfer data.
105
- *
106
- * @return array
107
- */
108
- public function getHandlerStats()
109
- {
110
- return $this->handlerStats;
111
- }
112
-
113
- /**
114
- * Get a specific handler statistic from the handler by name.
115
- *
116
- * @param string $stat Handler specific transfer stat to retrieve.
117
- *
118
- * @return mixed|null
119
- */
120
- public function getHandlerStat($stat)
121
- {
122
- return isset($this->handlerStats[$stat])
123
- ? $this->handlerStats[$stat]
124
- : null;
125
- }
126
- }
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ use Psr\Http\Message\RequestInterface;
5
+ use Psr\Http\Message\ResponseInterface;
6
+ use Psr\Http\Message\UriInterface;
7
+
8
+ /**
9
+ * Represents data at the point after it was transferred either successfully
10
+ * or after a network error.
11
+ */
12
+ final class TransferStats
13
+ {
14
+ private $request;
15
+ private $response;
16
+ private $transferTime;
17
+ private $handlerStats;
18
+ private $handlerErrorData;
19
+
20
+ /**
21
+ * @param RequestInterface $request Request that was sent.
22
+ * @param ResponseInterface $response Response received (if any)
23
+ * @param null $transferTime Total handler transfer time.
24
+ * @param mixed $handlerErrorData Handler error data.
25
+ * @param array $handlerStats Handler specific stats.
26
+ */
27
+ public function __construct(
28
+ RequestInterface $request,
29
+ ResponseInterface $response = null,
30
+ $transferTime = null,
31
+ $handlerErrorData = null,
32
+ $handlerStats = []
33
+ ) {
34
+ $this->request = $request;
35
+ $this->response = $response;
36
+ $this->transferTime = $transferTime;
37
+ $this->handlerErrorData = $handlerErrorData;
38
+ $this->handlerStats = $handlerStats;
39
+ }
40
+
41
+ /**
42
+ * @return RequestInterface
43
+ */
44
+ public function getRequest()
45
+ {
46
+ return $this->request;
47
+ }
48
+
49
+ /**
50
+ * Returns the response that was received (if any).
51
+ *
52
+ * @return ResponseInterface|null
53
+ */
54
+ public function getResponse()
55
+ {
56
+ return $this->response;
57
+ }
58
+
59
+ /**
60
+ * Returns true if a response was received.
61
+ *
62
+ * @return bool
63
+ */
64
+ public function hasResponse()
65
+ {
66
+ return $this->response !== null;
67
+ }
68
+
69
+ /**
70
+ * Gets handler specific error data.
71
+ *
72
+ * This might be an exception, a integer representing an error code, or
73
+ * anything else. Relying on this value assumes that you know what handler
74
+ * you are using.
75
+ *
76
+ * @return mixed
77
+ */
78
+ public function getHandlerErrorData()
79
+ {
80
+ return $this->handlerErrorData;
81
+ }
82
+
83
+ /**
84
+ * Get the effective URI the request was sent to.
85
+ *
86
+ * @return UriInterface
87
+ */
88
+ public function getEffectiveUri()
89
+ {
90
+ return $this->request->getUri();
91
+ }
92
+
93
+ /**
94
+ * Get the estimated time the request was being transferred by the handler.
95
+ *
96
+ * @return float Time in seconds.
97
+ */
98
+ public function getTransferTime()
99
+ {
100
+ return $this->transferTime;
101
+ }
102
+
103
+ /**
104
+ * Gets an array of all of the handler specific transfer data.
105
+ *
106
+ * @return array
107
+ */
108
+ public function getHandlerStats()
109
+ {
110
+ return $this->handlerStats;
111
+ }
112
+
113
+ /**
114
+ * Get a specific handler statistic from the handler by name.
115
+ *
116
+ * @param string $stat Handler specific transfer stat to retrieve.
117
+ *
118
+ * @return mixed|null
119
+ */
120
+ public function getHandlerStat($stat)
121
+ {
122
+ return isset($this->handlerStats[$stat])
123
+ ? $this->handlerStats[$stat]
124
+ : null;
125
+ }
126
+ }
vendor/guzzlehttp/guzzle/src/UriTemplate.php CHANGED
@@ -1,237 +1,237 @@
1
- <?php
2
- namespace GuzzleHttp;
3
-
4
- /**
5
- * Expands URI templates. Userland implementation of PECL uri_template.
6
- *
7
- * @link http://tools.ietf.org/html/rfc6570
8
- */
9
- class UriTemplate
10
- {
11
- /** @var string URI template */
12
- private $template;
13
-
14
- /** @var array Variables to use in the template expansion */
15
- private $variables;
16
-
17
- /** @var array Hash for quick operator lookups */
18
- private static $operatorHash = [
19
- '' => ['prefix' => '', 'joiner' => ',', 'query' => false],
20
- '+' => ['prefix' => '', 'joiner' => ',', 'query' => false],
21
- '#' => ['prefix' => '#', 'joiner' => ',', 'query' => false],
22
- '.' => ['prefix' => '.', 'joiner' => '.', 'query' => false],
23
- '/' => ['prefix' => '/', 'joiner' => '/', 'query' => false],
24
- ';' => ['prefix' => ';', 'joiner' => ';', 'query' => true],
25
- '?' => ['prefix' => '?', 'joiner' => '&', 'query' => true],
26
- '&' => ['prefix' => '&', 'joiner' => '&', 'query' => true]
27
- ];
28
-
29
- /** @var array Delimiters */
30
- private static $delims = [':', '/', '?', '#', '[', ']', '@', '!', '$',
31
- '&', '\'', '(', ')', '*', '+', ',', ';', '='];
32
-
33
- /** @var array Percent encoded delimiters */
34
- private static $delimsPct = ['%3A', '%2F', '%3F', '%23', '%5B', '%5D',
35
- '%40', '%21', '%24', '%26', '%27', '%28', '%29', '%2A', '%2B', '%2C',
36
- '%3B', '%3D'];
37
-
38
- public function expand($template, array $variables)
39
- {
40
- if (false === strpos($template, '{')) {
41
- return $template;
42
- }
43
-
44
- $this->template = $template;
45
- $this->variables = $variables;
46
-
47
- return preg_replace_callback(
48
- '/\{([^\}]+)\}/',
49
- [$this, 'expandMatch'],
50
- $this->template
51
- );
52
- }
53
-
54
- /**
55
- * Parse an expression into parts
56
- *
57
- * @param string $expression Expression to parse
58
- *
59
- * @return array Returns an associative array of parts
60
- */
61
- private function parseExpression($expression)
62
- {
63
- $result = [];
64
-
65
- if (isset(self::$operatorHash[$expression[0]])) {
66
- $result['operator'] = $expression[0];
67
- $expression = substr($expression, 1);
68
- } else {
69
- $result['operator'] = '';
70
- }
71
-
72
- foreach (explode(',', $expression) as $value) {
73
- $value = trim($value);
74
- $varspec = [];
75
- if ($colonPos = strpos($value, ':')) {
76
- $varspec['value'] = substr($value, 0, $colonPos);
77
- $varspec['modifier'] = ':';
78
- $varspec['position'] = (int) substr($value, $colonPos + 1);
79
- } elseif (substr($value, -1) === '*') {
80
- $varspec['modifier'] = '*';
81
- $varspec['value'] = substr($value, 0, -1);
82
- } else {
83
- $varspec['value'] = (string) $value;
84
- $varspec['modifier'] = '';
85
- }
86
- $result['values'][] = $varspec;
87
- }
88
-
89
- return $result;
90
- }
91
-
92
- /**
93
- * Process an expansion
94
- *
95
- * @param array $matches Matches met in the preg_replace_callback
96
- *
97
- * @return string Returns the replacement string
98
- */
99
- private function expandMatch(array $matches)
100
- {
101
- static $rfc1738to3986 = ['+' => '%20', '%7e' => '~'];
102
-
103
- $replacements = [];
104
- $parsed = self::parseExpression($matches[1]);
105
- $prefix = self::$operatorHash[$parsed['operator']]['prefix'];
106
- $joiner = self::$operatorHash[$parsed['operator']]['joiner'];
107
- $useQuery = self::$operatorHash[$parsed['operator']]['query'];
108
-
109
- foreach ($parsed['values'] as $value) {
110
- if (!isset($this->variables[$value['value']])) {
111
- continue;
112
- }
113
-
114
- $variable = $this->variables[$value['value']];
115
- $actuallyUseQuery = $useQuery;
116
- $expanded = '';
117
-
118
- if (is_array($variable)) {
119
- $isAssoc = $this->isAssoc($variable);
120
- $kvp = [];
121
- foreach ($variable as $key => $var) {
122
- if ($isAssoc) {
123
- $key = rawurlencode($key);
124
- $isNestedArray = is_array($var);
125
- } else {
126
- $isNestedArray = false;
127
- }
128
-
129
- if (!$isNestedArray) {
130
- $var = rawurlencode($var);
131
- if ($parsed['operator'] === '+' ||
132
- $parsed['operator'] === '#'
133
- ) {
134
- $var = $this->decodeReserved($var);
135
- }
136
- }
137
-
138
- if ($value['modifier'] === '*') {
139
- if ($isAssoc) {
140
- if ($isNestedArray) {
141
- // Nested arrays must allow for deeply nested
142
- // structures.
143
- $var = strtr(
144
- http_build_query([$key => $var]),
145
- $rfc1738to3986
146
- );
147
- } else {
148
- $var = $key . '=' . $var;
149
- }
150
- } elseif ($key > 0 && $actuallyUseQuery) {
151
- $var = $value['value'] . '=' . $var;
152
- }
153
- }
154
-
155
- $kvp[$key] = $var;
156
- }
157
-
158
- if (empty($variable)) {
159
- $actuallyUseQuery = false;
160
- } elseif ($value['modifier'] === '*') {
161
- $expanded = implode($joiner, $kvp);
162
- if ($isAssoc) {
163
- // Don't prepend the value name when using the explode
164
- // modifier with an associative array.
165
- $actuallyUseQuery = false;
166
- }
167
- } else {
168
- if ($isAssoc) {
169
- // When an associative array is encountered and the
170
- // explode modifier is not set, then the result must be
171
- // a comma separated list of keys followed by their
172
- // respective values.
173
- foreach ($kvp as $k => &$v) {
174
- $v = $k . ',' . $v;
175
- }
176
- }
177
- $expanded = implode(',', $kvp);
178
- }
179
- } else {
180
- if ($value['modifier'] === ':') {
181
- $variable = substr($variable, 0, $value['position']);
182
- }
183
- $expanded = rawurlencode($variable);
184
- if ($parsed['operator'] === '+' || $parsed['operator'] === '#') {
185
- $expanded = $this->decodeReserved($expanded);
186
- }
187
- }
188
-
189
- if ($actuallyUseQuery) {
190
- if (!$expanded && $joiner !== '&') {
191
- $expanded = $value['value'];
192
- } else {
193
- $expanded = $value['value'] . '=' . $expanded;
194
- }
195
- }
196
-
197
- $replacements[] = $expanded;
198
- }
199
-
200
- $ret = implode($joiner, $replacements);
201
- if ($ret && $prefix) {
202
- return $prefix . $ret;
203
- }
204
-
205
- return $ret;
206
- }
207
-
208
- /**
209
- * Determines if an array is associative.
210
- *
211
- * This makes the assumption that input arrays are sequences or hashes.
212
- * This assumption is a tradeoff for accuracy in favor of speed, but it
213
- * should work in almost every case where input is supplied for a URI
214
- * template.
215
- *
216
- * @param array $array Array to check
217
- *
218
- * @return bool
219
- */
220
- private function isAssoc(array $array)
221
- {
222
- return $array && array_keys($array)[0] !== 0;
223
- }
224
-
225
- /**
226
- * Removes percent encoding on reserved characters (used with + and #
227
- * modifiers).
228
- *
229
- * @param string $string String to fix
230
- *
231
- * @return string
232
- */
233
- private function decodeReserved($string)
234
- {
235
- return str_replace(self::$delimsPct, self::$delims, $string);
236
- }
237
- }
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ /**
5
+ * Expands URI templates. Userland implementation of PECL uri_template.
6
+ *
7
+ * @link http://tools.ietf.org/html/rfc6570
8
+ */
9
+ class UriTemplate
10
+ {
11
+ /** @var string URI template */
12
+ private $template;
13
+
14
+ /** @var array Variables to use in the template expansion */
15
+ private $variables;
16
+
17
+ /** @var array Hash for quick operator lookups */
18
+ private static $operatorHash = [
19
+ '' => ['prefix' => '', 'joiner' => ',', 'query' => false],
20
+ '+' => ['prefix' => '', 'joiner' => ',', 'query' => false],
21
+ '#' => ['prefix' => '#', 'joiner' => ',', 'query' => false],
22
+ '.' => ['prefix' => '.', 'joiner' => '.', 'query' => false],
23
+ '/' => ['prefix' => '/', 'joiner' => '/', 'query' => false],
24
+ ';' => ['prefix' => ';', 'joiner' => ';', 'query' => true],
25
+ '?' => ['prefix' => '?', 'joiner' => '&', 'query' => true],
26
+ '&' => ['prefix' => '&', 'joiner' => '&', 'query' => true]
27
+ ];
28
+
29
+ /** @var array Delimiters */
30
+ private static $delims = [':', '/', '?', '#', '[', ']', '@', '!', '$',
31
+ '&', '\'', '(', ')', '*', '+', ',', ';', '='];
32
+
33
+ /** @var array Percent encoded delimiters */
34
+ private static $delimsPct = ['%3A', '%2F', '%3F', '%23', '%5B', '%5D',
35
+ '%40', '%21', '%24', '%26', '%27', '%28', '%29', '%2A', '%2B', '%2C',
36
+ '%3B', '%3D'];
37
+
38
+ public function expand($template, array $variables)
39
+ {
40
+ if (false === strpos($template, '{')) {
41
+ return $template;
42
+ }
43
+
44
+ $this->template = $template;
45
+ $this->variables = $variables;
46
+
47
+ return preg_replace_callback(
48
+ '/\{([^\}]+)\}/',
49
+ [$this, 'expandMatch'],
50
+ $this->template
51
+ );
52
+ }
53
+
54
+ /**
55
+ * Parse an expression into parts
56
+ *
57
+ * @param string $expression Expression to parse
58
+ *
59
+ * @return array Returns an associative array of parts
60
+ */
61
+ private function parseExpression($expression)
62
+ {
63
+ $result = [];
64
+
65
+ if (isset(self::$operatorHash[$expression[0]])) {
66
+ $result['operator'] = $expression[0];
67
+ $expression = substr($expression, 1);
68
+ } else {
69
+ $result['operator'] = '';
70
+ }
71
+
72
+ foreach (explode(',', $expression) as $value) {
73
+ $value = trim($value);
74
+ $varspec = [];
75
+ if ($colonPos = strpos($value, ':')) {
76
+ $varspec['value'] = substr($value, 0, $colonPos);
77
+ $varspec['modifier'] = ':';
78
+ $varspec['position'] = (int) substr($value, $colonPos + 1);
79
+ } elseif (substr($value, -1) === '*') {
80
+ $varspec['modifier'] = '*';
81
+ $varspec['value'] = substr($value, 0, -1);
82
+ } else {
83
+ $varspec['value'] = (string) $value;
84
+ $varspec['modifier'] = '';
85
+ }
86
+ $result['values'][] = $varspec;
87
+ }
88
+
89
+ return $result;
90
+ }
91
+
92
+ /**
93
+ * Process an expansion
94
+ *
95
+ * @param array $matches Matches met in the preg_replace_callback
96
+ *
97
+ * @return string Returns the replacement string
98
+ */
99
+ private function expandMatch(array $matches)
100
+ {
101
+ static $rfc1738to3986 = ['+' => '%20', '%7e' => '~'];
102
+
103
+ $replacements = [];
104
+ $parsed = self::parseExpression($matches[1]);
105
+ $prefix = self::$operatorHash[$parsed['operator']]['prefix'];
106
+ $joiner = self::$operatorHash[$parsed['operator']]['joiner'];
107
+ $useQuery = self::$operatorHash[$parsed['operator']]['query'];
108
+
109
+ foreach ($parsed['values'] as $value) {
110
+ if (!isset($this->variables[$value['value']])) {
111
+ continue;
112
+ }
113
+
114
+ $variable = $this->variables[$value['value']];
115
+ $actuallyUseQuery = $useQuery;
116
+ $expanded = '';
117
+
118
+ if (is_array($variable)) {
119
+ $isAssoc = $this->isAssoc($variable);
120
+ $kvp = [];
121
+ foreach ($variable as $key => $var) {
122
+ if ($isAssoc) {
123
+ $key = rawurlencode($key);
124
+ $isNestedArray = is_array($var);
125
+ } else {
126
+ $isNestedArray = false;
127
+ }
128
+
129
+ if (!$isNestedArray) {
130
+ $var = rawurlencode($var);
131
+ if ($parsed['operator'] === '+' ||
132
+ $parsed['operator'] === '#'
133
+ ) {
134
+ $var = $this->decodeReserved($var);
135
+ }
136
+ }
137
+
138
+ if ($value['modifier'] === '*') {
139
+ if ($isAssoc) {
140
+ if ($isNestedArray) {
141
+ // Nested arrays must allow for deeply nested
142
+ // structures.
143
+ $var = strtr(
144
+ http_build_query([$key => $var]),
145
+ $rfc1738to3986
146
+ );
147
+ } else {
148
+ $var = $key . '=' . $var;
149
+ }
150
+ } elseif ($key > 0 && $actuallyUseQuery) {
151
+ $var = $value['value'] . '=' . $var;
152
+ }
153
+ }
154
+
155
+ $kvp[$key] = $var;
156
+ }
157
+
158
+ if (empty($variable)) {
159
+ $actuallyUseQuery = false;
160
+ } elseif ($value['modifier'] === '*') {
161
+ $expanded = implode($joiner, $kvp);
162
+ if ($isAssoc) {
163
+ // Don't prepend the value name when using the explode
164
+ // modifier with an associative array.
165
+ $actuallyUseQuery = false;
166
+ }
167
+ } else {
168
+ if ($isAssoc) {
169
+ // When an associative array is encountered and the
170
+ // explode modifier is not set, then the result must be
171
+ // a comma separated list of keys followed by their
172
+ // respective values.
173
+ foreach ($kvp as $k => &$v) {
174
+ $v = $k . ',' . $v;
175
+ }
176
+ }
177
+ $expanded = implode(',', $kvp);
178
+ }
179
+ } else {
180
+ if ($value['modifier'] === ':') {
181
+ $variable = substr($variable, 0, $value['position']);
182
+ }
183
+ $expanded = rawurlencode($variable);
184
+ if ($parsed['operator'] === '+' || $parsed['operator'] === '#') {
185
+ $expanded = $this->decodeReserved($expanded);
186
+ }
187
+ }
188
+
189
+ if ($actuallyUseQuery) {
190
+ if (!$expanded && $joiner !== '&') {
191
+ $expanded = $value['value'];
192
+ } else {
193
+ $expanded = $value['value'] . '=' . $expanded;
194
+ }
195
+ }
196
+
197
+ $replacements[] = $expanded;
198
+ }
199
+
200
+ $ret = implode($joiner, $replacements);
201
+ if ($ret && $prefix) {
202
+ return $prefix . $ret;
203
+ }
204
+
205
+ return $ret;
206
+ }
207
+
208
+ /**
209
+ * Determines if an array is associative.
210
+ *
211
+ * This makes the assumption that input arrays are sequences or hashes.
212
+ * This assumption is a tradeoff for accuracy in favor of speed, but it
213
+ * should work in almost every case where input is supplied for a URI
214
+ * template.
215
+ *
216
+ * @param array $array Array to check
217
+ *
218
+ * @return bool
219
+ */
220
+ private function isAssoc(array $array)
221
+ {
222
+ return $array && array_keys($array)[0] !== 0;
223
+ }
224
+
225
+ /**
226
+ * Removes percent encoding on reserved characters (used with + and #
227
+ * modifiers).
228
+ *
229
+ * @param string $string String to fix
230
+ *
231
+ * @return string
232
+ */
233
+ private function decodeReserved($string)
234
+ {
235
+ return str_replace(self::$delimsPct, self::$delims, $string);
236
+ }
237
+ }
vendor/guzzlehttp/guzzle/src/functions.php CHANGED
@@ -1,333 +1,333 @@
1
- <?php
2
- namespace GuzzleHttp;
3
-
4
- use GuzzleHttp\Handler\CurlHandler;
5
- use GuzzleHttp\Handler\CurlMultiHandler;
6
- use GuzzleHttp\Handler\Proxy;
7
- use GuzzleHttp\Handler\StreamHandler;
8
-
9
- /**
10
- * Expands a URI template
11
- *
12
- * @param string $template URI template
13
- * @param array $variables Template variables
14
- *
15
- * @return string
16
- */
17
- function uri_template($template, array $variables)
18
- {
19
- if (extension_loaded('uri_template')) {
20
- // @codeCoverageIgnoreStart
21
- return \uri_template($template, $variables);
22
- // @codeCoverageIgnoreEnd
23
- }
24
-
25
- static $uriTemplate;
26
- if (!$uriTemplate) {
27
- $uriTemplate = new UriTemplate();
28
- }
29
-
30
- return $uriTemplate->expand($template, $variables);
31
- }
32
-
33
- /**
34
- * Debug function used to describe the provided value type and class.
35
- *
36
- * @param mixed $input
37
- *
38
- * @return string Returns a string containing the type of the variable and
39
- * if a class is provided, the class name.
40
- */
41
- function describe_type($input)
42
- {
43
- switch (gettype($input)) {
44
- case 'object':
45
- return 'object(' . get_class($input) . ')';
46
- case 'array':
47
- return 'array(' . count($input) . ')';
48
- default:
49
- ob_start();
50
- var_dump($input);
51
- // normalize float vs double
52
- return str_replace('double(', 'float(', rtrim(ob_get_clean()));
53
- }
54
- }
55
-
56
- /**
57
- * Parses an array of header lines into an associative array of headers.
58
- *
59
- * @param array $lines Header lines array of strings in the following
60
- * format: "Name: Value"
61
- * @return array
62
- */
63
- function headers_from_lines($lines)
64
- {
65
- $headers = [];
66
-
67
- foreach ($lines as $line) {
68
- $parts = explode(':', $line, 2);
69
- $headers[trim($parts[0])][] = isset($parts[1])
70
- ? trim($parts[1])
71
- : null;
72
- }
73
-
74
- return $headers;
75
- }
76
-
77
- /**
78
- * Returns a debug stream based on the provided variable.
79
- *
80
- * @param mixed $value Optional value
81
- *
82
- * @return resource
83
- */
84
- function debug_resource($value = null)
85
- {
86
- if (is_resource($value)) {
87
- return $value;
88
- } elseif (defined('STDOUT')) {
89
- return STDOUT;
90
- }
91
-
92
- return fopen('php://output', 'w');
93
- }
94
-
95
- /**
96
- * Chooses and creates a default handler to use based on the environment.
97
- *
98
- * The returned handler is not wrapped by any default middlewares.
99
- *
100
- * @throws \RuntimeException if no viable Handler is available.
101
- * @return callable Returns the best handler for the given system.
102
- */
103
- function choose_handler()
104
- {
105
- $handler = null;
106
- if (function_exists('curl_multi_exec') && function_exists('curl_exec')) {
107
- $handler = Proxy::wrapSync(new CurlMultiHandler(), new CurlHandler());
108
- } elseif (function_exists('curl_exec')) {
109
- $handler = new CurlHandler();
110
- } elseif (function_exists('curl_multi_exec')) {
111
- $handler = new CurlMultiHandler();
112
- }
113
-
114
- if (ini_get('allow_url_fopen')) {
115
- $handler = $handler
116
- ? Proxy::wrapStreaming($handler, new StreamHandler())
117
- : new StreamHandler();
118
- } elseif (!$handler) {
119
- throw new \RuntimeException('GuzzleHttp requires cURL, the '
120
- . 'allow_url_fopen ini setting, or a custom HTTP handler.');
121
- }
122
-
123
- return $handler;
124
- }
125
-
126
- /**
127
- * Get the default User-Agent string to use with Guzzle
128
- *
129
- * @return string
130
- */
131
- function default_user_agent()
132
- {
133
- static $defaultAgent = '';
134
-
135
- if (!$defaultAgent) {
136
- $defaultAgent = 'GuzzleHttp/' . Client::VERSION;
137
- if (extension_loaded('curl') && function_exists('curl_version')) {
138
- $defaultAgent .= ' curl/' . \curl_version()['version'];
139
- }
140
- $defaultAgent .= ' PHP/' . PHP_VERSION;
141
- }
142
-
143
- return $defaultAgent;
144
- }
145
-
146
- /**
147
- * Returns the default cacert bundle for the current system.
148
- *
149
- * First, the openssl.cafile and curl.cainfo php.ini settings are checked.
150
- * If those settings are not configured, then the common locations for
151
- * bundles found on Red Hat, CentOS, Fedora, Ubuntu, Debian, FreeBSD, OS X
152
- * and Windows are checked. If any of these file locations are found on
153
- * disk, they will be utilized.
154
- *
155
- * Note: the result of this function is cached for subsequent calls.
156
- *
157
- * @return string
158
- * @throws \RuntimeException if no bundle can be found.
159
- */
160
- function default_ca_bundle()
161
- {
162
- static $cached = null;
163
- static $cafiles = [
164
- // Red Hat, CentOS, Fedora (provided by the ca-certificates package)
165
- '/etc/pki/tls/certs/ca-bundle.crt',
166
- // Ubuntu, Debian (provided by the ca-certificates package)
167
- '/etc/ssl/certs/ca-certificates.crt',
168
- // FreeBSD (provided by the ca_root_nss package)
169
- '/usr/local/share/certs/ca-root-nss.crt',
170
- // SLES 12 (provided by the ca-certificates package)
171
- '/var/lib/ca-certificates/ca-bundle.pem',
172
- // OS X provided by homebrew (using the default path)
173
- '/usr/local/etc/openssl/cert.pem',
174
- // Google app engine
175
- '/etc/ca-certificates.crt',
176
- // Windows?
177
- 'C:\\windows\\system32\\curl-ca-bundle.crt',
178
- 'C:\\windows\\curl-ca-bundle.crt',
179
- ];
180
-
181
- if ($cached) {
182
- return $cached;
183
- }
184
-
185
- if ($ca = ini_get('openssl.cafile')) {
186
- return $cached = $ca;
187
- }
188
-
189
- if ($ca = ini_get('curl.cainfo')) {
190
- return $cached = $ca;
191
- }
192
-
193
- foreach ($cafiles as $filename) {
194
- if (file_exists($filename)) {
195
- return $cached = $filename;
196
- }
197
- }
198
-
199
- throw new \RuntimeException(<<< EOT
200
- No system CA bundle could be found in any of the the common system locations.
201
- PHP versions earlier than 5.6 are not properly configured to use the system's
202
- CA bundle by default. In order to verify peer certificates, you will need to
203
- supply the path on disk to a certificate bundle to the 'verify' request
204
- option: http://docs.guzzlephp.org/en/latest/clients.html#verify. If you do not
205
- need a specific certificate bundle, then Mozilla provides a commonly used CA
206
- bundle which can be downloaded here (provided by the maintainer of cURL):
207
- https://raw.githubusercontent.com/bagder/ca-bundle/master/ca-bundle.crt. Once
208
- you have a CA bundle available on disk, you can set the 'openssl.cafile' PHP
209
- ini setting to point to the path to the file, allowing you to omit the 'verify'
210
- request option. See http://curl.haxx.se/docs/sslcerts.html for more
211
- information.
212
- EOT
213
- );
214
- }
215
-
216
- /**
217
- * Creates an associative array of lowercase header names to the actual
218
- * header casing.
219
- *
220
- * @param array $headers
221
- *
222
- * @return array
223
- */
224
- function normalize_header_keys(array $headers)
225
- {
226
- $result = [];
227
- foreach (array_keys($headers) as $key) {
228
- $result[strtolower($key)] = $key;
229
- }
230
-
231
- return $result;
232
- }
233
-
234
- /**
235
- * Returns true if the provided host matches any of the no proxy areas.
236
- *
237
- * This method will strip a port from the host if it is present. Each pattern
238
- * can be matched with an exact match (e.g., "foo.com" == "foo.com") or a
239
- * partial match: (e.g., "foo.com" == "baz.foo.com" and ".foo.com" ==
240
- * "baz.foo.com", but ".foo.com" != "foo.com").
241
- *
242
- * Areas are matched in the following cases:
243
- * 1. "*" (without quotes) always matches any hosts.
244
- * 2. An exact match.
245
- * 3. The area starts with "." and the area is the last part of the host. e.g.
246
- * '.mit.edu' will match any host that ends with '.mit.edu'.
247
- *
248
- * @param string $host Host to check against the patterns.
249
- * @param array $noProxyArray An array of host patterns.
250
- *
251
- * @return bool
252
- */
253
- function is_host_in_noproxy($host, array $noProxyArray)
254
- {
255
- if (strlen($host) === 0) {
256
- throw new \InvalidArgumentException('Empty host provided');
257
- }
258
-
259
- // Strip port if present.
260
- if (strpos($host, ':')) {
261
- $host = explode($host, ':', 2)[0];
262
- }
263
-
264
- foreach ($noProxyArray as $area) {
265
- // Always match on wildcards.
266
- if ($area === '*') {
267
- return true;
268
- } elseif (empty($area)) {
269
- // Don't match on empty values.
270
- continue;
271
- } elseif ($area === $host) {
272
- // Exact matches.
273
- return true;
274
- } else {
275
- // Special match if the area when prefixed with ".". Remove any
276
- // existing leading "." and add a new leading ".".
277
- $area = '.' . ltrim($area, '.');
278
- if (substr($host, -(strlen($area))) === $area) {
279
- return true;
280
- }
281
- }
282
- }
283
-
284
- return false;
285
- }
286
-
287
- /**
288
- * Wrapper for json_decode that throws when an error occurs.
289
- *
290
- * @param string $json JSON data to parse
291
- * @param bool $assoc When true, returned objects will be converted
292
- * into associative arrays.
293
- * @param int $depth User specified recursion depth.
294
- * @param int $options Bitmask of JSON decode options.
295
- *
296
- * @return mixed
297
- * @throws \InvalidArgumentException if the JSON cannot be decoded.
298
- * @link http://www.php.net/manual/en/function.json-decode.php
299
- */
300
- function json_decode($json, $assoc = false, $depth = 512, $options = 0)
301
- {
302
- $data = \json_decode($json, $assoc, $depth, $options);
303
- if (JSON_ERROR_NONE !== json_last_error()) {
304
- throw new \InvalidArgumentException(
305
- 'json_decode error: ' . json_last_error_msg()
306
- );
307
- }
308
-
309
- return $data;
310
- }
311
-
312
- /**
313
- * Wrapper for JSON encoding that throws when an error occurs.
314
- *
315
- * @param mixed $value The value being encoded
316
- * @param int $options JSON encode option bitmask
317
- * @param int $depth Set the maximum depth. Must be greater than zero.
318
- *
319
- * @return string
320
- * @throws \InvalidArgumentException if the JSON cannot be encoded.
321
- * @link http://www.php.net/manual/en/function.json-encode.php
322
- */
323
- function json_encode($value, $options = 0, $depth = 512)
324
- {
325
- $json = \json_encode($value, $options, $depth);
326
- if (JSON_ERROR_NONE !== json_last_error()) {
327
- throw new \InvalidArgumentException(
328
- 'json_encode error: ' . json_last_error_msg()
329
- );
330
- }
331
-
332
- return $json;
333
- }
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ use GuzzleHttp\Handler\CurlHandler;
5
+ use GuzzleHttp\Handler\CurlMultiHandler;
6
+ use GuzzleHttp\Handler\Proxy;
7
+ use GuzzleHttp\Handler\StreamHandler;
8
+
9
+ /**
10
+ * Expands a URI template
11
+ *
12
+ * @param string $template URI template
13
+ * @param array $variables Template variables
14
+ *
15
+ * @return string
16
+ */
17
+ function uri_template($template, array $variables)
18
+ {
19
+ if (extension_loaded('uri_template')) {
20
+ // @codeCoverageIgnoreStart
21
+ return \uri_template($template, $variables);
22
+ // @codeCoverageIgnoreEnd
23
+ }
24
+
25
+ static $uriTemplate;
26
+ if (!$uriTemplate) {
27
+ $uriTemplate = new UriTemplate();
28
+ }
29
+
30
+ return $uriTemplate->expand($template, $variables);
31
+ }
32
+
33
+ /**
34
+ * Debug function used to describe the provided value type and class.
35
+ *
36
+ * @param mixed $input
37
+ *
38
+ * @return string Returns a string containing the type of the variable and
39
+ * if a class is provided, the class name.
40
+ */
41
+ function describe_type($input)
42
+ {
43
+ switch (gettype($input)) {
44
+ case 'object':
45
+ return 'object(' . get_class($input) . ')';
46
+ case 'array':
47
+ return 'array(' . count($input) . ')';
48
+ default:
49
+ ob_start();
50
+ var_dump($input);
51
+ // normalize float vs double
52
+ return str_replace('double(', 'float(', rtrim(ob_get_clean()));
53
+ }
54
+ }
55
+
56
+ /**
57
+ * Parses an array of header lines into an associative array of headers.
58
+ *
59
+ * @param array $lines Header lines array of strings in the following
60
+ * format: "Name: Value"
61
+ * @return array
62
+ */
63
+ function headers_from_lines($lines)
64
+ {
65
+ $headers = [];
66
+
67
+ foreach ($lines as $line) {
68
+ $parts = explode(':', $line, 2);
69
+ $headers[trim($parts[0])][] = isset($parts[1])
70
+ ? trim($parts[1])
71
+ : null;
72
+ }
73
+
74
+ return $headers;
75
+ }
76
+
77
+ /**
78
+ * Returns a debug stream based on the provided variable.
79
+ *
80
+ * @param mixed $value Optional value
81
+ *
82
+ * @return resource
83
+ */
84
+ function debug_resource($value = null)
85
+ {
86
+ if (is_resource($value)) {
87
+ return $value;
88
+ } elseif (defined('STDOUT')) {
89
+ return STDOUT;
90
+ }
91
+
92
+ return fopen('php://output', 'w');
93
+ }
94
+
95
+ /**
96
+ * Chooses and creates a default handler to use based on the environment.
97
+ *
98
+ * The returned handler is not wrapped by any default middlewares.
99
+ *
100
+ * @throws \RuntimeException if no viable Handler is available.
101
+ * @return callable Returns the best handler for the given system.
102
+ */
103
+ function choose_handler()
104
+ {
105
+ $handler = null;
106
+ if (function_exists('curl_multi_exec') && function_exists('curl_exec')) {
107
+ $handler = Proxy::wrapSync(new CurlMultiHandler(), new CurlHandler());
108
+ } elseif (function_exists('curl_exec')) {
109
+ $handler = new CurlHandler();
110
+ } elseif (function_exists('curl_multi_exec')) {
111
+ $handler = new CurlMultiHandler();
112
+ }
113
+
114
+ if (ini_get('allow_url_fopen')) {
115
+ $handler = $handler
116
+ ? Proxy::wrapStreaming($handler, new StreamHandler())
117
+ : new StreamHandler();
118
+ } elseif (!$handler) {
119
+ throw new \RuntimeException('GuzzleHttp requires cURL, the '
120
+ . 'allow_url_fopen ini setting, or a custom HTTP handler.');
121
+ }
122
+
123
+ return $handler;
124
+ }
125
+
126
+ /**
127
+ * Get the default User-Agent string to use with Guzzle
128
+ *
129
+ * @return string
130
+ */
131
+ function default_user_agent()
132
+ {
133
+ static $defaultAgent = '';
134
+
135
+ if (!$defaultAgent) {
136
+ $defaultAgent = 'GuzzleHttp/' . Client::VERSION;
137
+ if (extension_loaded('curl') && function_exists('curl_version')) {
138
+ $defaultAgent .= ' curl/' . \curl_version()['version'];
139
+ }
140
+ $defaultAgent .= ' PHP/' . PHP_VERSION;
141
+ }
142
+
143
+ return $defaultAgent;
144
+ }
145
+
146
+ /**
147
+ * Returns the default cacert bundle for the current system.
148
+ *
149
+ * First, the openssl.cafile and curl.cainfo php.ini settings are checked.
150
+ * If those settings are not configured, then the common locations for
151
+ * bundles found on Red Hat, CentOS, Fedora, Ubuntu, Debian, FreeBSD, OS X
152
+ * and Windows are checked. If any of these file locations are found on
153
+ * disk, they will be utilized.
154
+ *
155
+ * Note: the result of this function is cached for subsequent calls.
156
+ *
157
+ * @return string
158
+ * @throws \RuntimeException if no bundle can be found.
159
+ */
160
+ function default_ca_bundle()
161
+ {
162
+ static $cached = null;
163
+ static $cafiles = [
164
+ // Red Hat, CentOS, Fedora (provided by the ca-certificates package)
165
+ '/etc/pki/tls/certs/ca-bundle.crt',
166
+ // Ubuntu, Debian (provided by the ca-certificates package)
167
+ '/etc/ssl/certs/ca-certificates.crt',
168
+ // FreeBSD (provided by the ca_root_nss package)
169
+ '/usr/local/share/certs/ca-root-nss.crt',
170
+ // SLES 12 (provided by the ca-certificates package)
171
+ '/var/lib/ca-certificates/ca-bundle.pem',
172
+ // OS X provided by homebrew (using the default path)
173
+ '/usr/local/etc/openssl/cert.pem',
174
+ // Google app engine
175
+ '/etc/ca-certificates.crt',
176
+ // Windows?
177
+ 'C:\\windows\\system32\\curl-ca-bundle.crt',
178
+ 'C:\\windows\\curl-ca-bundle.crt',
179
+ ];
180
+
181
+ if ($cached) {
182
+ return $cached;
183
+ }
184
+
185
+ if ($ca = ini_get('openssl.cafile')) {
186
+ return $cached = $ca;
187
+ }
188
+
189
+ if ($ca = ini_get('curl.cainfo')) {
190
+ return $cached = $ca;
191
+ }
192
+
193
+ foreach ($cafiles as $filename) {
194
+ if (file_exists($filename)) {
195
+ return $cached = $filename;
196
+ }
197
+ }
198
+
199
+ throw new \RuntimeException(<<< EOT
200
+ No system CA bundle could be found in any of the the common system locations.
201
+ PHP versions earlier than 5.6 are not properly configured to use the system's
202
+ CA bundle by default. In order to verify peer certificates, you will need to
203
+ supply the path on disk to a certificate bundle to the 'verify' request
204
+ option: http://docs.guzzlephp.org/en/latest/clients.html#verify. If you do not
205
+ need a specific certificate bundle, then Mozilla provides a commonly used CA
206
+ bundle which can be downloaded here (provided by the maintainer of cURL):
207
+ https://raw.githubusercontent.com/bagder/ca-bundle/master/ca-bundle.crt. Once
208
+ you have a CA bundle available on disk, you can set the 'openssl.cafile' PHP
209
+ ini setting to point to the path to the file, allowing you to omit the 'verify'
210
+ request option. See http://curl.haxx.se/docs/sslcerts.html for more
211
+ information.
212
+ EOT
213
+ );
214
+ }
215
+
216
+ /**
217
+ * Creates an associative array of lowercase header names to the actual
218
+ * header casing.
219
+ *
220
+ * @param array $headers
221
+ *
222
+ * @return array
223
+ */
224
+ function normalize_header_keys(array $headers)
225
+ {
226
+ $result = [];
227
+ foreach (array_keys($headers) as $key) {
228
+ $result[strtolower($key)] = $key;
229
+ }
230
+
231
+ return $result;
232
+ }
233
+
234
+ /**
235
+ * Returns true if the provided host matches any of the no proxy areas.
236
+ *
237
+ * This method will strip a port from the host if it is present. Each pattern
238
+ * can be matched with an exact match (e.g., "foo.com" == "foo.com") or a
239
+ * partial match: (e.g., "foo.com" == "baz.foo.com" and ".foo.com" ==
240
+ * "baz.foo.com", but ".foo.com" != "foo.com").
241
+ *
242
+ * Areas are matched in the following cases:
243
+ * 1. "*" (without quotes) always matches any hosts.
244
+ * 2. An exact match.
245
+ * 3. The area starts with "." and the area is the last part of the host. e.g.
246
+ * '.mit.edu' will match any host that ends with '.mit.edu'.
247
+ *
248
+ * @param string $host Host to check against the patterns.
249
+ * @param array $noProxyArray An array of host patterns.
250
+ *
251
+ * @return bool
252
+ */
253
+ function is_host_in_noproxy($host, array $noProxyArray)
254
+ {
255
+ if (strlen($host) === 0) {
256
+ throw new \InvalidArgumentException('Empty host provided');
257
+ }
258
+
259
+ // Strip port if present.
260
+ if (strpos($host, ':')) {
261
+ $host = explode($host, ':', 2)[0];
262
+ }
263
+
264
+ foreach ($noProxyArray as $area) {
265
+ // Always match on wildcards.
266
+ if ($area === '*') {
267
+ return true;
268
+ } elseif (empty($area)) {
269
+ // Don't match on empty values.
270
+ continue;
271
+ } elseif ($area === $host) {
272
+ // Exact matches.
273
+ return true;
274
+ } else {
275
+ // Special match if the area when prefixed with ".". Remove any
276
+ // existing leading "." and add a new leading ".".
277
+ $area = '.' . ltrim($area, '.');
278
+ if (substr($host, -(strlen($area))) === $area) {
279
+ return true;
280
+ }
281
+ }
282
+ }
283
+
284
+ return false;
285
+ }
286
+
287
+ /**
288
+ * Wrapper for json_decode that throws when an error occurs.
289
+ *
290
+ * @param string $json JSON data to parse
291
+ * @param bool $assoc When true, returned objects will be converted
292
+ * into associative arrays.
293
+ * @param int $depth User specified recursion depth.
294
+ * @param int $options Bitmask of JSON decode options.
295
+ *
296
+ * @return mixed
297
+ * @throws \InvalidArgumentException if the JSON cannot be decoded.
298
+ * @link http://www.php.net/manual/en/function.json-decode.php
299
+ */
300
+ function json_decode($json, $assoc = false, $depth = 512, $options = 0)
301
+ {
302
+ $data = \json_decode($json, $assoc, $depth, $options);
303
+ if (JSON_ERROR_NONE !== json_last_error()) {
304
+ throw new \InvalidArgumentException(
305
+ 'json_decode error: ' . json_last_error_msg()
306
+ );
307
+ }
308
+
309
+ return $data;
310
+ }
311
+
312
+ /**
313
+ * Wrapper for JSON encoding that throws when an error occurs.
314
+ *
315
+ * @param mixed $value The value being encoded
316
+ * @param int $options JSON encode option bitmask
317
+ * @param int $depth Set the maximum depth. Must be greater than zero.
318
+ *
319
+ * @return string
320
+ * @throws \InvalidArgumentException if the JSON cannot be encoded.
321
+ * @link http://www.php.net/manual/en/function.json-encode.php
322
+ */
323
+ function json_encode($value, $options = 0, $depth = 512)
324
+ {
325
+ $json = \json_encode($value, $options, $depth);
326
+ if (JSON_ERROR_NONE !== json_last_error()) {
327
+ throw new \InvalidArgumentException(
328
+ 'json_encode error: ' . json_last_error_msg()
329
+ );
330
+ }
331
+
332
+ return $json;
333
+ }
vendor/guzzlehttp/guzzle/src/functions_include.php CHANGED
@@ -1,6 +1,6 @@
1
- <?php
2
-
3
- // Don't redefine the functions if included multiple times.
4
- if (!function_exists('GuzzleHttp\uri_template')) {
5
- require __DIR__ . '/functions.php';
6
- }
1
+ <?php
2
+
3
+ // Don't redefine the functions if included multiple times.
4
+ if (!function_exists('GuzzleHttp\uri_template')) {
5
+ require __DIR__ . '/functions.php';
6
+ }
vendor/phpseclib/phpseclib/LICENSE CHANGED
@@ -1,21 +1,20 @@
1
- Copyright 2007-2016 TerraFrost and other contributors
2
- http://phpseclib.sourceforge.net/
3
-
4
- Permission is hereby granted, free of charge, to any person obtaining
5
- a copy of this software and associated documentation files (the
6
- "Software"), to deal in the Software without restriction, including
7
- without limitation the rights to use, copy, modify, merge, publish,
8
- distribute, sublicense, and/or sell copies of the Software, and to
9
- permit persons to whom the Software is furnished to do so, subject to
10
- the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be
13
- included in all copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1
+ Copyright (c) 2011-2019 TerraFrost and other contributors
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
vendor/phpseclib/phpseclib/phpseclib/Crypt/AES.php CHANGED
@@ -1,126 +1,126 @@
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 version 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 \phpseclib\Crypt\AES extends \phpseclib\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 'vendor/autoload.php';
27
- *
28
- * $aes = new \phpseclib\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
- * @category Crypt
43
- * @package AES
44
- * @author Jim Wigginton <terrafrost@php.net>
45
- * @copyright 2008 Jim Wigginton
46
- * @license http://www.opensource.org/licenses/mit-license.html MIT License
47
- * @link http://phpseclib.sourceforge.net
48
- */
49
-
50
- namespace phpseclib\Crypt;
51
-
52
- /**
53
- * Pure-PHP implementation of AES.
54
- *
55
- * @package AES
56
- * @author Jim Wigginton <terrafrost@php.net>
57
- * @access public
58
- */
59
- class AES extends Rijndael
60
- {
61
- /**
62
- * Dummy function
63
- *
64
- * Since \phpseclib\Crypt\AES extends \phpseclib\Crypt\Rijndael, this function is, technically, available, but it doesn't do anything.
65
- *
66
- * @see \phpseclib\Crypt\Rijndael::setBlockLength()
67
- * @access public
68
- * @param int $length
69
- */
70
- function setBlockLength($length)
71
- {
72
- return;
73
- }
74
-
75
- /**
76
- * Sets the key length
77
- *
78
- * Valid key lengths are 128, 192, and 256. If the length is less than 128, it will be rounded up to
79
- * 128. If the length is greater than 128 and invalid, it will be rounded down to the closest valid amount.
80
- *
81
- * @see \phpseclib\Crypt\Rijndael:setKeyLength()
82
- * @access public
83
- * @param int $length
84
- */
85
- function setKeyLength($length)
86
- {
87
- switch ($length) {
88
- case 160:
89
- $length = 192;
90
- break;
91
- case 224:
92
- $length = 256;
93
- }
94
- parent::setKeyLength($length);
95
- }
96
-
97
- /**
98
- * Sets the key.
99
- *
100
- * Rijndael supports five different key lengths, AES only supports three.
101
- *
102
- * @see \phpseclib\Crypt\Rijndael:setKey()
103
- * @see setKeyLength()
104
- * @access public
105
- * @param string $key
106
- */
107
- function setKey($key)
108
- {
109
- parent::setKey($key);
110
-
111
- if (!$this->explicit_key_length) {
112
- $length = strlen($key);
113
- switch (true) {
114
- case $length <= 16:
115
- $this->key_length = 16;
116
- break;
117
- case $length <= 24:
118
- $this->key_length = 24;
119
- break;
120
- default:
121
- $this->key_length = 32;
122
- }
123
- $this->_setEngine();
124
- }
125
- }
126
- }
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 version 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 \phpseclib\Crypt\AES extends \phpseclib\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 'vendor/autoload.php';
27
+ *
28
+ * $aes = new \phpseclib\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
+ * @category Crypt
43
+ * @package AES
44
+ * @author Jim Wigginton <terrafrost@php.net>
45
+ * @copyright 2008 Jim Wigginton
46
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
47
+ * @link http://phpseclib.sourceforge.net
48
+ */
49
+
50
+ namespace phpseclib\Crypt;
51
+
52
+ /**
53
+ * Pure-PHP implementation of AES.
54
+ *
55
+ * @package AES
56
+ * @author Jim Wigginton <terrafrost@php.net>
57
+ * @access public
58
+ */
59
+ class AES extends Rijndael
60
+ {
61
+ /**
62
+ * Dummy function
63
+ *
64
+ * Since \phpseclib\Crypt\AES extends \phpseclib\Crypt\Rijndael, this function is, technically, available, but it doesn't do anything.
65
+ *
66
+ * @see \phpseclib\Crypt\Rijndael::setBlockLength()
67
+ * @access public
68
+ * @param int $length
69
+ */
70
+ function setBlockLength($length)
71
+ {
72
+ return;
73
+ }
74
+
75
+ /**
76
+ * Sets the key length
77
+ *
78
+ * Valid key lengths are 128, 192, and 256. If the length is less than 128, it will be rounded up to
79
+ * 128. If the length is greater than 128 and invalid, it will be rounded down to the closest valid amount.
80
+ *
81
+ * @see \phpseclib\Crypt\Rijndael:setKeyLength()
82
+ * @access public
83
+ * @param int $length
84
+ */
85
+ function setKeyLength($length)
86
+ {
87
+ switch ($length) {
88
+ case 160:
89
+ $length = 192;
90
+ break;
91
+ case 224:
92
+ $length = 256;
93
+ }
94
+ parent::setKeyLength($length);
95
+ }
96
+
97
+ /**
98
+ * Sets the key.
99
+ *
100
+ * Rijndael supports five different key lengths, AES only supports three.
101
+ *
102
+ * @see \phpseclib\Crypt\Rijndael:setKey()
103
+ * @see setKeyLength()
104
+ * @access public
105
+ * @param string $key
106
+ */
107
+ function setKey($key)
108
+ {
109
+ parent::setKey($key);
110
+
111
+ if (!$this->explicit_key_length) {
112
+ $length = strlen($key);
113
+ switch (true) {
114
+ case $length <= 16:
115
+ $this->key_length = 16;
116
+ break;
117
+ case $length <= 24:
118
+ $this->key_length = 24;
119
+ break;
120
+ default:
121
+ $this->key_length = 32;
122
+ }
123
+ $this->_setEngine();
124
+ }
125
+ }
126
+ }
vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA.php CHANGED
@@ -1,3201 +1,3201 @@
1
- <?php
2
-
3
- /**
4
- * Pure-PHP PKCS#1 (v2.1) compliant implementation of RSA.
5
- *
6
- * PHP version 5
7
- *
8
- * Here's an example of how to encrypt and decrypt text with this library:
9
- * <code>
10
- * <?php
11
- * include 'vendor/autoload.php';
12
- *
13
- * $rsa = new \phpseclib\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 'vendor/autoload.php';
30
- *
31
- * $rsa = new \phpseclib\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
- * @category Crypt
45
- * @package RSA
46
- * @author Jim Wigginton <terrafrost@php.net>
47
- * @copyright 2009 Jim Wigginton
48
- * @license http://www.opensource.org/licenses/mit-license.html MIT License
49
- * @link http://phpseclib.sourceforge.net
50
- */
51
-
52
- namespace phpseclib\Crypt;
53
-
54
- use phpseclib\Math\BigInteger;
55
-
56
- /**
57
- * Pure-PHP PKCS#1 compliant implementation of RSA.
58
- *
59
- * @package RSA
60
- * @author Jim Wigginton <terrafrost@php.net>
61
- * @access public
62
- */
63
- class RSA
64
- {
65
- /**#@+
66
- * @access public
67
- * @see self::encrypt()
68
- * @see self::decrypt()
69
- */
70
- /**
71
- * Use {@link http://en.wikipedia.org/wiki/Optimal_Asymmetric_Encryption_Padding Optimal Asymmetric Encryption Padding}
72
- * (OAEP) for encryption / decryption.
73
- *
74
- * Uses sha1 by default.
75
- *
76
- * @see self::setHash()
77
- * @see self::setMGFHash()
78
- */
79
- const ENCRYPTION_OAEP = 1;
80
- /**
81
- * Use PKCS#1 padding.
82
- *
83
- * Although self::ENCRYPTION_OAEP offers more security, including PKCS#1 padding is necessary for purposes of backwards
84
- * compatibility with protocols (like SSH-1) written before OAEP's introduction.
85
- */
86
- const ENCRYPTION_PKCS1 = 2;
87
- /**
88
- * Do not use any padding
89
- *
90
- * Although this method is not recommended it can none-the-less sometimes be useful if you're trying to decrypt some legacy
91
- * stuff, if you're trying to diagnose why an encrypted message isn't decrypting, etc.
92
- */
93
- const ENCRYPTION_NONE = 3;
94
- /**#@-*/
95
-
96
- /**#@+
97
- * @access public
98
- * @see self::sign()
99
- * @see self::verify()
100
- * @see self::setHash()
101
- */
102
- /**
103
- * Use the Probabilistic Signature Scheme for signing
104
- *
105
- * Uses sha1 by default.
106
- *
107
- * @see self::setSaltLength()
108
- * @see self::setMGFHash()
109
- */
110
- const SIGNATURE_PSS = 1;
111
- /**
112
- * Use the PKCS#1 scheme by default.
113
- *
114
- * Although self::SIGNATURE_PSS offers more security, including PKCS#1 signing is necessary for purposes of backwards
115
- * compatibility with protocols (like SSH-2) written before PSS's introduction.
116
- */
117
- const SIGNATURE_PKCS1 = 2;
118
- /**#@-*/
119
-
120
- /**#@+
121
- * @access private
122
- * @see \phpseclib\Crypt\RSA::createKey()
123
- */
124
- /**
125
- * ASN1 Integer
126
- */
127
- const ASN1_INTEGER = 2;
128
- /**
129
- * ASN1 Bit String
130
- */
131
- const ASN1_BITSTRING = 3;
132
- /**
133
- * ASN1 Octet String
134
- */
135
- const ASN1_OCTETSTRING = 4;
136
- /**
137
- * ASN1 Object Identifier
138
- */
139
- const ASN1_OBJECT = 6;
140
- /**
141
- * ASN1 Sequence (with the constucted bit set)
142
- */
143
- const ASN1_SEQUENCE = 48;
144
- /**#@-*/
145
-
146
- /**#@+
147
- * @access private
148
- * @see \phpseclib\Crypt\RSA::__construct()
149
- */
150
- /**
151
- * To use the pure-PHP implementation
152
- */
153
- const MODE_INTERNAL = 1;
154
- /**
155
- * To use the OpenSSL library
156
- *
157
- * (if enabled; otherwise, the internal implementation will be used)
158
- */
159
- const MODE_OPENSSL = 2;
160
- /**#@-*/
161
-
162
- /**#@+
163
- * @access public
164
- * @see \phpseclib\Crypt\RSA::createKey()
165
- * @see \phpseclib\Crypt\RSA::setPrivateKeyFormat()
166
- */
167
- /**
168
- * PKCS#1 formatted private key
169
- *
170
- * Used by OpenSSH
171
- */
172
- const PRIVATE_FORMAT_PKCS1 = 0;
173
- /**
174
- * PuTTY formatted private key
175
- */
176
- const PRIVATE_FORMAT_PUTTY = 1;
177
- /**
178
- * XML formatted private key
179
- */
180
- const PRIVATE_FORMAT_XML = 2;
181
- /**
182
- * PKCS#8 formatted private key
183
- */
184
- const PRIVATE_FORMAT_PKCS8 = 8;
185
- /**
186
- * OpenSSH formatted private key
187
- */
188
- const PRIVATE_FORMAT_OPENSSH = 9;
189
- /**#@-*/
190
-
191
- /**#@+
192
- * @access public
193
- * @see \phpseclib\Crypt\RSA::createKey()
194
- * @see \phpseclib\Crypt\RSA::setPublicKeyFormat()
195
- */
196
- /**
197
- * Raw public key
198
- *
199
- * An array containing two \phpseclib\Math\BigInteger objects.
200
- *
201
- * The exponent can be indexed with any of the following:
202
- *
203
- * 0, e, exponent, publicExponent
204
- *
205
- * The modulus can be indexed with any of the following:
206
- *
207
- * 1, n, modulo, modulus
208
- */
209
- const PUBLIC_FORMAT_RAW = 3;
210
- /**
211
- * PKCS#1 formatted public key (raw)
212
- *
213
- * Used by File/X509.php
214
- *
215
- * Has the following header:
216
- *
217
- * -----BEGIN RSA PUBLIC KEY-----
218
- *
219
- * Analogous to ssh-keygen's pem format (as specified by -m)
220
- */
221
- const PUBLIC_FORMAT_PKCS1 = 4;
222
- const PUBLIC_FORMAT_PKCS1_RAW = 4;
223
- /**
224
- * XML formatted public key
225
- */
226
- const PUBLIC_FORMAT_XML = 5;
227
- /**
228
- * OpenSSH formatted public key
229
- *
230
- * Place in $HOME/.ssh/authorized_keys
231
- */
232
- const PUBLIC_FORMAT_OPENSSH = 6;
233
- /**
234
- * PKCS#1 formatted public key (encapsulated)
235
- *
236
- * Used by PHP's openssl_public_encrypt() and openssl's rsautl (when -pubin is set)
237
- *
238
- * Has the following header:
239
- *
240
- * -----BEGIN PUBLIC KEY-----
241
- *
242
- * Analogous to ssh-keygen's pkcs8 format (as specified by -m). Although PKCS8
243
- * is specific to private keys it's basically creating a DER-encoded wrapper
244
- * for keys. This just extends that same concept to public keys (much like ssh-keygen)
245
- */
246
- const PUBLIC_FORMAT_PKCS8 = 7;
247
- /**#@-*/
248
-
249
- /**
250
- * Precomputed Zero
251
- *
252
- * @var \phpseclib\Math\BigInteger
253
- * @access private
254
- */
255
- var $zero;
256
-
257
- /**
258
- * Precomputed One
259
- *
260
- * @var \phpseclib\Math\BigInteger
261
- * @access private
262
- */
263
- var $one;
264
-
265
- /**
266
- * Private Key Format
267
- *
268
- * @var int
269
- * @access private
270
- */
271
- var $privateKeyFormat = self::PRIVATE_FORMAT_PKCS1;
272
-
273
- /**
274
- * Public Key Format
275
- *
276
- * @var int
277
- * @access public
278
- */
279
- var $publicKeyFormat = self::PUBLIC_FORMAT_PKCS8;
280
-
281
- /**
282
- * Modulus (ie. n)
283
- *
284
- * @var \phpseclib\Math\BigInteger
285
- * @access private
286
- */
287
- var $modulus;
288
-
289
- /**
290
- * Modulus length
291
- *
292
- * @var \phpseclib\Math\BigInteger
293
- * @access private
294
- */
295
- var $k;
296
-
297
- /**
298
- * Exponent (ie. e or d)
299
- *
300
- * @var \phpseclib\Math\BigInteger
301
- * @access private
302
- */
303
- var $exponent;
304
-
305
- /**
306
- * Primes for Chinese Remainder Theorem (ie. p and q)
307
- *
308
- * @var array
309
- * @access private
310
- */
311
- var $primes;
312
-
313
- /**
314
- * Exponents for Chinese Remainder Theorem (ie. dP and dQ)
315
- *
316
- * @var array
317
- * @access private
318
- */
319
- var $exponents;
320
-
321
- /**
322
- * Coefficients for Chinese Remainder Theorem (ie. qInv)
323
- *
324
- * @var array
325
- * @access private
326
- */
327
- var $coefficients;
328
-
329
- /**
330
- * Hash name
331
- *
332
- * @var string
333
- * @access private
334
- */
335
- var $hashName;
336
-
337
- /**
338
- * Hash function
339
- *
340
- * @var \phpseclib\Crypt\Hash
341
- * @access private
342
- */
343
- var $hash;
344
-
345
- /**
346
- * Length of hash function output
347
- *
348
- * @var int
349
- * @access private
350
- */
351
- var $hLen;
352
-
353
- /**
354
- * Length of salt
355
- *
356
- * @var int
357
- * @access private
358
- */
359
- var $sLen;
360
-
361
- /**
362
- * Hash function for the Mask Generation Function
363
- *
364
- * @var \phpseclib\Crypt\Hash
365
- * @access private
366
- */
367
- var $mgfHash;
368
-
369
- /**
370
- * Length of MGF hash function output
371
- *
372
- * @var int
373
- * @access private
374
- */
375
- var $mgfHLen;
376
-
377
- /**
378
- * Encryption mode
379
- *
380
- * @var int
381
- * @access private
382
- */
383
- var $encryptionMode = self::ENCRYPTION_OAEP;
384
-
385
- /**
386
- * Signature mode
387
- *
388
- * @var int
389
- * @access private
390
- */
391
- var $signatureMode = self::SIGNATURE_PSS;
392
-
393
- /**
394
- * Public Exponent
395
- *
396
- * @var mixed
397
- * @access private
398
- */
399
- var $publicExponent = false;
400
-
401
- /**
402
- * Password
403
- *
404
- * @var string
405
- * @access private
406
- */
407
- var $password = false;
408
-
409
- /**
410
- * Components
411
- *
412
- * For use with parsing XML formatted keys. PHP's XML Parser functions use utilized - instead of PHP's DOM functions -
413
- * because PHP's XML Parser functions work on PHP4 whereas PHP's DOM functions - although surperior - don't.
414
- *
415
- * @see self::_start_element_handler()
416
- * @var array
417
- * @access private
418
- */
419
- var $components = array();
420
-
421
- /**
422
- * Current String
423
- *
424
- * For use with parsing XML formatted keys.
425
- *
426
- * @see self::_character_handler()
427
- * @see self::_stop_element_handler()
428
- * @var mixed
429
- * @access private
430
- */
431
- var $current;
432
-
433
- /**
434
- * OpenSSL configuration file name.
435
- *
436
- * Set to null to use system configuration file.
437
- * @see self::createKey()
438
- * @var mixed
439
- * @Access public
440
- */
441
- var $configFile;
442
-
443
- /**
444
- * Public key comment field.
445
- *
446
- * @var string
447
- * @access private
448
- */
449
- var $comment = 'phpseclib-generated-key';
450
-
451
- /**
452
- * The constructor
453
- *
454
- * If you want to make use of the openssl extension, you'll need to set the mode manually, yourself. The reason
455
- * \phpseclib\Crypt\RSA doesn't do it is because OpenSSL doesn't fail gracefully. openssl_pkey_new(), in particular, requires
456
- * openssl.cnf be present somewhere and, unfortunately, the only real way to find out is too late.
457
- *
458
- * @return \phpseclib\Crypt\RSA
459
- * @access public
460
- */
461
- function __construct()
462
- {
463
- $this->configFile = dirname(__FILE__) . '/../openssl.cnf';
464
-
465
- if (!defined('CRYPT_RSA_MODE')) {
466
- switch (true) {
467
- // Math/BigInteger's openssl requirements are a little less stringent than Crypt/RSA's. in particular,
468
- // Math/BigInteger doesn't require an openssl.cfg file whereas Crypt/RSA does. so if Math/BigInteger
469
- // can't use OpenSSL it can be pretty trivially assumed, then, that Crypt/RSA can't either.
470
- case defined('MATH_BIGINTEGER_OPENSSL_DISABLE'):
471
- define('CRYPT_RSA_MODE', self::MODE_INTERNAL);
472
- break;
473
- case extension_loaded('openssl') && file_exists($this->configFile):
474
- // some versions of XAMPP have mismatched versions of OpenSSL which causes it not to work
475
- $versions = array();
476
-
477
- // avoid generating errors (even with suppression) when phpinfo() is disabled (common in production systems)
478
- if (strpos(ini_get('disable_functions'), 'phpinfo') === false) {
479
- ob_start();
480
- @phpinfo();
481
- $content = ob_get_contents();
482
- ob_end_clean();
483
-
484
- preg_match_all('#OpenSSL (Header|Library) Version(.*)#im', $content, $matches);
485
-
486
- if (!empty($matches[1])) {
487
- for ($i = 0; $i < count($matches[1]); $i++) {
488
- $fullVersion = trim(str_replace('=>', '', strip_tags($matches[2][$i])));
489
-
490
- // Remove letter part in OpenSSL version
491
- if (!preg_match('/(\d+\.\d+\.\d+)/i', $fullVersion, $m)) {
492
- $versions[$matches[1][$i]] = $fullVersion;
493
- } else {
494
- $versions[$matches[1][$i]] = $m[0];
495
- }
496
- }
497
- }
498
- }
499
-
500
- // it doesn't appear that OpenSSL versions were reported upon until PHP 5.3+
501
- switch (true) {
502
- case !isset($versions['Header']):
503
- case !isset($versions['Library']):
504
- case $versions['Header'] == $versions['Library']:
505
- case version_compare($versions['Header'], '1.0.0') >= 0 && version_compare($versions['Library'], '1.0.0') >= 0:
506
- define('CRYPT_RSA_MODE', self::MODE_OPENSSL);
507
- break;
508
- default:
509
- define('CRYPT_RSA_MODE', self::MODE_INTERNAL);
510
- define('MATH_BIGINTEGER_OPENSSL_DISABLE', true);
511
- }
512
- break;
513
- default:
514
- define('CRYPT_RSA_MODE', self::MODE_INTERNAL);
515
- }
516
- }
517
-
518
- $this->zero = new BigInteger();
519
- $this->one = new BigInteger(1);
520
-
521
- $this->hash = new Hash('sha1');
522
- $this->hLen = $this->hash->getLength();
523
- $this->hashName = 'sha1';
524
- $this->mgfHash = new Hash('sha1');
525
- $this->mgfHLen = $this->mgfHash->getLength();
526
- }
527
-
528
- /**
529
- * Create public / private key pair
530
- *
531
- * Returns an array with the following three elements:
532
- * - 'privatekey': The private key.
533
- * - 'publickey': The public key.
534
- * - 'partialkey': A partially computed key (if the execution time exceeded $timeout).
535
- * Will need to be passed back to \phpseclib\Crypt\RSA::createKey() as the third parameter for further processing.
536
- *
537
- * @access public
538
- * @param int $bits
539
- * @param int $timeout
540
- * @param array $p
541
- */
542
- function createKey($bits = 1024, $timeout = false, $partial = array())
543
- {
544
- if (!defined('CRYPT_RSA_EXPONENT')) {
545
- // http://en.wikipedia.org/wiki/65537_%28number%29
546
- define('CRYPT_RSA_EXPONENT', '65537');
547
- }
548
- // per <http://cseweb.ucsd.edu/~hovav/dist/survey.pdf#page=5>, this number ought not result in primes smaller
549
- // 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
550
- // to 384 bits then you're going to get a 384 bit prime and a 640 bit prime (384 + 1024 % 384). at least if
551
- // CRYPT_RSA_MODE is set to self::MODE_INTERNAL. if CRYPT_RSA_MODE is set to self::MODE_OPENSSL then
552
- // CRYPT_RSA_SMALLEST_PRIME is ignored (ie. multi-prime RSA support is more intended as a way to speed up RSA key
553
- // generation when there's a chance neither gmp nor OpenSSL are installed)
554
- if (!defined('CRYPT_RSA_SMALLEST_PRIME')) {
555
- define('CRYPT_RSA_SMALLEST_PRIME', 4096);
556
- }
557
-
558
- // OpenSSL uses 65537 as the exponent and requires RSA keys be 384 bits minimum
559
- if (CRYPT_RSA_MODE == self::MODE_OPENSSL && $bits >= 384 && CRYPT_RSA_EXPONENT == 65537) {
560
- $config = array();
561
- if (isset($this->configFile)) {
562
- $config['config'] = $this->configFile;
563
- }
564
- $rsa = openssl_pkey_new(array('private_key_bits' => $bits) + $config);
565
- openssl_pkey_export($rsa, $privatekey, null, $config);
566
- $publickey = openssl_pkey_get_details($rsa);
567
- $publickey = $publickey['key'];
568
-
569
- $privatekey = call_user_func_array(array($this, '_convertPrivateKey'), array_values($this->_parseKey($privatekey, self::PRIVATE_FORMAT_PKCS1)));
570
- $publickey = call_user_func_array(array($this, '_convertPublicKey'), array_values($this->_parseKey($publickey, self::PUBLIC_FORMAT_PKCS1)));
571
-
572
- // clear the buffer of error strings stemming from a minimalistic openssl.cnf
573
- while (openssl_error_string() !== false) {
574
- }
575
-
576
- return array(
577
- 'privatekey' => $privatekey,
578
- 'publickey' => $publickey,
579
- 'partialkey' => false
580
- );
581
- }
582
-
583
- static $e;
584
- if (!isset($e)) {
585
- $e = new BigInteger(CRYPT_RSA_EXPONENT);
586
- }
587
-
588
- extract($this->_generateMinMax($bits));
589
- $absoluteMin = $min;
590
- $temp = $bits >> 1; // divide by two to see how many bits P and Q would be
591
- if ($temp > CRYPT_RSA_SMALLEST_PRIME) {
592
- $num_primes = floor($bits / CRYPT_RSA_SMALLEST_PRIME);
593
- $temp = CRYPT_RSA_SMALLEST_PRIME;
594
- } else {
595
- $num_primes = 2;
596
- }
597
- extract($this->_generateMinMax($temp + $bits % $temp));
598
- $finalMax = $max;
599
- extract($this->_generateMinMax($temp));
600
-
601
- $generator = new BigInteger();
602
-
603
- $n = $this->one->copy();
604
- if (!empty($partial)) {
605
- extract(unserialize($partial));
606
- } else {
607
- $exponents = $coefficients = $primes = array();
608
- $lcm = array(
609
- 'top' => $this->one->copy(),
610
- 'bottom' => false
611
- );
612
- }
613
-
614
- $start = time();
615
- $i0 = count($primes) + 1;
616
-
617
- do {
618
- for ($i = $i0; $i <= $num_primes; $i++) {
619
- if ($timeout !== false) {
620
- $timeout-= time() - $start;
621
- $start = time();
622
- if ($timeout <= 0) {
623
- return array(
624
- 'privatekey' => '',
625
- 'publickey' => '',
626
- 'partialkey' => serialize(array(
627
- 'primes' => $primes,
628
- 'coefficients' => $coefficients,
629
- 'lcm' => $lcm,
630
- 'exponents' => $exponents
631
- ))
632
- );
633
- }
634
- }
635
-
636
- if ($i == $num_primes) {
637
- list($min, $temp) = $absoluteMin->divide($n);
638
- if (!$temp->equals($this->zero)) {
639
- $min = $min->add($this->one); // ie. ceil()
640
- }
641
- $primes[$i] = $generator->randomPrime($min, $finalMax, $timeout);
642
- } else {
643
- $primes[$i] = $generator->randomPrime($min, $max, $timeout);
644
- }
645
-
646
- if ($primes[$i] === false) { // if we've reached the timeout
647
- if (count($primes) > 1) {
648
- $partialkey = '';
649
- } else {
650
- array_pop($primes);
651
- $partialkey = serialize(array(
652
- 'primes' => $primes,
653
- 'coefficients' => $coefficients,
654
- 'lcm' => $lcm,
655
- 'exponents' => $exponents
656
- ));
657
- }
658
-
659
- return array(
660
- 'privatekey' => '',
661
- 'publickey' => '',
662
- 'partialkey' => $partialkey
663
- );
664
- }
665
-
666
- // the first coefficient is calculated differently from the rest
667
- // ie. instead of being $primes[1]->modInverse($primes[2]), it's $primes[2]->modInverse($primes[1])
668
- if ($i > 2) {
669
- $coefficients[$i] = $n->modInverse($primes[$i]);
670
- }
671
-
672
- $n = $n->multiply($primes[$i]);
673
-
674
- $temp = $primes[$i]->subtract($this->one);
675
-
676
- // textbook RSA implementations use Euler's totient function instead of the least common multiple.
677
- // see http://en.wikipedia.org/wiki/Euler%27s_totient_function
678
- $lcm['top'] = $lcm['top']->multiply($temp);
679
- $lcm['bottom'] = $lcm['bottom'] === false ? $temp : $lcm['bottom']->gcd($temp);
680
-
681
- $exponents[$i] = $e->modInverse($temp);
682
- }
683
-
684
- list($temp) = $lcm['top']->divide($lcm['bottom']);
685
- $gcd = $temp->gcd($e);
686
- $i0 = 1;
687
- } while (!$gcd->equals($this->one));
688
-
689
- $d = $e->modInverse($temp);
690
-
691
- $coefficients[2] = $primes[2]->modInverse($primes[1]);
692
-
693
- // from <http://tools.ietf.org/html/rfc3447#appendix-A.1.2>:
694
- // RSAPrivateKey ::= SEQUENCE {
695
- // version Version,
696
- // modulus INTEGER, -- n
697
- // publicExponent INTEGER, -- e
698
- // privateExponent INTEGER, -- d
699
- // prime1 INTEGER, -- p
700
- // prime2 INTEGER, -- q
701
- // exponent1 INTEGER, -- d mod (p-1)
702
- // exponent2 INTEGER, -- d mod (q-1)
703
- // coefficient INTEGER, -- (inverse of q) mod p
704
- // otherPrimeInfos OtherPrimeInfos OPTIONAL
705
- // }
706
-
707
- return array(
708
- 'privatekey' => $this->_convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients),
709
- 'publickey' => $this->_convertPublicKey($n, $e),
710
- 'partialkey' => false
711
- );
712
- }
713
-
714
- /**
715
- * Convert a private key to the appropriate format.
716
- *
717
- * @access private
718
- * @see self::setPrivateKeyFormat()
719
- * @param string $RSAPrivateKey
720
- * @return string
721
- */
722
- function _convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients)
723
- {
724
- $signed = $this->privateKeyFormat != self::PRIVATE_FORMAT_XML;
725
- $num_primes = count($primes);
726
- $raw = array(
727
- 'version' => $num_primes == 2 ? chr(0) : chr(1), // two-prime vs. multi
728
- 'modulus' => $n->toBytes($signed),
729
- 'publicExponent' => $e->toBytes($signed),
730
- 'privateExponent' => $d->toBytes($signed),
731
- 'prime1' => $primes[1]->toBytes($signed),
732
- 'prime2' => $primes[2]->toBytes($signed),
733
- 'exponent1' => $exponents[1]->toBytes($signed),
734
- 'exponent2' => $exponents[2]->toBytes($signed),
735
- 'coefficient' => $coefficients[2]->toBytes($signed)
736
- );
737
-
738
- // if the format in question does not support multi-prime rsa and multi-prime rsa was used,
739
- // call _convertPublicKey() instead.
740
- switch ($this->privateKeyFormat) {
741
- case self::PRIVATE_FORMAT_XML:
742
- if ($num_primes != 2) {
743
- return false;
744
- }
745
- return "<RSAKeyValue>\r\n" .
746
- ' <Modulus>' . base64_encode($raw['modulus']) . "</Modulus>\r\n" .
747
- ' <Exponent>' . base64_encode($raw['publicExponent']) . "</Exponent>\r\n" .
748
- ' <P>' . base64_encode($raw['prime1']) . "</P>\r\n" .
749
- ' <Q>' . base64_encode($raw['prime2']) . "</Q>\r\n" .
750
- ' <DP>' . base64_encode($raw['exponent1']) . "</DP>\r\n" .
751
- ' <DQ>' . base64_encode($raw['exponent2']) . "</DQ>\r\n" .
752
- ' <InverseQ>' . base64_encode($raw['coefficient']) . "</InverseQ>\r\n" .
753
- ' <D>' . base64_encode($raw['privateExponent']) . "</D>\r\n" .
754
- '</RSAKeyValue>';
755
- break;
756
- case self::PRIVATE_FORMAT_PUTTY:
757
- if ($num_primes != 2) {
758
- return false;
759
- }
760
- $key = "PuTTY-User-Key-File-2: ssh-rsa\r\nEncryption: ";
761
- $encryption = (!empty($this->password) || is_string($this->password)) ? 'aes256-cbc' : 'none';
762
- $key.= $encryption;
763
- $key.= "\r\nComment: " . $this->comment . "\r\n";
764
- $public = pack(
765
- 'Na*Na*Na*',
766
- strlen('ssh-rsa'),
767
- 'ssh-rsa',
768
- strlen($raw['publicExponent']),
769
- $raw['publicExponent'],
770
- strlen($raw['modulus']),
771
- $raw['modulus']
772
- );
773
- $source = pack(
774
- 'Na*Na*Na*Na*',
775
- strlen('ssh-rsa'),
776
- 'ssh-rsa',
777
- strlen($encryption),
778
- $encryption,
779
- strlen($this->comment),
780
- $this->comment,
781
- strlen($public),
782
- $public
783
- );
784
- $public = base64_encode($public);
785
- $key.= "Public-Lines: " . ((strlen($public) + 63) >> 6) . "\r\n";
786
- $key.= chunk_split($public, 64);
787
- $private = pack(
788
- 'Na*Na*Na*Na*',
789
- strlen($raw['privateExponent']),
790
- $raw['privateExponent'],
791
- strlen($raw['prime1']),
792
- $raw['prime1'],
793
- strlen($raw['prime2']),
794
- $raw['prime2'],
795
- strlen($raw['coefficient']),
796
- $raw['coefficient']
797
- );
798
- if (empty($this->password) && !is_string($this->password)) {
799
- $source.= pack('Na*', strlen($private), $private);
800
- $hashkey = 'putty-private-key-file-mac-key';
801
- } else {
802
- $private.= Random::string(16 - (strlen($private) & 15));
803
- $source.= pack('Na*', strlen($private), $private);
804
- $sequence = 0;
805
- $symkey = '';
806
- while (strlen($symkey) < 32) {
807
- $temp = pack('Na*', $sequence++, $this->password);
808
- $symkey.= pack('H*', sha1($temp));
809
- }
810
- $symkey = substr($symkey, 0, 32);
811
- $crypto = new AES();
812
-
813
- $crypto->setKey($symkey);
814
- $crypto->disablePadding();
815
- $private = $crypto->encrypt($private);
816
- $hashkey = 'putty-private-key-file-mac-key' . $this->password;
817
- }
818
-
819
- $private = base64_encode($private);
820
- $key.= 'Private-Lines: ' . ((strlen($private) + 63) >> 6) . "\r\n";
821
- $key.= chunk_split($private, 64);
822
- $hash = new Hash('sha1');
823
- $hash->setKey(pack('H*', sha1($hashkey)));
824
- $key.= 'Private-MAC: ' . bin2hex($hash->hash($source)) . "\r\n";
825
-
826
- return $key;
827
- case self::PRIVATE_FORMAT_OPENSSH:
828
- if ($num_primes != 2) {
829
- return false;
830
- }
831
- $publicKey = pack('Na*Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($raw['publicExponent']), $raw['publicExponent'], strlen($raw['modulus']), $raw['modulus']);
832
- $privateKey = pack(
833
- 'Na*Na*Na*Na*Na*Na*Na*',
834
- strlen('ssh-rsa'),
835
- 'ssh-rsa',
836
- strlen($raw['modulus']),
837
- $raw['modulus'],
838
- strlen($raw['publicExponent']),
839
- $raw['publicExponent'],
840
- strlen($raw['privateExponent']),
841
- $raw['privateExponent'],
842
- strlen($raw['coefficient']),
843
- $raw['coefficient'],
844
- strlen($raw['prime1']),
845
- $raw['prime1'],
846
- strlen($raw['prime2']),
847
- $raw['prime2']
848
- );
849
- $checkint = Random::string(4);
850
- $paddedKey = pack(
851
- 'a*Na*',
852
- $checkint . $checkint . $privateKey,
853
- strlen($this->comment),
854
- $this->comment
855
- );
856
- $paddingLength = (7 * strlen($paddedKey)) % 8;
857
- for ($i = 1; $i <= $paddingLength; $i++) {
858
- $paddedKey.= chr($i);
859
- }
860
- $key = pack(
861
- 'Na*Na*Na*NNa*Na*',
862
- strlen('none'),
863
- 'none',
864
- strlen('none'),
865
- 'none',
866
- 0,
867
- '',
868
- 1,
869
- strlen($publicKey),
870
- $publicKey,
871
- strlen($paddedKey),
872
- $paddedKey
873
- );
874
- $key = "openssh-key-v1\0$key";
875
-
876
- return "-----BEGIN OPENSSH PRIVATE KEY-----\r\n" .
877
- chunk_split(base64_encode($key), 70) .
878
- "-----END OPENSSH PRIVATE KEY-----";
879
- default: // eg. self::PRIVATE_FORMAT_PKCS1
880
- $components = array();
881
- foreach ($raw as $name => $value) {
882
- $components[$name] = pack('Ca*a*', self::ASN1_INTEGER, $this->_encodeLength(strlen($value)), $value);
883
- }
884
-
885
- $RSAPrivateKey = implode('', $components);
886
-
887
- if ($num_primes > 2) {
888
- $OtherPrimeInfos = '';
889
- for ($i = 3; $i <= $num_primes; $i++) {
890
- // OtherPrimeInfos ::= SEQUENCE SIZE(1..MAX) OF OtherPrimeInfo
891
- //
892
- // OtherPrimeInfo ::= SEQUENCE {
893
- // prime INTEGER, -- ri
894
- // exponent INTEGER, -- di
895
- // coefficient INTEGER -- ti
896
- // }
897
- $OtherPrimeInfo = pack('Ca*a*', self::ASN1_INTEGER, $this->_encodeLength(strlen($primes[$i]->toBytes(true))), $primes[$i]->toBytes(true));
898
- $OtherPrimeInfo.= pack('Ca*a*', self::ASN1_INTEGER, $this->_encodeLength(strlen($exponents[$i]->toBytes(true))), $exponents[$i]->toBytes(true));
899
- $OtherPrimeInfo.= pack('Ca*a*', self::ASN1_INTEGER, $this->_encodeLength(strlen($coefficients[$i]->toBytes(true))), $coefficients[$i]->toBytes(true));
900
- $OtherPrimeInfos.= pack('Ca*a*', self::ASN1_SEQUENCE, $this->_encodeLength(strlen($OtherPrimeInfo)), $OtherPrimeInfo);
901
- }
902
- $RSAPrivateKey.= pack('Ca*a*', self::ASN1_SEQUENCE, $this->_encodeLength(strlen($OtherPrimeInfos)), $OtherPrimeInfos);
903
- }
904
-
905
- $RSAPrivateKey = pack('Ca*a*', self::ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);
906
-
907
- if ($this->privateKeyFormat == self::PRIVATE_FORMAT_PKCS8) {
908
- $rsaOID = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA
909
- $RSAPrivateKey = pack(
910
- 'Ca*a*Ca*a*',
911
- self::ASN1_INTEGER,
912
- "\01\00",
913
- $rsaOID,
914
- 4,
915
- $this->_encodeLength(strlen($RSAPrivateKey)),
916
- $RSAPrivateKey
917
- );
918
- $RSAPrivateKey = pack('Ca*a*', self::ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);
919
- if (!empty($this->password) || is_string($this->password)) {
920
- $salt = Random::string(8);
921
- $iterationCount = 2048;
922
-
923
- $crypto = new DES();
924
- $crypto->setPassword($this->password, 'pbkdf1', 'md5', $salt, $iterationCount);
925
- $RSAPrivateKey = $crypto->encrypt($RSAPrivateKey);
926
-
927
- $parameters = pack(
928
- 'Ca*a*Ca*N',
929
- self::ASN1_OCTETSTRING,
930
- $this->_encodeLength(strlen($salt)),
931
- $salt,
932
- self::ASN1_INTEGER,
933
- $this->_encodeLength(4),
934
- $iterationCount
935
- );
936
- $pbeWithMD5AndDES_CBC = "\x2a\x86\x48\x86\xf7\x0d\x01\x05\x03";
937
-
938
- $encryptionAlgorithm = pack(
939
- 'Ca*a*Ca*a*',
940
- self::ASN1_OBJECT,
941
- $this->_encodeLength(strlen($pbeWithMD5AndDES_CBC)),
942
- $pbeWithMD5AndDES_CBC,
943
- self::ASN1_SEQUENCE,
944
- $this->_encodeLength(strlen($parameters)),
945
- $parameters
946
- );
947
-
948
- $RSAPrivateKey = pack(
949
- 'Ca*a*Ca*a*',
950
- self::ASN1_SEQUENCE,
951
- $this->_encodeLength(strlen($encryptionAlgorithm)),
952
- $encryptionAlgorithm,
953
- self::ASN1_OCTETSTRING,
954
- $this->_encodeLength(strlen($RSAPrivateKey)),
955
- $RSAPrivateKey
956
- );
957
-
958
- $RSAPrivateKey = pack('Ca*a*', self::ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);
959
-
960
- $RSAPrivateKey = "-----BEGIN ENCRYPTED PRIVATE KEY-----\r\n" .
961
- chunk_split(base64_encode($RSAPrivateKey), 64) .
962
- '-----END ENCRYPTED PRIVATE KEY-----';
963
- } else {
964
- $RSAPrivateKey = "-----BEGIN PRIVATE KEY-----\r\n" .
965
- chunk_split(base64_encode($RSAPrivateKey), 64) .
966
- '-----END PRIVATE KEY-----';
967
- }
968
- return $RSAPrivateKey;
969
- }
970
-
971
- if (!empty($this->password) || is_string($this->password)) {
972
- $iv = Random::string(8);
973
- $symkey = pack('H*', md5($this->password . $iv)); // symkey is short for symmetric key
974
- $symkey.= substr(pack('H*', md5($symkey . $this->password . $iv)), 0, 8);
975
- $des = new TripleDES();
976
- $des->setKey($symkey);
977
- $des->setIV($iv);
978
- $iv = strtoupper(bin2hex($iv));
979
- $RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" .
980
- "Proc-Type: 4,ENCRYPTED\r\n" .
981
- "DEK-Info: DES-EDE3-CBC,$iv\r\n" .
982
- "\r\n" .
983
- chunk_split(base64_encode($des->encrypt($RSAPrivateKey)), 64) .
984
- '-----END RSA PRIVATE KEY-----';
985
- } else {
986
- $RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" .
987
- chunk_split(base64_encode($RSAPrivateKey), 64) .
988
- '-----END RSA PRIVATE KEY-----';
989
- }
990
-
991
- return $RSAPrivateKey;
992
- }
993
- }
994
-
995
- /**
996
- * Convert a public key to the appropriate format
997
- *
998
- * @access private
999
- * @see self::setPublicKeyFormat()
1000
- * @param string $RSAPrivateKey
1001
- * @return string
1002
- */
1003
- function _convertPublicKey($n, $e)
1004
- {
1005
- $signed = $this->publicKeyFormat != self::PUBLIC_FORMAT_XML;
1006
-
1007
- $modulus = $n->toBytes($signed);
1008
- $publicExponent = $e->toBytes($signed);
1009
-
1010
- switch ($this->publicKeyFormat) {
1011
- case self::PUBLIC_FORMAT_RAW:
1012
- return array('e' => $e->copy(), 'n' => $n->copy());
1013
- case self::PUBLIC_FORMAT_XML:
1014
- return "<RSAKeyValue>\r\n" .
1015
- ' <Modulus>' . base64_encode($modulus) . "</Modulus>\r\n" .
1016
- ' <Exponent>' . base64_encode($publicExponent) . "</Exponent>\r\n" .
1017
- '</RSAKeyValue>';
1018
- break;
1019
- case self::PUBLIC_FORMAT_OPENSSH:
1020
- // from <http://tools.ietf.org/html/rfc4253#page-15>:
1021
- // string "ssh-rsa"
1022
- // mpint e
1023
- // mpint n
1024
- $RSAPublicKey = pack('Na*Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($publicExponent), $publicExponent, strlen($modulus), $modulus);
1025
- $RSAPublicKey = 'ssh-rsa ' . base64_encode($RSAPublicKey) . ' ' . $this->comment;
1026
-
1027
- return $RSAPublicKey;
1028
- default: // eg. self::PUBLIC_FORMAT_PKCS1_RAW or self::PUBLIC_FORMAT_PKCS1
1029
- // from <http://tools.ietf.org/html/rfc3447#appendix-A.1.1>:
1030
- // RSAPublicKey ::= SEQUENCE {
1031
- // modulus INTEGER, -- n
1032
- // publicExponent INTEGER -- e
1033
- // }
1034
- $components = array(
1035
- 'modulus' => pack('Ca*a*', self::ASN1_INTEGER, $this->_encodeLength(strlen($modulus)), $modulus),
1036
- 'publicExponent' => pack('Ca*a*', self::ASN1_INTEGER, $this->_encodeLength(strlen($publicExponent)), $publicExponent)
1037
- );
1038
-
1039
- $RSAPublicKey = pack(
1040
- 'Ca*a*a*',
1041
- self::ASN1_SEQUENCE,
1042
- $this->_encodeLength(strlen($components['modulus']) + strlen($components['publicExponent'])),
1043
- $components['modulus'],
1044
- $components['publicExponent']
1045
- );
1046
-
1047
- if ($this->publicKeyFormat == self::PUBLIC_FORMAT_PKCS1_RAW) {
1048
- $RSAPublicKey = "-----BEGIN RSA PUBLIC KEY-----\r\n" .
1049
- chunk_split(base64_encode($RSAPublicKey), 64) .
1050
- '-----END RSA PUBLIC KEY-----';
1051
- } else {
1052
- // sequence(oid(1.2.840.113549.1.1.1), null)) = rsaEncryption.
1053
- $rsaOID = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA
1054
- $RSAPublicKey = chr(0) . $RSAPublicKey;
1055
- $RSAPublicKey = chr(3) . $this->_encodeLength(strlen($RSAPublicKey)) . $RSAPublicKey;
1056
-
1057
- $RSAPublicKey = pack(
1058
- 'Ca*a*',
1059
- self::ASN1_SEQUENCE,
1060
- $this->_encodeLength(strlen($rsaOID . $RSAPublicKey)),
1061
- $rsaOID . $RSAPublicKey
1062
- );
1063
-
1064
- $RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" .
1065
- chunk_split(base64_encode($RSAPublicKey), 64) .
1066
- '-----END PUBLIC KEY-----';
1067
- }
1068
-
1069
- return $RSAPublicKey;
1070
- }
1071
- }
1072
-
1073
- /**
1074
- * Break a public or private key down into its constituant components
1075
- *
1076
- * @access private
1077
- * @see self::_convertPublicKey()
1078
- * @see self::_convertPrivateKey()
1079
- * @param string|array $key
1080
- * @param int $type
1081
- * @return array|bool
1082
- */
1083
- function _parseKey($key, $type)
1084
- {
1085
- if ($type != self::PUBLIC_FORMAT_RAW && !is_string($key)) {
1086
- return false;
1087
- }
1088
-
1089
- switch ($type) {
1090
- case self::PUBLIC_FORMAT_RAW:
1091
- if (!is_array($key)) {
1092
- return false;
1093
- }
1094
- $components = array();
1095
- switch (true) {
1096
- case isset($key['e']):
1097
- $components['publicExponent'] = $key['e']->copy();
1098
- break;
1099
- case isset($key['exponent']):
1100
- $components['publicExponent'] = $key['exponent']->copy();
1101
- break;
1102
- case isset($key['publicExponent']):
1103
- $components['publicExponent'] = $key['publicExponent']->copy();
1104
- break;
1105
- case isset($key[0]):
1106
- $components['publicExponent'] = $key[0]->copy();
1107
- }
1108
- switch (true) {
1109
- case isset($key['n']):
1110
- $components['modulus'] = $key['n']->copy();
1111
- break;
1112
- case isset($key['modulo']):
1113
- $components['modulus'] = $key['modulo']->copy();
1114
- break;
1115
- case isset($key['modulus']):
1116
- $components['modulus'] = $key['modulus']->copy();
1117
- break;
1118
- case isset($key[1]):
1119
- $components['modulus'] = $key[1]->copy();
1120
- }
1121
- return isset($components['modulus']) && isset($components['publicExponent']) ? $components : false;
1122
- case self::PRIVATE_FORMAT_PKCS1:
1123
- case self::PRIVATE_FORMAT_PKCS8:
1124
- case self::PUBLIC_FORMAT_PKCS1:
1125
- /* Although PKCS#1 proposes a format that public and private keys can use, encrypting them is
1126
- "outside the scope" of PKCS#1. PKCS#1 then refers you to PKCS#12 and PKCS#15 if you're wanting to
1127
- protect private keys, however, that's not what OpenSSL* does. OpenSSL protects private keys by adding
1128
- two new "fields" to the key - DEK-Info and Proc-Type. These fields are discussed here:
1129
-
1130
- http://tools.ietf.org/html/rfc1421#section-4.6.1.1
1131
- http://tools.ietf.org/html/rfc1421#section-4.6.1.3
1132
-
1133
- DES-EDE3-CBC as an algorithm, however, is not discussed anywhere, near as I can tell.
1134
- DES-CBC and DES-EDE are discussed in RFC1423, however, DES-EDE3-CBC isn't, nor is its key derivation
1135
- function. As is, the definitive authority on this encoding scheme isn't the IETF but rather OpenSSL's
1136
- own implementation. ie. the implementation *is* the standard and any bugs that may exist in that
1137
- implementation are part of the standard, as well.
1138
-
1139
- * OpenSSL is the de facto standard. It's utilized by OpenSSH and other projects */
1140
- if (preg_match('#DEK-Info: (.+),(.+)#', $key, $matches)) {
1141
- $iv = pack('H*', trim($matches[2]));
1142
- $symkey = pack('H*', md5($this->password . substr($iv, 0, 8))); // symkey is short for symmetric key
1143
- $symkey.= pack('H*', md5($symkey . $this->password . substr($iv, 0, 8)));
1144
- // remove the Proc-Type / DEK-Info sections as they're no longer needed
1145
- $key = preg_replace('#^(?:Proc-Type|DEK-Info): .*#m', '', $key);
1146
- $ciphertext = $this->_extractBER($key);
1147
- if ($ciphertext === false) {
1148
- $ciphertext = $key;
1149
- }
1150
- switch ($matches[1]) {
1151
- case 'AES-256-CBC':
1152
- $crypto = new AES();
1153
- break;
1154
- case 'AES-128-CBC':
1155
- $symkey = substr($symkey, 0, 16);
1156
- $crypto = new AES();
1157
- break;
1158
- case 'DES-EDE3-CFB':
1159
- $crypto = new TripleDES(Base::MODE_CFB);
1160
- break;
1161
- case 'DES-EDE3-CBC':
1162
- $symkey = substr($symkey, 0, 24);
1163
- $crypto = new TripleDES();
1164
- break;
1165
- case 'DES-CBC':
1166
- $crypto = new DES();
1167
- break;
1168
- default:
1169
- return false;
1170
- }
1171
- $crypto->setKey($symkey);
1172
- $crypto->setIV($iv);
1173
- $decoded = $crypto->decrypt($ciphertext);
1174
- } else {
1175
- $decoded = $this->_extractBER($key);
1176
- }
1177
-
1178
- if ($decoded !== false) {
1179
- $key = $decoded;
1180
- }
1181
-
1182
- $components = array();
1183
-
1184
- if (ord($this->_string_shift($key)) != self::ASN1_SEQUENCE) {
1185
- return false;
1186
- }
1187
- if ($this->_decodeLength($key) != strlen($key)) {
1188
- return false;
1189
- }
1190
-
1191
- $tag = ord($this->_string_shift($key));
1192
- /* intended for keys for which OpenSSL's asn1parse returns the following:
1193
-
1194
- 0:d=0 hl=4 l= 631 cons: SEQUENCE
1195
- 4:d=1 hl=2 l= 1 prim: INTEGER :00
1196
- 7:d=1 hl=2 l= 13 cons: SEQUENCE
1197
- 9:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption
1198
- 20:d=2 hl=2 l= 0 prim: NULL
1199
- 22:d=1 hl=4 l= 609 prim: OCTET STRING
1200
-
1201
- ie. PKCS8 keys*/
1202
-
1203
- if ($tag == self::ASN1_INTEGER && substr($key, 0, 3) == "\x01\x00\x30") {
1204
- $this->_string_shift($key, 3);
1205
- $tag = self::ASN1_SEQUENCE;
1206
- }
1207
-
1208
- if ($tag == self::ASN1_SEQUENCE) {
1209
- $temp = $this->_string_shift($key, $this->_decodeLength($key));
1210
- if (ord($this->_string_shift($temp)) != self::ASN1_OBJECT) {
1211
- return false;
1212
- }
1213
- $length = $this->_decodeLength($temp);
1214
- switch ($this->_string_shift($temp, $length)) {
1215
- case "\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01": // rsaEncryption
1216
- break;
1217
- case "\x2a\x86\x48\x86\xf7\x0d\x01\x05\x03": // pbeWithMD5AndDES-CBC
1218
- /*
1219
- PBEParameter ::= SEQUENCE {
1220
- salt OCTET STRING (SIZE(8)),
1221
- iterationCount INTEGER }
1222
- */
1223
- if (ord($this->_string_shift($temp)) != self::ASN1_SEQUENCE) {
1224
- return false;
1225
- }
1226
- if ($this->_decodeLength($temp) != strlen($temp)) {
1227
- return false;
1228
- }
1229
- $this->_string_shift($temp); // assume it's an octet string
1230
- $salt = $this->_string_shift($temp, $this->_decodeLength($temp));
1231
- if (ord($this->_string_shift($temp)) != self::ASN1_INTEGER) {
1232
- return false;
1233
- }
1234
- $this->_decodeLength($temp);
1235
- list(, $iterationCount) = unpack('N', str_pad($temp, 4, chr(0), STR_PAD_LEFT));
1236
- $this->_string_shift($key); // assume it's an octet string
1237
- $length = $this->_decodeLength($key);
1238
- if (strlen($key) != $length) {
1239
- return false;
1240
- }
1241
-
1242
- $crypto = new DES();
1243
- $crypto->setPassword($this->password, 'pbkdf1', 'md5', $salt, $iterationCount);
1244
- $key = $crypto->decrypt($key);
1245
- if ($key === false) {
1246
- return false;
1247
- }
1248
- return $this->_parseKey($key, self::PRIVATE_FORMAT_PKCS1);
1249
- default:
1250
- return false;
1251
- }
1252
- /* intended for keys for which OpenSSL's asn1parse returns the following:
1253
-
1254
- 0:d=0 hl=4 l= 290 cons: SEQUENCE
1255
- 4:d=1 hl=2 l= 13 cons: SEQUENCE
1256
- 6:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption
1257
- 17:d=2 hl=2 l= 0 prim: NULL
1258
- 19:d=1 hl=4 l= 271 prim: BIT STRING */
1259
- $tag = ord($this->_string_shift($key)); // skip over the BIT STRING / OCTET STRING tag
1260
- $this->_decodeLength($key); // skip over the BIT STRING / OCTET STRING length
1261
- // "The initial octet shall encode, as an unsigned binary integer wtih bit 1 as the least significant bit, the number of
1262
- // unused bits in the final subsequent octet. The number shall be in the range zero to seven."
1263
- // -- http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf (section 8.6.2.2)
1264
- if ($tag == self::ASN1_BITSTRING) {
1265
- $this->_string_shift($key);
1266
- }
1267
- if (ord($this->_string_shift($key)) != self::ASN1_SEQUENCE) {
1268
- return false;
1269
- }
1270
- if ($this->_decodeLength($key) != strlen($key)) {
1271
- return false;
1272
- }
1273
- $tag = ord($this->_string_shift($key));
1274
- }
1275
- if ($tag != self::ASN1_INTEGER) {
1276
- return false;
1277
- }
1278
-
1279
- $length = $this->_decodeLength($key);
1280
- $temp = $this->_string_shift($key, $length);
1281
- if (strlen($temp) != 1 || ord($temp) > 2) {
1282
- $components['modulus'] = new BigInteger($temp, 256);
1283
- $this->_string_shift($key); // skip over self::ASN1_INTEGER
1284
- $length = $this->_decodeLength($key);
1285
- $components[$type == self::PUBLIC_FORMAT_PKCS1 ? 'publicExponent' : 'privateExponent'] = new BigInteger($this->_string_shift($key, $length), 256);
1286
-
1287
- return $components;
1288
- }
1289
- if (ord($this->_string_shift($key)) != self::ASN1_INTEGER) {
1290
- return false;
1291
- }
1292
- $length = $this->_decodeLength($key);
1293
- $components['modulus'] = new BigInteger($this->_string_shift($key, $length), 256);
1294
- $this->_string_shift($key);
1295
- $length = $this->_decodeLength($key);
1296
- $components['publicExponent'] = new BigInteger($this->_string_shift($key, $length), 256);
1297
- $this->_string_shift($key);
1298
- $length = $this->_decodeLength($key);
1299
- $components['privateExponent'] = new BigInteger($this->_string_shift($key, $length), 256);
1300
- $this->_string_shift($key);
1301
- $length = $this->_decodeLength($key);
1302
- $components['primes'] = array(1 => new BigInteger($this->_string_shift($key, $length), 256));
1303
- $this->_string_shift($key);
1304
- $length = $this->_decodeLength($key);
1305
- $components['primes'][] = new BigInteger($this->_string_shift($key, $length), 256);
1306
- $this->_string_shift($key);
1307
- $length = $this->_decodeLength($key);
1308
- $components['exponents'] = array(1 => new BigInteger($this->_string_shift($key, $length), 256));
1309
- $this->_string_shift($key);
1310
- $length = $this->_decodeLength($key);
1311
- $components['exponents'][] = new BigInteger($this->_string_shift($key, $length), 256);
1312
- $this->_string_shift($key);
1313
- $length = $this->_decodeLength($key);
1314
- $components['coefficients'] = array(2 => new BigInteger($this->_string_shift($key, $length), 256));
1315
-
1316
- if (!empty($key)) {
1317
- if (ord($this->_string_shift($key)) != self::ASN1_SEQUENCE) {
1318
- return false;
1319
- }
1320
- $this->_decodeLength($key);
1321
- while (!empty($key)) {
1322
- if (ord($this->_string_shift($key)) != self::ASN1_SEQUENCE) {
1323
- return false;
1324
- }
1325
- $this->_decodeLength($key);
1326
- $key = substr($key, 1);
1327
- $length = $this->_decodeLength($key);
1328
- $components['primes'][] = new BigInteger($this->_string_shift($key, $length), 256);
1329
- $this->_string_shift($key);
1330
- $length = $this->_decodeLength($key);
1331
- $components['exponents'][] = new BigInteger($this->_string_shift($key, $length), 256);
1332
- $this->_string_shift($key);
1333
- $length = $this->_decodeLength($key);
1334
- $components['coefficients'][] = new BigInteger($this->_string_shift($key, $length), 256);
1335
- }
1336
- }
1337
-
1338
- return $components;
1339
- case self::PUBLIC_FORMAT_OPENSSH:
1340
- $parts = explode(' ', $key, 3);
1341
-
1342
- $key = isset($parts[1]) ? base64_decode($parts[1]) : false;
1343
- if ($key === false) {
1344
- return false;
1345
- }
1346
-
1347
- $comment = isset($parts[2]) ? $parts[2] : false;
1348
-
1349
- $cleanup = substr($key, 0, 11) == "\0\0\0\7ssh-rsa";
1350
-
1351
- if (strlen($key) <= 4) {
1352
- return false;
1353
- }
1354
- extract(unpack('Nlength', $this->_string_shift($key, 4)));
1355
- $publicExponent = new BigInteger($this->_string_shift($key, $length), -256);
1356
- if (strlen($key) <= 4) {
1357
- return false;
1358
- }
1359
- extract(unpack('Nlength', $this->_string_shift($key, 4)));
1360
- $modulus = new BigInteger($this->_string_shift($key, $length), -256);
1361
-
1362
- if ($cleanup && strlen($key)) {
1363
- if (strlen($key) <= 4) {
1364
- return false;
1365
- }
1366
- extract(unpack('Nlength', $this->_string_shift($key, 4)));
1367
- $realModulus = new BigInteger($this->_string_shift($key, $length), -256);
1368
- return strlen($key) ? false : array(
1369
- 'modulus' => $realModulus,
1370
- 'publicExponent' => $modulus,
1371
- 'comment' => $comment
1372
- );
1373
- } else {
1374
- return strlen($key) ? false : array(
1375
- 'modulus' => $modulus,
1376
- 'publicExponent' => $publicExponent,
1377
- 'comment' => $comment
1378
- );
1379
- }
1380
- // http://www.w3.org/TR/xmldsig-core/#sec-RSAKeyValue
1381
- // http://en.wikipedia.org/wiki/XML_Signature
1382
- case self::PRIVATE_FORMAT_XML:
1383
- case self::PUBLIC_FORMAT_XML:
1384
- $this->components = array();
1385
-
1386
- $xml = xml_parser_create('UTF-8');
1387
- xml_set_object($xml, $this);
1388
- xml_set_element_handler($xml, '_start_element_handler', '_stop_element_handler');
1389
- xml_set_character_data_handler($xml, '_data_handler');
1390
- // add <xml></xml> to account for "dangling" tags like <BitStrength>...</BitStrength> that are sometimes added
1391
- if (!xml_parse($xml, '<xml>' . $key . '</xml>')) {
1392
- xml_parser_free($xml);
1393
- unset($xml);
1394
- return false;
1395
- }
1396
-
1397
- xml_parser_free($xml);
1398
- unset($xml);
1399
-
1400
- return isset($this->components['modulus']) && isset($this->components['publicExponent']) ? $this->components : false;
1401
- // from PuTTY's SSHPUBK.C
1402
- case self::PRIVATE_FORMAT_PUTTY:
1403
- $components = array();
1404
- $key = preg_split('#\r\n|\r|\n#', $key);
1405
- $type = trim(preg_replace('#PuTTY-User-Key-File-2: (.+)#', '$1', $key[0]));
1406
- if ($type != 'ssh-rsa') {
1407
- return false;
1408
- }
1409
- $encryption = trim(preg_replace('#Encryption: (.+)#', '$1', $key[1]));
1410
- $comment = trim(preg_replace('#Comment: (.+)#', '$1', $key[2]));
1411
-
1412
- $publicLength = trim(preg_replace('#Public-Lines: (\d+)#', '$1', $key[3]));
1413
- $public = base64_decode(implode('', array_map('trim', array_slice($key, 4, $publicLength))));
1414
- $public = substr($public, 11);
1415
- extract(unpack('Nlength', $this->_string_shift($public, 4)));
1416
- $components['publicExponent'] = new BigInteger($this->_string_shift($public, $length), -256);
1417
- extract(unpack('Nlength', $this->_string_shift($public, 4)));
1418
- $components['modulus'] = new BigInteger($this->_string_shift($public, $length), -256);
1419
-
1420
- $privateLength = trim(preg_replace('#Private-Lines: (\d+)#', '$1', $key[$publicLength + 4]));
1421
- $private = base64_decode(implode('', array_map('trim', array_slice($key, $publicLength + 5, $privateLength))));
1422
-
1423
- switch ($encryption) {
1424
- case 'aes256-cbc':
1425
- $symkey = '';
1426
- $sequence = 0;
1427
- while (strlen($symkey) < 32) {
1428
- $temp = pack('Na*', $sequence++, $this->password);
1429
- $symkey.= pack('H*', sha1($temp));
1430
- }
1431
- $symkey = substr($symkey, 0, 32);
1432
- $crypto = new AES();
1433
- }
1434
-
1435
- if ($encryption != 'none') {
1436
- $crypto->setKey($symkey);
1437
- $crypto->disablePadding();
1438
- $private = $crypto->decrypt($private);
1439
- if ($private === false) {
1440
- return false;
1441
- }
1442
- }
1443
-
1444
- extract(unpack('Nlength', $this->_string_shift($private, 4)));
1445
- if (strlen($private) < $length) {
1446
- return false;
1447
- }
1448
- $components['privateExponent'] = new BigInteger($this->_string_shift($private, $length), -256);
1449
- extract(unpack('Nlength', $this->_string_shift($private, 4)));
1450
- if (strlen($private) < $length) {
1451
- return false;
1452
- }
1453
- $components['primes'] = array(1 => new BigInteger($this->_string_shift($private, $length), -256));
1454
- extract(unpack('Nlength', $this->_string_shift($private, 4)));
1455
- if (strlen($private) < $length) {
1456
- return false;
1457
- }
1458
- $components['primes'][] = new BigInteger($this->_string_shift($private, $length), -256);
1459
-
1460
- $temp = $components['primes'][1]->subtract($this->one);
1461
- $components['exponents'] = array(1 => $components['publicExponent']->modInverse($temp));
1462
- $temp = $components['primes'][2]->subtract($this->one);
1463
- $components['exponents'][] = $components['publicExponent']->modInverse($temp);
1464
-
1465
- extract(unpack('Nlength', $this->_string_shift($private, 4)));
1466
- if (strlen($private) < $length) {
1467
- return false;
1468
- }
1469
- $components['coefficients'] = array(2 => new BigInteger($this->_string_shift($private, $length), -256));
1470
-
1471
- return $components;
1472
- case self::PRIVATE_FORMAT_OPENSSH:
1473
- $components = array();
1474
- $decoded = $this->_extractBER($key);
1475
- $magic = $this->_string_shift($decoded, 15);
1476
- if ($magic !== "openssh-key-v1\0") {
1477
- return false;
1478
- }
1479
- $options = $this->_string_shift($decoded, 24);
1480
- // \0\0\0\4none = ciphername
1481
- // \0\0\0\4none = kdfname
1482
- // \0\0\0\0 = kdfoptions
1483
- // \0\0\0\1 = numkeys
1484
- if ($options != "\0\0\0\4none\0\0\0\4none\0\0\0\0\0\0\0\1") {
1485
- return false;
1486
- }
1487
- extract(unpack('Nlength', $this->_string_shift($decoded, 4)));
1488
- if (strlen($decoded) < $length) {
1489
- return false;
1490
- }
1491
- $publicKey = $this->_string_shift($decoded, $length);
1492
- extract(unpack('Nlength', $this->_string_shift($decoded, 4)));
1493
- if (strlen($decoded) < $length) {
1494
- return false;
1495
- }
1496
- $paddedKey = $this->_string_shift($decoded, $length);
1497
-
1498
- if ($this->_string_shift($publicKey, 11) !== "\0\0\0\7ssh-rsa") {
1499
- return false;
1500
- }
1501
-
1502
- $checkint1 = $this->_string_shift($paddedKey, 4);
1503
- $checkint2 = $this->_string_shift($paddedKey, 4);
1504
- if (strlen($checkint1) != 4 || $checkint1 !== $checkint2) {
1505
- return false;
1506
- }
1507
-
1508
- if ($this->_string_shift($paddedKey, 11) !== "\0\0\0\7ssh-rsa") {
1509
- return false;
1510
- }
1511
-
1512
- $values = array(
1513
- &$components['modulus'],
1514
- &$components['publicExponent'],
1515
- &$components['privateExponent'],
1516
- &$components['coefficients'][2],
1517
- &$components['primes'][1],
1518
- &$components['primes'][2]
1519
- );
1520
-
1521
- foreach ($values as &$value) {
1522
- extract(unpack('Nlength', $this->_string_shift($paddedKey, 4)));
1523
- if (strlen($paddedKey) < $length) {
1524
- return false;
1525
- }
1526
- $value = new BigInteger($this->_string_shift($paddedKey, $length), -256);
1527
- }
1528
-
1529
- extract(unpack('Nlength', $this->_string_shift($paddedKey, 4)));
1530
- if (strlen($paddedKey) < $length) {
1531
- return false;
1532
- }
1533
- $components['comment'] = $this->_string_shift($decoded, $length);
1534
-
1535
- $temp = $components['primes'][1]->subtract($this->one);
1536
- $components['exponents'] = array(1 => $components['publicExponent']->modInverse($temp));
1537
- $temp = $components['primes'][2]->subtract($this->one);
1538
- $components['exponents'][] = $components['publicExponent']->modInverse($temp);
1539
-
1540
- return $components;
1541
- }
1542
- }
1543
-
1544
- /**
1545
- * Returns the key size
1546
- *
1547
- * More specifically, this returns the size of the modulo in bits.
1548
- *
1549
- * @access public
1550
- * @return int
1551
- */
1552
- function getSize()
1553
- {
1554
- return !isset($this->modulus) ? 0 : strlen($this->modulus->toBits());
1555
- }
1556
-
1557
- /**
1558
- * Start Element Handler
1559
- *
1560
- * Called by xml_set_element_handler()
1561
- *
1562
- * @access private
1563
- * @param resource $parser
1564
- * @param string $name
1565
- * @param array $attribs
1566
- */
1567
- function _start_element_handler($parser, $name, $attribs)
1568
- {
1569
- //$name = strtoupper($name);
1570
- switch ($name) {
1571
- case 'MODULUS':
1572
- $this->current = &$this->components['modulus'];
1573
- break;
1574
- case 'EXPONENT':
1575
- $this->current = &$this->components['publicExponent'];
1576
- break;
1577
- case 'P':
1578
- $this->current = &$this->components['primes'][1];
1579
- break;
1580
- case 'Q':
1581
- $this->current = &$this->components['primes'][2];
1582
- break;
1583
- case 'DP':
1584
- $this->current = &$this->components['exponents'][1];
1585
- break;
1586
- case 'DQ':
1587
- $this->current = &$this->components['exponents'][2];
1588
- break;
1589
- case 'INVERSEQ':
1590
- $this->current = &$this->components['coefficients'][2];
1591
- break;
1592
- case 'D':
1593
- $this->current = &$this->components['privateExponent'];
1594
- }
1595
- $this->current = '';
1596
- }
1597
-
1598
- /**
1599
- * Stop Element Handler
1600
- *
1601
- * Called by xml_set_element_handler()
1602
- *
1603
- * @access private
1604
- * @param resource $parser
1605
- * @param string $name
1606
- */
1607
- function _stop_element_handler($parser, $name)
1608
- {
1609
- if (isset($this->current)) {
1610
- $this->current = new BigInteger(base64_decode($this->current), 256);
1611
- unset($this->current);
1612
- }
1613
- }
1614
-
1615
- /**
1616
- * Data Handler
1617
- *
1618
- * Called by xml_set_character_data_handler()
1619
- *
1620
- * @access private
1621
- * @param resource $parser
1622
- * @param string $data
1623
- */
1624
- function _data_handler($parser, $data)
1625
- {
1626
- if (!isset($this->current) || is_object($this->current)) {
1627
- return;
1628
- }
1629
- $this->current.= trim($data);
1630
- }
1631
-
1632
- /**
1633
- * Loads a public or private key
1634
- *
1635
- * Returns true on success and false on failure (ie. an incorrect password was provided or the key was malformed)
1636
- *
1637
- * @access public
1638
- * @param string|RSA|array $key
1639
- * @param bool|int $type optional
1640
- * @return bool
1641
- */
1642
- function loadKey($key, $type = false)
1643
- {
1644
- if ($key instanceof RSA) {
1645
- $this->privateKeyFormat = $key->privateKeyFormat;
1646
- $this->publicKeyFormat = $key->publicKeyFormat;
1647
- $this->k = $key->k;
1648
- $this->hLen = $key->hLen;
1649
- $this->sLen = $key->sLen;
1650
- $this->mgfHLen = $key->mgfHLen;
1651
- $this->encryptionMode = $key->encryptionMode;
1652
- $this->signatureMode = $key->signatureMode;
1653
- $this->password = $key->password;
1654
- $this->configFile = $key->configFile;
1655
- $this->comment = $key->comment;
1656
-
1657
- if (is_object($key->hash)) {
1658
- $this->hash = new Hash($key->hash->getHash());
1659
- }
1660
- if (is_object($key->mgfHash)) {
1661
- $this->mgfHash = new Hash($key->mgfHash->getHash());
1662
- }
1663
-
1664
- if (is_object($key->modulus)) {
1665
- $this->modulus = $key->modulus->copy();
1666
- }
1667
- if (is_object($key->exponent)) {
1668
- $this->exponent = $key->exponent->copy();
1669
- }
1670
- if (is_object($key->publicExponent)) {
1671
- $this->publicExponent = $key->publicExponent->copy();
1672
- }
1673
-
1674
- $this->primes = array();
1675
- $this->exponents = array();
1676
- $this->coefficients = array();
1677
-
1678
- foreach ($this->primes as $prime) {
1679
- $this->primes[] = $prime->copy();
1680
- }
1681
- foreach ($this->exponents as $exponent) {
1682
- $this->exponents[] = $exponent->copy();
1683
- }
1684
- foreach ($this->coefficients as $coefficient) {
1685
- $this->coefficients[] = $coefficient->copy();
1686
- }
1687
-
1688
- return true;
1689
- }
1690
-
1691
- if ($type === false) {
1692
- $types = array(
1693
- self::PUBLIC_FORMAT_RAW,
1694
- self::PRIVATE_FORMAT_PKCS1,
1695
- self::PRIVATE_FORMAT_XML,
1696
- self::PRIVATE_FORMAT_PUTTY,
1697
- self::PUBLIC_FORMAT_OPENSSH,
1698
- self::PRIVATE_FORMAT_OPENSSH
1699
- );
1700
- foreach ($types as $type) {
1701
- $components = $this->_parseKey($key, $type);
1702
- if ($components !== false) {
1703
- break;
1704
- }
1705
- }
1706
- } else {
1707
- $components = $this->_parseKey($key, $type);
1708
- }
1709
-
1710
- if ($components === false) {
1711
- $this->comment = null;
1712
- $this->modulus = null;
1713
- $this->k = null;
1714
- $this->exponent = null;
1715
- $this->primes = null;
1716
- $this->exponents = null;
1717
- $this->coefficients = null;
1718
- $this->publicExponent = null;
1719
-
1720
- return false;
1721
- }
1722
-
1723
- if (isset($components['comment']) && $components['comment'] !== false) {
1724
- $this->comment = $components['comment'];
1725
- }
1726
- $this->modulus = $components['modulus'];
1727
- $this->k = strlen($this->modulus->toBytes());
1728
- $this->exponent = isset($components['privateExponent']) ? $components['privateExponent'] : $components['publicExponent'];
1729
- if (isset($components['primes'])) {
1730
- $this->primes = $components['primes'];
1731
- $this->exponents = $components['exponents'];
1732
- $this->coefficients = $components['coefficients'];
1733
- $this->publicExponent = $components['publicExponent'];
1734
- } else {
1735
- $this->primes = array();
1736
- $this->exponents = array();
1737
- $this->coefficients = array();
1738
- $this->publicExponent = false;
1739
- }
1740
-
1741
- switch ($type) {
1742
- case self::PUBLIC_FORMAT_OPENSSH:
1743
- case self::PUBLIC_FORMAT_RAW:
1744
- $this->setPublicKey();
1745
- break;
1746
- case self::PRIVATE_FORMAT_PKCS1:
1747
- switch (true) {
1748
- case strpos($key, '-BEGIN PUBLIC KEY-') !== false:
1749
- case strpos($key, '-BEGIN RSA PUBLIC KEY-') !== false:
1750
- $this->setPublicKey();
1751
- }
1752
- }
1753
-
1754
- return true;
1755
- }
1756
-
1757
- /**
1758
- * Sets the password
1759
- *
1760
- * Private keys can be encrypted with a password. To unset the password, pass in the empty string or false.
1761
- * Or rather, pass in $password such that empty($password) && !is_string($password) is true.
1762
- *
1763
- * @see self::createKey()
1764
- * @see self::loadKey()
1765
- * @access public
1766
- * @param string $password
1767
- */
1768
- function setPassword($password = false)
1769
- {
1770
- $this->password = $password;
1771
- }
1772
-
1773
- /**
1774
- * Defines the public key
1775
- *
1776
- * Some private key formats define the public exponent and some don't. Those that don't define it are problematic when
1777
- * used in certain contexts. For example, in SSH-2, RSA authentication works by sending the public key along with a
1778
- * message signed by the private key to the server. The SSH-2 server looks the public key up in an index of public keys
1779
- * and if it's present then proceeds to verify the signature. Problem is, if your private key doesn't include the public
1780
- * exponent this won't work unless you manually add the public exponent. phpseclib tries to guess if the key being used
1781
- * is the public key but in the event that it guesses incorrectly you might still want to explicitly set the key as being
1782
- * public.
1783
- *
1784
- * Do note that when a new key is loaded the index will be cleared.
1785
- *
1786
- * Returns true on success, false on failure
1787
- *
1788
- * @see self::getPublicKey()
1789
- * @access public
1790
- * @param string $key optional
1791
- * @param int $type optional
1792
- * @return bool
1793
- */
1794
- function setPublicKey($key = false, $type = false)
1795
- {
1796
- // if a public key has already been loaded return false
1797
- if (!empty($this->publicExponent)) {
1798
- return false;
1799
- }
1800
-
1801
- if ($key === false && !empty($this->modulus)) {
1802
- $this->publicExponent = $this->exponent;
1803
- return true;
1804
- }
1805
-
1806
- if ($type === false) {
1807
- $types = array(
1808
- self::PUBLIC_FORMAT_RAW,
1809
- self::PUBLIC_FORMAT_PKCS1,
1810
- self::PUBLIC_FORMAT_XML,
1811
- self::PUBLIC_FORMAT_OPENSSH
1812
- );
1813
- foreach ($types as $type) {
1814
- $components = $this->_parseKey($key, $type);
1815
- if ($components !== false) {
1816
- break;
1817
- }
1818
- }
1819
- } else {
1820
- $components = $this->_parseKey($key, $type);
1821
- }
1822
-
1823
- if ($components === false) {
1824
- return false;
1825
- }
1826
-
1827
- if (empty($this->modulus) || !$this->modulus->equals($components['modulus'])) {
1828
- $this->modulus = $components['modulus'];
1829
- $this->exponent = $this->publicExponent = $components['publicExponent'];
1830
- return true;
1831
- }
1832
-
1833
- $this->publicExponent = $components['publicExponent'];
1834
-
1835
- return true;
1836
- }
1837
-
1838
- /**
1839
- * Defines the private key
1840
- *
1841
- * If phpseclib guessed a private key was a public key and loaded it as such it might be desirable to force
1842
- * phpseclib to treat the key as a private key. This function will do that.
1843
- *
1844
- * Do note that when a new key is loaded the index will be cleared.
1845
- *
1846
- * Returns true on success, false on failure
1847
- *
1848
- * @see self::getPublicKey()
1849
- * @access public
1850
- * @param string $key optional
1851
- * @param int $type optional
1852
- * @return bool
1853
- */
1854
- function setPrivateKey($key = false, $type = false)
1855
- {
1856
- if ($key === false && !empty($this->publicExponent)) {
1857
- $this->publicExponent = false;
1858
- return true;
1859
- }
1860
-
1861
- $rsa = new RSA();
1862
- if (!$rsa->loadKey($key, $type)) {
1863
- return false;
1864
- }
1865
- $rsa->publicExponent = false;
1866
-
1867
- // don't overwrite the old key if the new key is invalid
1868
- $this->loadKey($rsa);
1869
- return true;
1870
- }
1871
-
1872
- /**
1873
- * Returns the public key
1874
- *
1875
- * The public key is only returned under two circumstances - if the private key had the public key embedded within it
1876
- * or if the public key was set via setPublicKey(). If the currently loaded key is supposed to be the public key this
1877
- * function won't return it since this library, for the most part, doesn't distinguish between public and private keys.
1878
- *
1879
- * @see self::getPublicKey()
1880
- * @access public
1881
- * @param string $key
1882
- * @param int $type optional
1883
- */
1884
- function getPublicKey($type = self::PUBLIC_FORMAT_PKCS8)
1885
- {
1886
- if (empty($this->modulus) || empty($this->publicExponent)) {
1887
- return false;
1888
- }
1889
-
1890
- $oldFormat = $this->publicKeyFormat;
1891
- $this->publicKeyFormat = $type;
1892
- $temp = $this->_convertPublicKey($this->modulus, $this->publicExponent);
1893
- $this->publicKeyFormat = $oldFormat;
1894
- return $temp;
1895
- }
1896
-
1897
- /**
1898
- * Returns the public key's fingerprint
1899
- *
1900
- * The public key's fingerprint is returned, which is equivalent to running `ssh-keygen -lf rsa.pub`. If there is
1901
- * no public key currently loaded, false is returned.
1902
- * Example output (md5): "c1:b1:30:29:d7:b8:de:6c:97:77:10:d7:46:41:63:87" (as specified by RFC 4716)
1903
- *
1904
- * @access public
1905
- * @param string $algorithm The hashing algorithm to be used. Valid options are 'md5' and 'sha256'. False is returned
1906
- * for invalid values.
1907
- * @return mixed
1908
- */
1909
- function getPublicKeyFingerprint($algorithm = 'md5')
1910
- {
1911
- if (empty($this->modulus) || empty($this->publicExponent)) {
1912
- return false;
1913
- }
1914
-
1915
- $modulus = $this->modulus->toBytes(true);
1916
- $publicExponent = $this->publicExponent->toBytes(true);
1917
-
1918
- $RSAPublicKey = pack('Na*Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($publicExponent), $publicExponent, strlen($modulus), $modulus);
1919
-
1920
- switch ($algorithm) {
1921
- case 'sha256':
1922
- $hash = new Hash('sha256');
1923
- $base = base64_encode($hash->hash($RSAPublicKey));
1924
- return substr($base, 0, strlen($base) - 1);
1925
- case 'md5':
1926
- return substr(chunk_split(md5($RSAPublicKey), 2, ':'), 0, -1);
1927
- default:
1928
- return false;
1929
- }
1930
- }
1931
-
1932
- /**
1933
- * Returns the private key
1934
- *
1935
- * The private key is only returned if the currently loaded key contains the constituent prime numbers.
1936
- *
1937
- * @see self::getPublicKey()
1938
- * @access public
1939
- * @param string $key
1940
- * @param int $type optional
1941
- * @return mixed
1942
- */
1943
- function getPrivateKey($type = self::PUBLIC_FORMAT_PKCS1)
1944
- {
1945
- if (empty($this->primes)) {
1946
- return false;
1947
- }
1948
-
1949
- $oldFormat = $this->privateKeyFormat;
1950
- $this->privateKeyFormat = $type;
1951
- $temp = $this->_convertPrivateKey($this->modulus, $this->publicExponent, $this->exponent, $this->primes, $this->exponents, $this->coefficients);
1952
- $this->privateKeyFormat = $oldFormat;
1953
- return $temp;
1954
- }
1955
-
1956
- /**
1957
- * Returns a minimalistic private key
1958
- *
1959
- * Returns the private key without the prime number constituants. Structurally identical to a public key that
1960
- * hasn't been set as the public key
1961
- *
1962
- * @see self::getPrivateKey()
1963
- * @access private
1964
- * @param string $key
1965
- * @param int $type optional
1966
- */
1967
- function _getPrivatePublicKey($mode = self::PUBLIC_FORMAT_PKCS8)
1968
- {
1969
- if (empty($this->modulus) || empty($this->exponent)) {
1970
- return false;
1971
- }
1972
-
1973
- $oldFormat = $this->publicKeyFormat;
1974
- $this->publicKeyFormat = $mode;
1975
- $temp = $this->_convertPublicKey($this->modulus, $this->exponent);
1976
- $this->publicKeyFormat = $oldFormat;
1977
- return $temp;
1978
- }
1979
-
1980
- /**
1981
- * __toString() magic method
1982
- *
1983
- * @access public
1984
- * @return string
1985
- */
1986
- function __toString()
1987
- {
1988
- $key = $this->getPrivateKey($this->privateKeyFormat);
1989
- if ($key !== false) {
1990
- return $key;
1991
- }
1992
- $key = $this->_getPrivatePublicKey($this->publicKeyFormat);
1993
- return $key !== false ? $key : '';
1994
- }
1995
-
1996
- /**
1997
- * __clone() magic method
1998
- *
1999
- * @access public
2000
- * @return Crypt_RSA
2001
- */
2002
- function __clone()
2003
- {
2004
- $key = new RSA();
2005
- $key->loadKey($this);
2006
- return $key;
2007
- }
2008
-
2009
- /**
2010
- * Generates the smallest and largest numbers requiring $bits bits
2011
- *
2012
- * @access private
2013
- * @param int $bits
2014
- * @return array
2015
- */
2016
- function _generateMinMax($bits)
2017
- {
2018
- $bytes = $bits >> 3;
2019
- $min = str_repeat(chr(0), $bytes);
2020
- $max = str_repeat(chr(0xFF), $bytes);
2021
- $msb = $bits & 7;
2022
- if ($msb) {
2023
- $min = chr(1 << ($msb - 1)) . $min;
2024
- $max = chr((1 << $msb) - 1) . $max;
2025
- } else {
2026
- $min[0] = chr(0x80);
2027
- }
2028
-
2029
- return array(
2030
- 'min' => new BigInteger($min, 256),
2031
- 'max' => new BigInteger($max, 256)
2032
- );
2033
- }
2034
-
2035
- /**
2036
- * DER-decode the length
2037
- *
2038
- * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See
2039
- * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information.
2040
- *
2041
- * @access private
2042
- * @param string $string
2043
- * @return int
2044
- */
2045
- function _decodeLength(&$string)
2046
- {
2047
- $length = ord($this->_string_shift($string));
2048
- if ($length & 0x80) { // definite length, long form
2049
- $length&= 0x7F;
2050
- $temp = $this->_string_shift($string, $length);
2051
- list(, $length) = unpack('N', substr(str_pad($temp, 4, chr(0), STR_PAD_LEFT), -4));
2052
- }
2053
- return $length;
2054
- }
2055
-
2056
- /**
2057
- * DER-encode the length
2058
- *
2059
- * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See
2060
- * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information.
2061
- *
2062
- * @access private
2063
- * @param int $length
2064
- * @return string
2065
- */
2066
- function _encodeLength($length)
2067
- {
2068
- if ($length <= 0x7F) {
2069
- return chr($length);
2070
- }
2071
-
2072
- $temp = ltrim(pack('N', $length), chr(0));
2073
- return pack('Ca*', 0x80 | strlen($temp), $temp);
2074
- }
2075
-
2076
- /**
2077
- * String Shift
2078
- *
2079
- * Inspired by array_shift
2080
- *
2081
- * @param string $string
2082
- * @param int $index
2083
- * @return string
2084
- * @access private
2085
- */
2086
- function _string_shift(&$string, $index = 1)
2087
- {
2088
- $substr = substr($string, 0, $index);
2089
- $string = substr($string, $index);
2090
- return $substr;
2091
- }
2092
-
2093
- /**
2094
- * Determines the private key format
2095
- *
2096
- * @see self::createKey()
2097
- * @access public
2098
- * @param int $format
2099
- */
2100
- function setPrivateKeyFormat($format)
2101
- {
2102
- $this->privateKeyFormat = $format;
2103
- }
2104
-
2105
- /**
2106
- * Determines the public key format
2107
- *
2108
- * @see self::createKey()
2109
- * @access public
2110
- * @param int $format
2111
- */
2112
- function setPublicKeyFormat($format)
2113
- {
2114
- $this->publicKeyFormat = $format;
2115
- }
2116
-
2117
- /**
2118
- * Determines which hashing function should be used
2119
- *
2120
- * Used with signature production / verification and (if the encryption mode is self::ENCRYPTION_OAEP) encryption and
2121
- * decryption. If $hash isn't supported, sha1 is used.
2122
- *
2123
- * @access public
2124
- * @param string $hash
2125
- */
2126
- function setHash($hash)
2127
- {
2128
- // \phpseclib\Crypt\Hash supports algorithms that PKCS#1 doesn't support. md5-96 and sha1-96, for example.
2129
- switch ($hash) {
2130
- case 'md2':
2131
- case 'md5':
2132
- case 'sha1':
2133
- case 'sha256':
2134
- case 'sha384':
2135
- case 'sha512':
2136
- $this->hash = new Hash($hash);
2137
- $this->hashName = $hash;
2138
- break;
2139
- default:
2140
- $this->hash = new Hash('sha1');
2141
- $this->hashName = 'sha1';
2142
- }
2143
- $this->hLen = $this->hash->getLength();
2144
- }
2145
-
2146
- /**
2147
- * Determines which hashing function should be used for the mask generation function
2148
- *
2149
- * The mask generation function is used by self::ENCRYPTION_OAEP and self::SIGNATURE_PSS and although it's
2150
- * best if Hash and MGFHash are set to the same thing this is not a requirement.
2151
- *
2152
- * @access public
2153
- * @param string $hash
2154
- */
2155
- function setMGFHash($hash)
2156
- {
2157
- // \phpseclib\Crypt\Hash supports algorithms that PKCS#1 doesn't support. md5-96 and sha1-96, for example.
2158
- switch ($hash) {
2159
- case 'md2':
2160
- case 'md5':
2161
- case 'sha1':
2162
- case 'sha256':
2163
- case 'sha384':
2164
- case 'sha512':
2165
- $this->mgfHash = new Hash($hash);
2166
- break;
2167
- default:
2168
- $this->mgfHash = new Hash('sha1');
2169
- }
2170
- $this->mgfHLen = $this->mgfHash->getLength();
2171
- }
2172
-
2173
- /**
2174
- * Determines the salt length
2175
- *
2176
- * To quote from {@link http://tools.ietf.org/html/rfc3447#page-38 RFC3447#page-38}:
2177
- *
2178
- * Typical salt lengths in octets are hLen (the length of the output
2179
- * of the hash function Hash) and 0.
2180
- *
2181
- * @access public
2182
- * @param int $format
2183
- */
2184
- function setSaltLength($sLen)
2185
- {
2186
- $this->sLen = $sLen;
2187
- }
2188
-
2189
- /**
2190
- * Integer-to-Octet-String primitive
2191
- *
2192
- * See {@link http://tools.ietf.org/html/rfc3447#section-4.1 RFC3447#section-4.1}.
2193
- *
2194
- * @access private
2195
- * @param \phpseclib\Math\BigInteger $x
2196
- * @param int $xLen
2197
- * @return string
2198
- */
2199
- function _i2osp($x, $xLen)
2200
- {
2201
- $x = $x->toBytes();
2202
- if (strlen($x) > $xLen) {
2203
- user_error('Integer too large');
2204
- return false;
2205
- }
2206
- return str_pad($x, $xLen, chr(0), STR_PAD_LEFT);
2207
- }
2208
-
2209
- /**
2210
- * Octet-String-to-Integer primitive
2211
- *
2212
- * See {@link http://tools.ietf.org/html/rfc3447#section-4.2 RFC3447#section-4.2}.
2213
- *
2214
- * @access private
2215
- * @param string $x
2216
- * @return \phpseclib\Math\BigInteger
2217
- */
2218
- function _os2ip($x)
2219
- {
2220
- return new BigInteger($x, 256);
2221
- }
2222
-
2223
- /**
2224
- * Exponentiate with or without Chinese Remainder Theorem
2225
- *
2226
- * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.1 RFC3447#section-5.1.2}.
2227
- *
2228
- * @access private
2229
- * @param \phpseclib\Math\BigInteger $x
2230
- * @return \phpseclib\Math\BigInteger
2231
- */
2232
- function _exponentiate($x)
2233
- {
2234
- switch (true) {
2235
- case empty($this->primes):
2236
- case $this->primes[1]->equals($this->zero):
2237
- case empty($this->coefficients):
2238
- case $this->coefficients[2]->equals($this->zero):
2239
- case empty($this->exponents):
2240
- case $this->exponents[1]->equals($this->zero):
2241
- return $x->modPow($this->exponent, $this->modulus);
2242
- }
2243
-
2244
- $num_primes = count($this->primes);
2245
-
2246
- if (defined('CRYPT_RSA_DISABLE_BLINDING')) {
2247
- $m_i = array(
2248
- 1 => $x->modPow($this->exponents[1], $this->primes[1]),
2249
- 2 => $x->modPow($this->exponents[2], $this->primes[2])
2250
- );
2251
- $h = $m_i[1]->subtract($m_i[2]);
2252
- $h = $h->multiply($this->coefficients[2]);
2253
- list(, $h) = $h->divide($this->primes[1]);
2254
- $m = $m_i[2]->add($h->multiply($this->primes[2]));
2255
-
2256
- $r = $this->primes[1];
2257
- for ($i = 3; $i <= $num_primes; $i++) {
2258
- $m_i = $x->modPow($this->exponents[$i], $this->primes[$i]);
2259
-
2260
- $r = $r->multiply($this->primes[$i - 1]);
2261
-
2262
- $h = $m_i->subtract($m);
2263
- $h = $h->multiply($this->coefficients[$i]);
2264
- list(, $h) = $h->divide($this->primes[$i]);
2265
-
2266
- $m = $m->add($r->multiply($h));
2267
- }
2268
- } else {
2269
- $smallest = $this->primes[1];
2270
- for ($i = 2; $i <= $num_primes; $i++) {
2271
- if ($smallest->compare($this->primes[$i]) > 0) {
2272
- $smallest = $this->primes[$i];
2273
- }
2274
- }
2275
-
2276
- $one = new BigInteger(1);
2277
-
2278
- $r = $one->random($one, $smallest->subtract($one));
2279
-
2280
- $m_i = array(
2281
- 1 => $this->_blind($x, $r, 1),
2282
- 2 => $this->_blind($x, $r, 2)
2283
- );
2284
- $h = $m_i[1]->subtract($m_i[2]);
2285
- $h = $h->multiply($this->coefficients[2]);
2286
- list(, $h) = $h->divide($this->primes[1]);
2287
- $m = $m_i[2]->add($h->multiply($this->primes[2]));
2288
-
2289
- $r = $this->primes[1];
2290
- for ($i = 3; $i <= $num_primes; $i++) {
2291
- $m_i = $this->_blind($x, $r, $i);
2292
-
2293
- $r = $r->multiply($this->primes[$i - 1]);
2294
-
2295
- $h = $m_i->subtract($m);
2296
- $h = $h->multiply($this->coefficients[$i]);
2297
- list(, $h) = $h->divide($this->primes[$i]);
2298
-
2299
- $m = $m->add($r->multiply($h));
2300
- }
2301
- }
2302
-
2303
- return $m;
2304
- }
2305
-
2306
- /**
2307
- * Performs RSA Blinding
2308
- *
2309
- * Protects against timing attacks by employing RSA Blinding.
2310
- * Returns $x->modPow($this->exponents[$i], $this->primes[$i])
2311
- *
2312
- * @access private
2313
- * @param \phpseclib\Math\BigInteger $x
2314
- * @param \phpseclib\Math\BigInteger $r
2315
- * @param int $i
2316
- * @return \phpseclib\Math\BigInteger
2317
- */
2318
- function _blind($x, $r, $i)
2319
- {
2320
- $x = $x->multiply($r->modPow($this->publicExponent, $this->primes[$i]));
2321
- $x = $x->modPow($this->exponents[$i], $this->primes[$i]);
2322
-
2323
- $r = $r->modInverse($this->primes[$i]);
2324
- $x = $x->multiply($r);
2325
- list(, $x) = $x->divide($this->primes[$i]);
2326
-
2327
- return $x;
2328
- }
2329
-
2330
- /**
2331
- * Performs blinded RSA equality testing
2332
- *
2333
- * Protects against a particular type of timing attack described.
2334
- *
2335
- * See {@link http://codahale.com/a-lesson-in-timing-attacks/ A Lesson In Timing Attacks (or, Don't use MessageDigest.isEquals)}
2336
- *
2337
- * Thanks for the heads up singpolyma!
2338
- *
2339
- * @access private
2340
- * @param string $x
2341
- * @param string $y
2342
- * @return bool
2343
- */
2344
- function _equals($x, $y)
2345
- {
2346
- if (function_exists('hash_equals')) {
2347
- return hash_equals($x, $y);
2348
- }
2349
-
2350
- if (strlen($x) != strlen($y)) {
2351
- return false;
2352
- }
2353
-
2354
- $result = "\0";
2355
- $x^= $y;
2356
- for ($i = 0; $i < strlen($x); $i++) {
2357
- $result|= $x[$i];
2358
- }
2359
-
2360
- return $result === "\0";
2361
- }
2362
-
2363
- /**
2364
- * RSAEP
2365
- *
2366
- * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.1 RFC3447#section-5.1.1}.
2367
- *
2368
- * @access private
2369
- * @param \phpseclib\Math\BigInteger $m
2370
- * @return \phpseclib\Math\BigInteger
2371
- */
2372
- function _rsaep($m)
2373
- {
2374
- if ($m->compare($this->zero) < 0 || $m->compare($this->modulus) > 0) {
2375
- user_error('Message representative out of range');
2376
- return false;
2377
- }
2378
- return $this->_exponentiate($m);
2379
- }
2380
-
2381
- /**
2382
- * RSADP
2383
- *
2384
- * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.2 RFC3447#section-5.1.2}.
2385
- *
2386
- * @access private
2387
- * @param \phpseclib\Math\BigInteger $c
2388
- * @return \phpseclib\Math\BigInteger
2389
- */
2390
- function _rsadp($c)
2391
- {
2392
- if ($c->compare($this->zero) < 0 || $c->compare($this->modulus) > 0) {
2393
- user_error('Ciphertext representative out of range');
2394
- return false;
2395
- }
2396
- return $this->_exponentiate($c);
2397
- }
2398
-
2399
- /**
2400
- * RSASP1
2401
- *
2402
- * See {@link http://tools.ietf.org/html/rfc3447#section-5.2.1 RFC3447#section-5.2.1}.
2403
- *
2404
- * @access private
2405
- * @param \phpseclib\Math\BigInteger $m
2406
- * @return \phpseclib\Math\BigInteger
2407
- */
2408
- function _rsasp1($m)
2409
- {
2410
- if ($m->compare($this->zero) < 0 || $m->compare($this->modulus) > 0) {
2411
- user_error('Message representative out of range');
2412
- return false;
2413
- }
2414
- return $this->_exponentiate($m);
2415
- }
2416
-
2417
- /**
2418
- * RSAVP1
2419
- *
2420
- * See {@link http://tools.ietf.org/html/rfc3447#section-5.2.2 RFC3447#section-5.2.2}.
2421
- *
2422
- * @access private
2423
- * @param \phpseclib\Math\BigInteger $s
2424
- * @return \phpseclib\Math\BigInteger
2425
- */
2426
- function _rsavp1($s)
2427
- {
2428
- if ($s->compare($this->zero) < 0 || $s->compare($this->modulus) > 0) {
2429
- user_error('Signature representative out of range');
2430
- return false;
2431
- }
2432
- return $this->_exponentiate($s);
2433
- }
2434
-
2435
- /**
2436
- * MGF1
2437
- *
2438
- * See {@link http://tools.ietf.org/html/rfc3447#appendix-B.2.1 RFC3447#appendix-B.2.1}.
2439
- *
2440
- * @access private
2441
- * @param string $mgfSeed
2442
- * @param int $mgfLen
2443
- * @return string
2444
- */
2445
- function _mgf1($mgfSeed, $maskLen)
2446
- {
2447
- // if $maskLen would yield strings larger than 4GB, PKCS#1 suggests a "Mask too long" error be output.
2448
-
2449
- $t = '';
2450
- $count = ceil($maskLen / $this->mgfHLen);
2451
- for ($i = 0; $i < $count; $i++) {
2452
- $c = pack('N', $i);
2453
- $t.= $this->mgfHash->hash($mgfSeed . $c);
2454
- }
2455
-
2456
- return substr($t, 0, $maskLen);
2457
- }
2458
-
2459
- /**
2460
- * RSAES-OAEP-ENCRYPT
2461
- *
2462
- * See {@link http://tools.ietf.org/html/rfc3447#section-7.1.1 RFC3447#section-7.1.1} and
2463
- * {http://en.wikipedia.org/wiki/Optimal_Asymmetric_Encryption_Padding OAES}.
2464
- *
2465
- * @access private
2466
- * @param string $m
2467
- * @param string $l
2468
- * @return string
2469
- */
2470
- function _rsaes_oaep_encrypt($m, $l = '')
2471
- {
2472
- $mLen = strlen($m);
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 ($mLen > $this->k - 2 * $this->hLen - 2) {
2480
- user_error('Message too long');
2481
- return false;
2482
- }
2483
-
2484
- // EME-OAEP encoding
2485
-
2486
- $lHash = $this->hash->hash($l);
2487
- $ps = str_repeat(chr(0), $this->k - $mLen - 2 * $this->hLen - 2);
2488
- $db = $lHash . $ps . chr(1) . $m;
2489
- $seed = Random::string($this->hLen);
2490
- $dbMask = $this->_mgf1($seed, $this->k - $this->hLen - 1);
2491
- $maskedDB = $db ^ $dbMask;
2492
- $seedMask = $this->_mgf1($maskedDB, $this->hLen);
2493
- $maskedSeed = $seed ^ $seedMask;
2494
- $em = chr(0) . $maskedSeed . $maskedDB;
2495
-
2496
- // RSA encryption
2497
-
2498
- $m = $this->_os2ip($em);
2499
- $c = $this->_rsaep($m);
2500
- $c = $this->_i2osp($c, $this->k);
2501
-
2502
- // Output the ciphertext C
2503
-
2504
- return $c;
2505
- }
2506
-
2507
- /**
2508
- * RSAES-OAEP-DECRYPT
2509
- *
2510
- * See {@link http://tools.ietf.org/html/rfc3447#section-7.1.2 RFC3447#section-7.1.2}. The fact that the error
2511
- * messages aren't distinguishable from one another hinders debugging, but, to quote from RFC3447#section-7.1.2:
2512
- *
2513
- * Note. Care must be taken to ensure that an opponent cannot
2514
- * distinguish the different error conditions in Step 3.g, whether by
2515
- * error message or timing, or, more generally, learn partial
2516
- * information about the encoded message EM. Otherwise an opponent may
2517
- * be able to obtain useful information about the decryption of the
2518
- * ciphertext C, leading to a chosen-ciphertext attack such as the one
2519
- * observed by Manger [36].
2520
- *
2521
- * As for $l... to quote from {@link http://tools.ietf.org/html/rfc3447#page-17 RFC3447#page-17}:
2522
- *
2523
- * Both the encryption and the decryption operations of RSAES-OAEP take
2524
- * the value of a label L as input. In this version of PKCS #1, L is
2525
- * the empty string; other uses of the label are outside the scope of
2526
- * this document.
2527
- *
2528
- * @access private
2529
- * @param string $c
2530
- * @param string $l
2531
- * @return string
2532
- */
2533
- function _rsaes_oaep_decrypt($c, $l = '')
2534
- {
2535
- // Length checking
2536
-
2537
- // if $l is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
2538
- // be output.
2539
-
2540
- if (strlen($c) != $this->k || $this->k < 2 * $this->hLen + 2) {
2541
- user_error('Decryption error');
2542
- return false;
2543
- }
2544
-
2545
- // RSA decryption
2546
-
2547
- $c = $this->_os2ip($c);
2548
- $m = $this->_rsadp($c);
2549
- if ($m === false) {
2550
- user_error('Decryption error');
2551
- return false;
2552
- }
2553
- $em = $this->_i2osp($m, $this->k);
2554
-
2555
- // EME-OAEP decoding
2556
-
2557
- $lHash = $this->hash->hash($l);
2558
- $y = ord($em[0]);
2559
- $maskedSeed = substr($em, 1, $this->hLen);
2560
- $maskedDB = substr($em, $this->hLen + 1);
2561
- $seedMask = $this->_mgf1($maskedDB, $this->hLen);
2562
- $seed = $maskedSeed ^ $seedMask;
2563
- $dbMask = $this->_mgf1($seed, $this->k - $this->hLen - 1);
2564
- $db = $maskedDB ^ $dbMask;
2565
- $lHash2 = substr($db, 0, $this->hLen);
2566
- $m = substr($db, $this->hLen);
2567
- $hashesMatch = $this->_equals($lHash, $lHash2);
2568
- $leadingZeros = 1;
2569
- $patternMatch = 0;
2570
- $offset = 0;
2571
- for ($i = 0; $i < strlen($m); $i++) {
2572
- $patternMatch|= $leadingZeros & ($m[$i] === "\1");
2573
- $leadingZeros&= $m[$i] === "\0";
2574
- $offset+= $patternMatch ? 0 : 1;
2575
- }
2576
-
2577
- // we do & instead of && to avoid https://en.wikipedia.org/wiki/Short-circuit_evaluation
2578
- // to protect against timing attacks
2579
- if (!$hashesMatch & !$patternMatch) {
2580
- user_error('Decryption error');
2581
- return false;
2582
- }
2583
-
2584
- // Output the message M
2585
-
2586
- return substr($m, $offset + 1);
2587
- }
2588
-
2589
- /**
2590
- * Raw Encryption / Decryption
2591
- *
2592
- * Doesn't use padding and is not recommended.
2593
- *
2594
- * @access private
2595
- * @param string $m
2596
- * @return string
2597
- */
2598
- function _raw_encrypt($m)
2599
- {
2600
- $temp = $this->_os2ip($m);
2601
- $temp = $this->_rsaep($temp);
2602
- return $this->_i2osp($temp, $this->k);
2603
- }
2604
-
2605
- /**
2606
- * RSAES-PKCS1-V1_5-ENCRYPT
2607
- *
2608
- * See {@link http://tools.ietf.org/html/rfc3447#section-7.2.1 RFC3447#section-7.2.1}.
2609
- *
2610
- * @access private
2611
- * @param string $m
2612
- * @return string
2613
- */
2614
- function _rsaes_pkcs1_v1_5_encrypt($m)
2615
- {
2616
- $mLen = strlen($m);
2617
-
2618
- // Length checking
2619
-
2620
- if ($mLen > $this->k - 11) {
2621
- user_error('Message too long');
2622
- return false;
2623
- }
2624
-
2625
- // EME-PKCS1-v1_5 encoding
2626
-
2627
- $psLen = $this->k - $mLen - 3;
2628
- $ps = '';
2629
- while (strlen($ps) != $psLen) {
2630
- $temp = Random::string($psLen - strlen($ps));
2631
- $temp = str_replace("\x00", '', $temp);
2632
- $ps.= $temp;
2633
- }
2634
- $type = 2;
2635
- // see the comments of _rsaes_pkcs1_v1_5_decrypt() to understand why this is being done
2636
- if (defined('CRYPT_RSA_PKCS15_COMPAT') && (!isset($this->publicExponent) || $this->exponent !== $this->publicExponent)) {
2637
- $type = 1;
2638
- // "The padding string PS shall consist of k-3-||D|| octets. ... for block type 01, they shall have value FF"
2639
- $ps = str_repeat("\xFF", $psLen);
2640
- }
2641
- $em = chr(0) . chr($type) . $ps . chr(0) . $m;
2642
-
2643
- // RSA encryption
2644
- $m = $this->_os2ip($em);
2645
- $c = $this->_rsaep($m);
2646
- $c = $this->_i2osp($c, $this->k);
2647
-
2648
- // Output the ciphertext C
2649
-
2650
- return $c;
2651
- }
2652
-
2653
- /**
2654
- * RSAES-PKCS1-V1_5-DECRYPT
2655
- *
2656
- * See {@link http://tools.ietf.org/html/rfc3447#section-7.2.2 RFC3447#section-7.2.2}.
2657
- *
2658
- * For compatibility purposes, this function departs slightly from the description given in RFC3447.
2659
- * The reason being that RFC2313#section-8.1 (PKCS#1 v1.5) states that ciphertext's encrypted by the
2660
- * private key should have the second byte set to either 0 or 1 and that ciphertext's encrypted by the
2661
- * public key should have the second byte set to 2. In RFC3447 (PKCS#1 v2.1), the second byte is supposed
2662
- * to be 2 regardless of which key is used. For compatibility purposes, we'll just check to make sure the
2663
- * second byte is 2 or less. If it is, we'll accept the decrypted string as valid.
2664
- *
2665
- * As a consequence of this, a private key encrypted ciphertext produced with \phpseclib\Crypt\RSA may not decrypt
2666
- * with a strictly PKCS#1 v1.5 compliant RSA implementation. Public key encrypted ciphertext's should but
2667
- * not private key encrypted ciphertext's.
2668
- *
2669
- * @access private
2670
- * @param string $c
2671
- * @return string
2672
- */
2673
- function _rsaes_pkcs1_v1_5_decrypt($c)
2674
- {
2675
- // Length checking
2676
-
2677
- if (strlen($c) != $this->k) { // or if k < 11
2678
- user_error('Decryption error');
2679
- return false;
2680
- }
2681
-
2682
- // RSA decryption
2683
-
2684
- $c = $this->_os2ip($c);
2685
- $m = $this->_rsadp($c);
2686
-
2687
- if ($m === false) {
2688
- user_error('Decryption error');
2689
- return false;
2690
- }
2691
- $em = $this->_i2osp($m, $this->k);
2692
-
2693
- // EME-PKCS1-v1_5 decoding
2694
-
2695
- if (ord($em[0]) != 0 || ord($em[1]) > 2) {
2696
- user_error('Decryption error');
2697
- return false;
2698
- }
2699
-
2700
- $ps = substr($em, 2, strpos($em, chr(0), 2) - 2);
2701
- $m = substr($em, strlen($ps) + 3);
2702
-
2703
- if (strlen($ps) < 8) {
2704
- user_error('Decryption error');
2705
- return false;
2706
- }
2707
-
2708
- // Output M
2709
-
2710
- return $m;
2711
- }
2712
-
2713
- /**
2714
- * EMSA-PSS-ENCODE
2715
- *
2716
- * See {@link http://tools.ietf.org/html/rfc3447#section-9.1.1 RFC3447#section-9.1.1}.
2717
- *
2718
- * @access private
2719
- * @param string $m
2720
- * @param int $emBits
2721
- */
2722
- function _emsa_pss_encode($m, $emBits)
2723
- {
2724
- // if $m is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
2725
- // be output.
2726
-
2727
- $emLen = ($emBits + 1) >> 3; // ie. ceil($emBits / 8)
2728
- $sLen = $this->sLen !== null ? $this->sLen : $this->hLen;
2729
-
2730
- $mHash = $this->hash->hash($m);
2731
- if ($emLen < $this->hLen + $sLen + 2) {
2732
- user_error('Encoding error');
2733
- return false;
2734
- }
2735
-
2736
- $salt = Random::string($sLen);
2737
- $m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt;
2738
- $h = $this->hash->hash($m2);
2739
- $ps = str_repeat(chr(0), $emLen - $sLen - $this->hLen - 2);
2740
- $db = $ps . chr(1) . $salt;
2741
- $dbMask = $this->_mgf1($h, $emLen - $this->hLen - 1);
2742
- $maskedDB = $db ^ $dbMask;
2743
- $maskedDB[0] = ~chr(0xFF << ($emBits & 7)) & $maskedDB[0];
2744
- $em = $maskedDB . $h . chr(0xBC);
2745
-
2746
- return $em;
2747
- }
2748
-
2749
- /**
2750
- * EMSA-PSS-VERIFY
2751
- *
2752
- * See {@link http://tools.ietf.org/html/rfc3447#section-9.1.2 RFC3447#section-9.1.2}.
2753
- *
2754
- * @access private
2755
- * @param string $m
2756
- * @param string $em
2757
- * @param int $emBits
2758
- * @return string
2759
- */
2760
- function _emsa_pss_verify($m, $em, $emBits)
2761
- {
2762
- // if $m is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
2763
- // be output.
2764
-
2765
- $emLen = ($emBits + 1) >> 3; // ie. ceil($emBits / 8);
2766
- $sLen = $this->sLen !== null ? $this->sLen : $this->hLen;
2767
-
2768
- $mHash = $this->hash->hash($m);
2769
- if ($emLen < $this->hLen + $sLen + 2) {
2770
- return false;
2771
- }
2772
-
2773
- if ($em[strlen($em) - 1] != chr(0xBC)) {
2774
- return false;
2775
- }
2776
-
2777
- $maskedDB = substr($em, 0, -$this->hLen - 1);
2778
- $h = substr($em, -$this->hLen - 1, $this->hLen);
2779
- $temp = chr(0xFF << ($emBits & 7));
2780
- if ((~$maskedDB[0] & $temp) != $temp) {
2781
- return false;
2782
- }
2783
- $dbMask = $this->_mgf1($h, $emLen - $this->hLen - 1);
2784
- $db = $maskedDB ^ $dbMask;
2785
- $db[0] = ~chr(0xFF << ($emBits & 7)) & $db[0];
2786
- $temp = $emLen - $this->hLen - $sLen - 2;
2787
- if (substr($db, 0, $temp) != str_repeat(chr(0), $temp) || ord($db[$temp]) != 1) {
2788
- return false;
2789
- }
2790
- $salt = substr($db, $temp + 1); // should be $sLen long
2791
- $m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt;
2792
- $h2 = $this->hash->hash($m2);
2793
- return $this->_equals($h, $h2);
2794
- }
2795
-
2796
- /**
2797
- * RSASSA-PSS-SIGN
2798
- *
2799
- * See {@link http://tools.ietf.org/html/rfc3447#section-8.1.1 RFC3447#section-8.1.1}.
2800
- *
2801
- * @access private
2802
- * @param string $m
2803
- * @return string
2804
- */
2805
- function _rsassa_pss_sign($m)
2806
- {
2807
- // EMSA-PSS encoding
2808
-
2809
- $em = $this->_emsa_pss_encode($m, 8 * $this->k - 1);
2810
-
2811
- // RSA signature
2812
-
2813
- $m = $this->_os2ip($em);
2814
- $s = $this->_rsasp1($m);
2815
- $s = $this->_i2osp($s, $this->k);
2816
-
2817
- // Output the signature S
2818
-
2819
- return $s;
2820
- }
2821
-
2822
- /**
2823
- * RSASSA-PSS-VERIFY
2824
- *
2825
- * See {@link http://tools.ietf.org/html/rfc3447#section-8.1.2 RFC3447#section-8.1.2}.
2826
- *
2827
- * @access private
2828
- * @param string $m
2829
- * @param string $s
2830
- * @return string
2831
- */
2832
- function _rsassa_pss_verify($m, $s)
2833
- {
2834
- // Length checking
2835
-
2836
- if (strlen($s) != $this->k) {
2837
- user_error('Invalid signature');
2838
- return false;
2839
- }
2840
-
2841
- // RSA verification
2842
-
2843
- $modBits = 8 * $this->k;
2844
-
2845
- $s2 = $this->_os2ip($s);
2846
- $m2 = $this->_rsavp1($s2);
2847
- if ($m2 === false) {
2848
- user_error('Invalid signature');
2849
- return false;
2850
- }
2851
- $em = $this->_i2osp($m2, $modBits >> 3);
2852
- if ($em === false) {
2853
- user_error('Invalid signature');
2854
- return false;
2855
- }
2856
-
2857
- // EMSA-PSS verification
2858
-
2859
- return $this->_emsa_pss_verify($m, $em, $modBits - 1);
2860
- }
2861
-
2862
- /**
2863
- * EMSA-PKCS1-V1_5-ENCODE
2864
- *
2865
- * See {@link http://tools.ietf.org/html/rfc3447#section-9.2 RFC3447#section-9.2}.
2866
- *
2867
- * @access private
2868
- * @param string $m
2869
- * @param int $emLen
2870
- * @return string
2871
- */
2872
- function _emsa_pkcs1_v1_5_encode($m, $emLen)
2873
- {
2874
- $h = $this->hash->hash($m);
2875
- if ($h === false) {
2876
- return false;
2877
- }
2878
-
2879
- // see http://tools.ietf.org/html/rfc3447#page-43
2880
- switch ($this->hashName) {
2881
- case 'md2':
2882
- $t = pack('H*', '3020300c06082a864886f70d020205000410');
2883
- break;
2884
- case 'md5':
2885
- $t = pack('H*', '3020300c06082a864886f70d020505000410');
2886
- break;
2887
- case 'sha1':
2888
- $t = pack('H*', '3021300906052b0e03021a05000414');
2889
- break;
2890
- case 'sha256':
2891
- $t = pack('H*', '3031300d060960864801650304020105000420');
2892
- break;
2893
- case 'sha384':
2894
- $t = pack('H*', '3041300d060960864801650304020205000430');
2895
- break;
2896
- case 'sha512':
2897
- $t = pack('H*', '3051300d060960864801650304020305000440');
2898
- }
2899
- $t.= $h;
2900
- $tLen = strlen($t);
2901
-
2902
- if ($emLen < $tLen + 11) {
2903
- user_error('Intended encoded message length too short');
2904
- return false;
2905
- }
2906
-
2907
- $ps = str_repeat(chr(0xFF), $emLen - $tLen - 3);
2908
-
2909
- $em = "\0\1$ps\0$t";
2910
-
2911
- return $em;
2912
- }
2913
-
2914
- /**
2915
- * RSASSA-PKCS1-V1_5-SIGN
2916
- *
2917
- * See {@link http://tools.ietf.org/html/rfc3447#section-8.2.1 RFC3447#section-8.2.1}.
2918
- *
2919
- * @access private
2920
- * @param string $m
2921
- * @return string
2922
- */
2923
- function _rsassa_pkcs1_v1_5_sign($m)
2924
- {
2925
- // EMSA-PKCS1-v1_5 encoding
2926
-
2927
- $em = $this->_emsa_pkcs1_v1_5_encode($m, $this->k);
2928
- if ($em === false) {
2929
- user_error('RSA modulus too short');
2930
- return false;
2931
- }
2932
-
2933
- // RSA signature
2934
-
2935
- $m = $this->_os2ip($em);
2936
- $s = $this->_rsasp1($m);
2937
- $s = $this->_i2osp($s, $this->k);
2938
-
2939
- // Output the signature S
2940
-
2941
- return $s;
2942
- }
2943
-
2944
- /**
2945
- * RSASSA-PKCS1-V1_5-VERIFY
2946
- *
2947
- * See {@link http://tools.ietf.org/html/rfc3447#section-8.2.2 RFC3447#section-8.2.2}.
2948
- *
2949
- * @access private
2950
- * @param string $m
2951
- * @return string
2952
- */
2953
- function _rsassa_pkcs1_v1_5_verify($m, $s)
2954
- {
2955
- // Length checking
2956
-
2957
- if (strlen($s) != $this->k) {
2958
- user_error('Invalid signature');
2959
- return false;
2960
- }
2961
-
2962
- // RSA verification
2963
-
2964
- $s = $this->_os2ip($s);
2965
- $m2 = $this->_rsavp1($s);
2966
- if ($m2 === false) {
2967
- user_error('Invalid signature');
2968
- return false;
2969
- }
2970
- $em = $this->_i2osp($m2, $this->k);
2971
- if ($em === false) {
2972
- user_error('Invalid signature');
2973
- return false;
2974
- }
2975
-
2976
- // EMSA-PKCS1-v1_5 encoding
2977
-
2978
- $em2 = $this->_emsa_pkcs1_v1_5_encode($m, $this->k);
2979
- if ($em2 === false) {
2980
- user_error('RSA modulus too short');
2981
- return false;
2982
- }
2983
-
2984
- // Compare
2985
- return $this->_equals($em, $em2);
2986
- }
2987
-
2988
- /**
2989
- * Set Encryption Mode
2990
- *
2991
- * Valid values include self::ENCRYPTION_OAEP and self::ENCRYPTION_PKCS1.
2992
- *
2993
- * @access public
2994
- * @param int $mode
2995
- */
2996
- function setEncryptionMode($mode)
2997
- {
2998
- $this->encryptionMode = $mode;
2999
- }
3000
-
3001
- /**
3002
- * Set Signature Mode
3003
- *
3004
- * Valid values include self::SIGNATURE_PSS and self::SIGNATURE_PKCS1
3005
- *
3006
- * @access public
3007
- * @param int $mode
3008
- */
3009
- function setSignatureMode($mode)
3010
- {
3011
- $this->signatureMode = $mode;
3012
- }
3013
-
3014
- /**
3015
- * Set public key comment.
3016
- *
3017
- * @access public
3018
- * @param string $comment
3019
- */
3020
- function setComment($comment)
3021
- {
3022
- $this->comment = $comment;
3023
- }
3024
-
3025
- /**
3026
- * Get public key comment.
3027
- *
3028
- * @access public
3029
- * @return string
3030
- */
3031
- function getComment()
3032
- {
3033
- return $this->comment;
3034
- }
3035
-
3036
- /**
3037
- * Encryption
3038
- *
3039
- * Both self::ENCRYPTION_OAEP and self::ENCRYPTION_PKCS1 both place limits on how long $plaintext can be.
3040
- * If $plaintext exceeds those limits it will be broken up so that it does and the resultant ciphertext's will
3041
- * be concatenated together.
3042
- *
3043
- * @see self::decrypt()
3044
- * @access public
3045
- * @param string $plaintext
3046
- * @return string
3047
- */
3048
- function encrypt($plaintext)
3049
- {
3050
- switch ($this->encryptionMode) {
3051
- case self::ENCRYPTION_NONE:
3052
- $plaintext = str_split($plaintext, $this->k);
3053
- $ciphertext = '';
3054
- foreach ($plaintext as $m) {
3055
- $ciphertext.= $this->_raw_encrypt($m);
3056
- }
3057
- return $ciphertext;
3058
- case self::ENCRYPTION_PKCS1:
3059
- $length = $this->k - 11;
3060
- if ($length <= 0) {
3061
- return false;
3062
- }
3063
-
3064
- $plaintext = str_split($plaintext, $length);
3065
- $ciphertext = '';
3066
- foreach ($plaintext as $m) {
3067
- $ciphertext.= $this->_rsaes_pkcs1_v1_5_encrypt($m);
3068
- }
3069
- return $ciphertext;
3070
- //case self::ENCRYPTION_OAEP:
3071
- default:
3072
- $length = $this->k - 2 * $this->hLen - 2;
3073
- if ($length <= 0) {
3074
- return false;
3075
- }
3076
-
3077
- $plaintext = str_split($plaintext, $length);
3078
- $ciphertext = '';
3079
- foreach ($plaintext as $m) {
3080
- $ciphertext.= $this->_rsaes_oaep_encrypt($m);
3081
- }
3082
- return $ciphertext;
3083
- }
3084
- }
3085
-
3086
- /**
3087
- * Decryption
3088
- *
3089
- * @see self::encrypt()
3090
- * @access public
3091
- * @param string $plaintext
3092
- * @return string
3093
- */
3094
- function decrypt($ciphertext)
3095
- {
3096
- if ($this->k <= 0) {
3097
- return false;
3098
- }
3099
-
3100
- $ciphertext = str_split($ciphertext, $this->k);
3101
- $ciphertext[count($ciphertext) - 1] = str_pad($ciphertext[count($ciphertext) - 1], $this->k, chr(0), STR_PAD_LEFT);
3102
-
3103
- $plaintext = '';
3104
-
3105
- switch ($this->encryptionMode) {
3106
- case self::ENCRYPTION_NONE:
3107
- $decrypt = '_raw_encrypt';
3108
- break;
3109
- case self::ENCRYPTION_PKCS1:
3110
- $decrypt = '_rsaes_pkcs1_v1_5_decrypt';
3111
- break;
3112
- //case self::ENCRYPTION_OAEP:
3113
- default:
3114
- $decrypt = '_rsaes_oaep_decrypt';
3115
- }
3116
-
3117
- foreach ($ciphertext as $c) {
3118
- $temp = $this->$decrypt($c);
3119
- if ($temp === false) {
3120
- return false;
3121
- }
3122
- $plaintext.= $temp;
3123
- }
3124
-
3125
- return $plaintext;
3126
- }
3127
-
3128
- /**
3129
- * Create a signature
3130
- *
3131
- * @see self::verify()
3132
- * @access public
3133
- * @param string $message
3134
- * @return string
3135
- */
3136
- function sign($message)
3137
- {
3138
- if (empty($this->modulus) || empty($this->exponent)) {
3139
- return false;
3140
- }
3141
-
3142
- switch ($this->signatureMode) {
3143
- case self::SIGNATURE_PKCS1:
3144
- return $this->_rsassa_pkcs1_v1_5_sign($message);
3145
- //case self::SIGNATURE_PSS:
3146
- default:
3147
- return $this->_rsassa_pss_sign($message);
3148
- }
3149
- }
3150
-
3151
- /**
3152
- * Verifies a signature
3153
- *
3154
- * @see self::sign()
3155
- * @access public
3156
- * @param string $message
3157
- * @param string $signature
3158
- * @return bool
3159
- */
3160
- function verify($message, $signature)
3161
- {
3162
- if (empty($this->modulus) || empty($this->exponent)) {
3163
- return false;
3164
- }
3165
-
3166
- switch ($this->signatureMode) {
3167
- case self::SIGNATURE_PKCS1:
3168
- return $this->_rsassa_pkcs1_v1_5_verify($message, $signature);
3169
- //case self::SIGNATURE_PSS:
3170
- default:
3171
- return $this->_rsassa_pss_verify($message, $signature);
3172
- }
3173
- }
3174
-
3175
- /**
3176
- * Extract raw BER from Base64 encoding
3177
- *
3178
- * @access private
3179
- * @param string $str
3180
- * @return string
3181
- */
3182
- function _extractBER($str)
3183
- {
3184
- /* X.509 certs are assumed to be base64 encoded but sometimes they'll have additional things in them
3185
- * above and beyond the ceritificate.
3186
- * ie. some may have the following preceding the -----BEGIN CERTIFICATE----- line:
3187
- *
3188
- * Bag Attributes
3189
- * localKeyID: 01 00 00 00
3190
- * subject=/O=organization/OU=org unit/CN=common name
3191
- * issuer=/O=organization/CN=common name
3192
- */
3193
- $temp = preg_replace('#.*?^-+[^-]+-+[\r\n ]*$#ms', '', $str, 1);
3194
- // remove the -----BEGIN CERTIFICATE----- and -----END CERTIFICATE----- stuff
3195
- $temp = preg_replace('#-+[^-]+-+#', '', $temp);
3196
- // remove new lines
3197
- $temp = str_replace(array("\r", "\n", ' '), '', $temp);
3198
- $temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? base64_decode($temp) : false;
3199
- return $temp != false ? $temp : $str;
3200
- }
3201
- }
1
+ <?php
2
+
3
+ /**
4
+ * Pure-PHP PKCS#1 (v2.1) compliant implementation of RSA.
5
+ *
6
+ * PHP version 5
7
+ *
8
+ * Here's an example of how to encrypt and decrypt text with this library:
9
+ * <code>
10
+ * <?php
11
+ * include 'vendor/autoload.php';
12
+ *
13
+ * $rsa = new \phpseclib\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 'vendor/autoload.php';
30
+ *
31
+ * $rsa = new \phpseclib\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
+ * @category Crypt
45
+ * @package RSA
46
+ * @author Jim Wigginton <terrafrost@php.net>
47
+ * @copyright 2009 Jim Wigginton
48
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
49
+ * @link http://phpseclib.sourceforge.net
50
+ */
51
+
52
+ namespace phpseclib\Crypt;
53
+
54
+ use phpseclib\Math\BigInteger;
55
+
56
+ /**
57
+ * Pure-PHP PKCS#1 compliant implementation of RSA.
58
+ *
59
+ * @package RSA
60
+ * @author Jim Wigginton <terrafrost@php.net>
61
+ * @access public
62
+ */
63
+ class RSA
64
+ {
65
+ /**#@+
66
+ * @access public
67
+ * @see self::encrypt()
68
+ * @see self::decrypt()
69
+ */
70
+ /**
71
+ * Use {@link http://en.wikipedia.org/wiki/Optimal_Asymmetric_Encryption_Padding Optimal Asymmetric Encryption Padding}
72
+ * (OAEP) for encryption / decryption.
73
+ *
74
+ * Uses sha1 by default.
75
+ *
76
+ * @see self::setHash()
77
+ * @see self::setMGFHash()
78
+ */
79
+ const ENCRYPTION_OAEP = 1;
80
+ /**
81
+ * Use PKCS#1 padding.
82
+ *
83
+ * Although self::ENCRYPTION_OAEP offers more security, including PKCS#1 padding is necessary for purposes of backwards
84
+ * compatibility with protocols (like SSH-1) written before OAEP's introduction.
85
+ */
86
+ const ENCRYPTION_PKCS1 = 2;
87
+ /**
88
+ * Do not use any padding
89
+ *
90
+ * Although this method is not recommended it can none-the-less sometimes be useful if you're trying to decrypt some legacy
91
+ * stuff, if you're trying to diagnose why an encrypted message isn't decrypting, etc.
92
+ */
93
+ const ENCRYPTION_NONE = 3;
94
+ /**#@-*/
95
+
96
+ /**#@+
97
+ * @access public
98
+ * @see self::sign()
99
+ * @see self::verify()
100
+ * @see self::setHash()
101
+ */
102
+ /**
103
+ * Use the Probabilistic Signature Scheme for signing
104
+ *
105
+ * Uses sha1 by default.
106
+ *
107
+ * @see self::setSaltLength()
108
+ * @see self::setMGFHash()
109
+ */
110
+ const SIGNATURE_PSS = 1;
111
+ /**
112
+ * Use the PKCS#1 scheme by default.
113
+ *
114
+ * Although self::SIGNATURE_PSS offers more security, including PKCS#1 signing is necessary for purposes of backwards
115
+ * compatibility with protocols (like SSH-2) written before PSS's introduction.
116
+ */
117
+ const SIGNATURE_PKCS1 = 2;
118
+ /**#@-*/
119
+
120
+ /**#@+
121
+ * @access private
122
+ * @see \phpseclib\Crypt\RSA::createKey()
123
+ */
124
+ /**
125
+ * ASN1 Integer
126
+ */
127
+ const ASN1_INTEGER = 2;
128
+ /**
129
+ * ASN1 Bit String
130
+ */
131
+ const ASN1_BITSTRING = 3;
132
+ /**
133
+ * ASN1 Octet String
134
+ */
135
+ const ASN1_OCTETSTRING = 4;
136
+ /**
137
+ * ASN1 Object Identifier
138
+ */
139
+ const ASN1_OBJECT = 6;
140
+ /**
141
+ * ASN1 Sequence (with the constucted bit set)
142
+ */
143
+ const ASN1_SEQUENCE = 48;
144
+ /**#@-*/
145
+
146
+ /**#@+
147
+ * @access private
148
+ * @see \phpseclib\Crypt\RSA::__construct()
149
+ */
150
+ /**
151
+ * To use the pure-PHP implementation
152
+ */
153
+ const MODE_INTERNAL = 1;
154
+ /**
155
+ * To use the OpenSSL library
156
+ *
157
+ * (if enabled; otherwise, the internal implementation will be used)
158
+ */
159
+ const MODE_OPENSSL = 2;
160
+ /**#@-*/
161
+
162
+ /**#@+
163
+ * @access public
164
+ * @see \phpseclib\Crypt\RSA::createKey()
165
+ * @see \phpseclib\Crypt\RSA::setPrivateKeyFormat()
166
+ */
167
+ /**
168
+ * PKCS#1 formatted private key
169
+ *
170
+ * Used by OpenSSH
171
+ */
172
+ const PRIVATE_FORMAT_PKCS1 = 0;
173
+ /**
174
+ * PuTTY formatted private key
175
+ */
176
+ const PRIVATE_FORMAT_PUTTY = 1;
177
+ /**
178
+ * XML formatted private key
179
+ */
180
+ const PRIVATE_FORMAT_XML = 2;
181
+ /**
182
+ * PKCS#8 formatted private key
183
+ */
184
+ const PRIVATE_FORMAT_PKCS8 = 8;
185
+ /**
186
+ * OpenSSH formatted private key
187
+ */
188
+ const PRIVATE_FORMAT_OPENSSH = 9;
189
+ /**#@-*/
190
+
191
+ /**#@+
192
+ * @access public
193
+ * @see \phpseclib\Crypt\RSA::createKey()
194
+ * @see \phpseclib\Crypt\RSA::setPublicKeyFormat()
195
+ */
196
+ /**
197
+ * Raw public key
198
+ *
199
+ * An array containing two \phpseclib\Math\BigInteger objects.
200
+ *
201
+ * The exponent can be indexed with any of the following:
202
+ *
203
+ * 0, e, exponent, publicExponent
204
+ *
205
+ * The modulus can be indexed with any of the following:
206
+ *
207
+ * 1, n, modulo, modulus
208
+ */
209
+ const PUBLIC_FORMAT_RAW = 3;
210
+ /**
211
+ * PKCS#1 formatted public key (raw)
212
+ *
213
+ * Used by File/X509.php
214
+ *
215
+ * Has the following header:
216
+ *
217
+ * -----BEGIN RSA PUBLIC KEY-----
218
+ *
219
+ * Analogous to ssh-keygen's pem format (as specified by -m)
220
+ */
221
+ const PUBLIC_FORMAT_PKCS1 = 4;
222
+ const PUBLIC_FORMAT_PKCS1_RAW = 4;
223
+ /**
224
+ * XML formatted public key
225
+ */
226
+ const PUBLIC_FORMAT_XML = 5;
227
+ /**
228
+ * OpenSSH formatted public key
229
+ *
230
+ * Place in $HOME/.ssh/authorized_keys
231
+ */
232
+ const PUBLIC_FORMAT_OPENSSH = 6;
233
+ /**
234
+ * PKCS#1 formatted public key (encapsulated)
235
+ *
236
+ * Used by PHP's openssl_public_encrypt() and openssl's rsautl (when -pubin is set)
237
+ *
238
+ * Has the following header:
239
+ *
240
+ * -----BEGIN PUBLIC KEY-----
241
+ *
242
+ * Analogous to ssh-keygen's pkcs8 format (as specified by -m). Although PKCS8
243
+ * is specific to private keys it's basically creating a DER-encoded wrapper
244
+ * for keys. This just extends that same concept to public keys (much like ssh-keygen)
245
+ */
246
+ const PUBLIC_FORMAT_PKCS8 = 7;
247
+ /**#@-*/
248
+
249
+ /**
250
+ * Precomputed Zero
251
+ *
252
+ * @var \phpseclib\Math\BigInteger
253
+ * @access private
254
+ */
255
+ var $zero;
256
+
257
+ /**
258
+ * Precomputed One
259
+ *
260
+ * @var \phpseclib\Math\BigInteger
261
+ * @access private
262
+ */
263
+ var $one;
264
+
265
+ /**
266
+ * Private Key Format
267
+ *
268
+ * @var int
269
+ * @access private
270
+ */
271
+ var $privateKeyFormat = self::PRIVATE_FORMAT_PKCS1;
272
+
273
+ /**
274
+ * Public Key Format
275
+ *
276
+ * @var int
277
+ * @access public
278
+ */
279
+ var $publicKeyFormat = self::PUBLIC_FORMAT_PKCS8;
280
+
281
+ /**
282
+ * Modulus (ie. n)
283
+ *
284
+ * @var \phpseclib\Math\BigInteger
285
+ * @access private
286
+ */
287
+ var $modulus;
288
+
289
+ /**
290
+ * Modulus length
291
+ *
292
+ * @var \phpseclib\Math\BigInteger
293
+ * @access private
294
+ */
295
+ var $k;
296
+
297
+ /**
298
+ * Exponent (ie. e or d)
299
+ *
300
+ * @var \phpseclib\Math\BigInteger
301
+ * @access private
302
+ */
303
+ var $exponent;
304
+
305
+ /**
306
+ * Primes for Chinese Remainder Theorem (ie. p and q)
307
+ *
308
+ * @var array
309
+ * @access private
310
+ */
311
+ var $primes;
312
+
313
+ /**
314
+ * Exponents for Chinese Remainder Theorem (ie. dP and dQ)
315
+ *
316
+ * @var array
317
+ * @access private
318
+ */
319
+ var $exponents;
320
+
321
+ /**
322
+ * Coefficients for Chinese Remainder Theorem (ie. qInv)
323
+ *
324
+ * @var array
325
+ * @access private
326
+ */
327
+ var $coefficients;
328
+
329
+ /**
330
+ * Hash name
331
+ *
332
+ * @var string
333
+ * @access private
334
+ */
335
+ var $hashName;
336
+
337
+ /**
338
+ * Hash function
339
+ *
340
+ * @var \phpseclib\Crypt\Hash
341
+ * @access private
342
+ */
343
+ var $hash;
344
+
345
+ /**
346
+ * Length of hash function output
347
+ *
348
+ * @var int
349
+ * @access private
350
+ */
351
+ var $hLen;
352
+
353
+ /**
354
+ * Length of salt
355
+ *
356
+ * @var int
357
+ * @access private
358
+ */
359
+ var $sLen;
360
+
361
+ /**
362
+ * Hash function for the Mask Generation Function
363
+ *
364
+ * @var \phpseclib\Crypt\Hash
365
+ * @access private
366
+ */
367
+ var $mgfHash;
368
+
369
+ /**
370
+ * Length of MGF hash function output
371
+ *
372
+ * @var int
373
+ * @access private
374
+ */
375
+ var $mgfHLen;
376
+
377
+ /**
378
+ * Encryption mode
379
+ *
380
+ * @var int
381
+ * @access private
382
+ */
383
+ var $encryptionMode = self::ENCRYPTION_OAEP;
384
+
385
+ /**
386
+ * Signature mode
387
+ *
388
+ * @var int
389
+ * @access private
390
+ */
391
+ var $signatureMode = self::SIGNATURE_PSS;
392
+
393
+ /**
394
+ * Public Exponent
395
+ *
396
+ * @var mixed
397
+ * @access private
398
+ */
399
+ var $publicExponent = false;
400
+
401
+ /**
402
+ * Password
403
+ *
404
+ * @var string
405
+ * @access private
406
+ */
407
+ var $password = false;
408
+
409
+ /**
410
+ * Components
411
+ *
412
+ * For use with parsing XML formatted keys. PHP's XML Parser functions use utilized - instead of PHP's DOM functions -
413
+ * because PHP's XML Parser functions work on PHP4 whereas PHP's DOM functions - although surperior - don't.
414
+ *
415
+ * @see self::_start_element_handler()
416
+ * @var array
417
+ * @access private
418
+ */
419
+ var $components = array();
420
+
421
+ /**
422
+ * Current String
423
+ *
424
+ * For use with parsing XML formatted keys.
425
+ *
426
+ * @see self::_character_handler()
427
+ * @see self::_stop_element_handler()
428
+ * @var mixed
429
+ * @access private
430
+ */
431
+ var $current;
432
+
433
+ /**
434
+ * OpenSSL configuration file name.
435
+ *
436
+ * Set to null to use system configuration file.
437
+ * @see self::createKey()
438
+ * @var mixed
439
+ * @Access public
440
+ */
441
+ var $configFile;
442
+
443
+ /**
444
+ * Public key comment field.
445
+ *
446
+ * @var string
447
+ * @access private
448
+ */
449
+ var $comment = 'phpseclib-generated-key';
450
+
451
+ /**
452
+ * The constructor
453
+ *
454
+ * If you want to make use of the openssl extension, you'll need to set the mode manually, yourself. The reason
455
+ * \phpseclib\Crypt\RSA doesn't do it is because OpenSSL doesn't fail gracefully. openssl_pkey_new(), in particular, requires
456
+ * openssl.cnf be present somewhere and, unfortunately, the only real way to find out is too late.
457
+ *
458
+ * @return \phpseclib\Crypt\RSA
459
+ * @access public
460
+ */
461
+ function __construct()
462
+ {
463
+ $this->configFile = dirname(__FILE__) . '/../openssl.cnf';
464
+
465
+ if (!defined('CRYPT_RSA_MODE')) {
466
+ switch (true) {
467
+ // Math/BigInteger's openssl requirements are a little less stringent than Crypt/RSA's. in particular,
468
+ // Math/BigInteger doesn't require an openssl.cfg file whereas Crypt/RSA does. so if Math/BigInteger
469
+ // can't use OpenSSL it can be pretty trivially assumed, then, that Crypt/RSA can't either.
470
+ case defined('MATH_BIGINTEGER_OPENSSL_DISABLE'):
471
+ define('CRYPT_RSA_MODE', self::MODE_INTERNAL);
472
+ break;
473
+ case extension_loaded('openssl') && file_exists($this->configFile):
474
+ // some versions of XAMPP have mismatched versions of OpenSSL which causes it not to work
475
+ $versions = array();
476
+
477
+ // avoid generating errors (even with suppression) when phpinfo() is disabled (common in production systems)
478
+ if (strpos(ini_get('disable_functions'), 'phpinfo') === false) {
479
+ ob_start();
480
+ @phpinfo();
481
+ $content = ob_get_contents();
482
+ ob_end_clean();
483
+
484
+ preg_match_all('#OpenSSL (Header|Library) Version(.*)#im', $content, $matches);
485
+
486
+ if (!empty($matches[1])) {
487
+ for ($i = 0; $i < count($matches[1]); $i++) {
488
+ $fullVersion = trim(str_replace('=>', '', strip_tags($matches[2][$i])));
489
+
490
+ // Remove letter part in OpenSSL version
491
+ if (!preg_match('/(\d+\.\d+\.\d+)/i', $fullVersion, $m)) {
492
+ $versions[$matches[1][$i]] = $fullVersion;
493
+ } else {
494
+ $versions[$matches[1][$i]] = $m[0];
495
+ }
496
+ }
497
+ }
498
+ }
499
+
500
+ // it doesn't appear that OpenSSL versions were reported upon until PHP 5.3+
501
+ switch (true) {
502
+ case !isset($versions['Header']):
503
+ case !isset($versions['Library']):
504
+ case $versions['Header'] == $versions['Library']:
505
+ case version_compare($versions['Header'], '1.0.0') >= 0 && version_compare($versions['Library'], '1.0.0') >= 0:
506
+ define('CRYPT_RSA_MODE', self::MODE_OPENSSL);
507
+ break;
508
+ default:
509
+ define('CRYPT_RSA_MODE', self::MODE_INTERNAL);
510
+ define('MATH_BIGINTEGER_OPENSSL_DISABLE', true);
511
+ }
512
+ break;
513
+ default:
514
+ define('CRYPT_RSA_MODE', self::MODE_INTERNAL);
515
+ }
516
+ }
517
+
518
+ $this->zero = new BigInteger();
519
+ $this->one = new BigInteger(1);
520
+
521
+ $this->hash = new Hash('sha1');
522
+ $this->hLen = $this->hash->getLength();
523
+ $this->hashName = 'sha1';
524
+ $this->mgfHash = new Hash('sha1');
525
+ $this->mgfHLen = $this->mgfHash->getLength();
526
+ }
527
+
528
+ /**
529
+ * Create public / private key pair
530
+ *
531
+ * Returns an array with the following three elements:
532
+ * - 'privatekey': The private key.
533
+ * - 'publickey': The public key.
534
+ * - 'partialkey': A partially computed key (if the execution time exceeded $timeout).
535
+ * Will need to be passed back to \phpseclib\Crypt\RSA::createKey() as the third parameter for further processing.
536
+ *
537
+ * @access public
538
+ * @param int $bits
539
+ * @param int $timeout
540
+ * @param array $p
541
+ */
542
+ function createKey($bits = 1024, $timeout = false, $partial = array())
543
+ {
544
+ if (!defined('CRYPT_RSA_EXPONENT')) {
545
+ // http://en.wikipedia.org/wiki/65537_%28number%29
546
+ define('CRYPT_RSA_EXPONENT', '65537');
547
+ }
548
+ // per <http://cseweb.ucsd.edu/~hovav/dist/survey.pdf#page=5>, this number ought not result in primes smaller
549
+ // 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
550
+ // to 384 bits then you're going to get a 384 bit prime and a 640 bit prime (384 + 1024 % 384). at least if
551
+ // CRYPT_RSA_MODE is set to self::MODE_INTERNAL. if CRYPT_RSA_MODE is set to self::MODE_OPENSSL then
552
+ // CRYPT_RSA_SMALLEST_PRIME is ignored (ie. multi-prime RSA support is more intended as a way to speed up RSA key
553
+ // generation when there's a chance neither gmp nor OpenSSL are installed)
554
+ if (!defined('CRYPT_RSA_SMALLEST_PRIME')) {
555
+ define('CRYPT_RSA_SMALLEST_PRIME', 4096);
556
+ }
557
+
558
+ // OpenSSL uses 65537 as the exponent and requires RSA keys be 384 bits minimum
559
+ if (CRYPT_RSA_MODE == self::MODE_OPENSSL && $bits >= 384 && CRYPT_RSA_EXPONENT == 65537) {
560
+ $config = array();
561
+ if (isset($this->configFile)) {
562
+ $config['config'] = $this->configFile;
563
+ }
564
+ $rsa = openssl_pkey_new(array('private_key_bits' => $bits) + $config);
565
+ openssl_pkey_export($rsa, $privatekey, null, $config);
566
+ $publickey = openssl_pkey_get_details($rsa);
567
+ $publickey = $publickey['key'];
568
+
569
+ $privatekey = call_user_func_array(array($this, '_convertPrivateKey'), array_values($this->_parseKey($privatekey, self::PRIVATE_FORMAT_PKCS1)));
570
+ $publickey = call_user_func_array(array($this, '_convertPublicKey'), array_values($this->_parseKey($publickey, self::PUBLIC_FORMAT_PKCS1)));
571
+
572
+ // clear the buffer of error strings stemming from a minimalistic openssl.cnf
573
+ while (openssl_error_string() !== false) {
574
+ }
575
+
576
+ return array(
577
+ 'privatekey' => $privatekey,
578
+ 'publickey' => $publickey,
579
+ 'partialkey' => false
580
+ );
581
+ }
582
+
583
+ static $e;
584
+ if (!isset($e)) {
585
+ $e = new BigInteger(CRYPT_RSA_EXPONENT);
586
+ }
587
+
588
+ extract($this->_generateMinMax($bits));
589
+ $absoluteMin = $min;
590
+ $temp = $bits >> 1; // divide by two to see how many bits P and Q would be
591
+ if ($temp > CRYPT_RSA_SMALLEST_PRIME) {
592
+ $num_primes = floor($bits / CRYPT_RSA_SMALLEST_PRIME);
593
+ $temp = CRYPT_RSA_SMALLEST_PRIME;
594
+ } else {
595
+ $num_primes = 2;
596
+ }
597
+ extract($this->_generateMinMax($temp + $bits % $temp));
598
+ $finalMax = $max;
599
+ extract($this->_generateMinMax($temp));
600
+
601
+ $generator = new BigInteger();
602
+
603
+ $n = $this->one->copy();
604
+ if (!empty($partial)) {
605
+ extract(unserialize($partial));
606
+ } else {
607
+ $exponents = $coefficients = $primes = array();
608
+ $lcm = array(
609
+ 'top' => $this->one->copy(),
610
+ 'bottom' => false
611
+ );
612
+ }
613
+
614
+ $start = time();
615
+ $i0 = count($primes) + 1;
616
+
617
+ do {
618
+ for ($i = $i0; $i <= $num_primes; $i++) {
619
+ if ($timeout !== false) {
620
+ $timeout-= time() - $start;
621
+ $start = time();
622
+ if ($timeout <= 0) {
623
+ return array(
624
+ 'privatekey' => '',
625
+ 'publickey' => '',
626
+ 'partialkey' => serialize(array(
627
+ 'primes' => $primes,
628
+ 'coefficients' => $coefficients,
629
+ 'lcm' => $lcm,
630
+ 'exponents' => $exponents
631
+ ))
632
+ );
633
+ }
634
+ }
635
+
636
+ if ($i == $num_primes) {
637
+ list($min, $temp) = $absoluteMin->divide($n);
638
+ if (!$temp->equals($this->zero)) {
639
+ $min = $min->add($this->one); // ie. ceil()
640
+ }
641
+ $primes[$i] = $generator->randomPrime($min, $finalMax, $timeout);
642
+ } else {
643
+ $primes[$i] = $generator->randomPrime($min, $max, $timeout);
644
+ }
645
+
646
+ if ($primes[$i] === false) { // if we've reached the timeout
647
+ if (count($primes) > 1) {
648
+ $partialkey = '';
649
+ } else {
650
+ array_pop($primes);
651
+ $partialkey = serialize(array(
652
+ 'primes' => $primes,
653
+ 'coefficients' => $coefficients,
654
+ 'lcm' => $lcm,
655
+ 'exponents' => $exponents
656
+ ));
657
+ }
658
+
659
+ return array(
660
+ 'privatekey' => '',
661
+ 'publickey' => '',
662
+ 'partialkey' => $partialkey
663
+ );
664
+ }
665
+
666
+ // the first coefficient is calculated differently from the rest
667
+ // ie. instead of being $primes[1]->modInverse($primes[2]), it's $primes[2]->modInverse($primes[1])
668
+ if ($i > 2) {
669
+ $coefficients[$i] = $n->modInverse($primes[$i]);
670
+ }
671
+
672
+ $n = $n->multiply($primes[$i]);
673
+
674
+ $temp = $primes[$i]->subtract($this->one);
675
+
676
+ // textbook RSA implementations use Euler's totient function instead of the least common multiple.
677
+ // see http://en.wikipedia.org/wiki/Euler%27s_totient_function
678
+ $lcm['top'] = $lcm['top']->multiply($temp);
679
+ $lcm['bottom'] = $lcm['bottom'] === false ? $temp : $lcm['bottom']->gcd($temp);
680
+
681
+ $exponents[$i] = $e->modInverse($temp);
682
+ }
683
+
684
+ list($temp) = $lcm['top']->divide($lcm['bottom']);
685
+ $gcd = $temp->gcd($e);
686
+ $i0 = 1;
687
+ } while (!$gcd->equals($this->one));
688
+
689
+ $d = $e->modInverse($temp);
690
+
691
+ $coefficients[2] = $primes[2]->modInverse($primes[1]);
692
+
693
+ // from <http://tools.ietf.org/html/rfc3447#appendix-A.1.2>:
694
+ // RSAPrivateKey ::= SEQUENCE {
695
+ // version Version,
696
+ // modulus INTEGER, -- n
697
+ // publicExponent INTEGER, -- e
698
+ // privateExponent INTEGER, -- d
699
+ // prime1 INTEGER, -- p
700
+ // prime2 INTEGER, -- q
701
+ // exponent1 INTEGER, -- d mod (p-1)
702
+ // exponent2 INTEGER, -- d mod (q-1)
703
+ // coefficient INTEGER, -- (inverse of q) mod p
704
+ // otherPrimeInfos OtherPrimeInfos OPTIONAL
705
+ // }
706
+
707
+ return array(
708
+ 'privatekey' => $this->_convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients),
709
+ 'publickey' => $this->_convertPublicKey($n, $e),
710
+ 'partialkey' => false
711
+ );
712
+ }
713
+
714
+ /**
715
+ * Convert a private key to the appropriate format.
716
+ *
717
+ * @access private
718
+ * @see self::setPrivateKeyFormat()
719
+ * @param string $RSAPrivateKey
720
+ * @return string
721
+ */
722
+ function _convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients)
723
+ {
724
+ $signed = $this->privateKeyFormat != self::PRIVATE_FORMAT_XML;
725
+ $num_primes = count($primes);
726
+ $raw = array(
727
+ 'version' => $num_primes == 2 ? chr(0) : chr(1), // two-prime vs. multi
728
+ 'modulus' => $n->toBytes($signed),
729
+ 'publicExponent' => $e->toBytes($signed),
730
+ 'privateExponent' => $d->toBytes($signed),
731
+ 'prime1' => $primes[1]->toBytes($signed),
732
+ 'prime2' => $primes[2]->toBytes($signed),
733
+ 'exponent1' => $exponents[1]->toBytes($signed),
734
+ 'exponent2' => $exponents[2]->toBytes($signed),
735
+ 'coefficient' => $coefficients[2]->toBytes($signed)
736
+ );
737
+
738
+ // if the format in question does not support multi-prime rsa and multi-prime rsa was used,
739
+ // call _convertPublicKey() instead.
740
+ switch ($this->privateKeyFormat) {
741
+ case self::PRIVATE_FORMAT_XML:
742
+ if ($num_primes != 2) {
743
+ return false;
744
+ }
745
+ return "<RSAKeyValue>\r\n" .
746
+ ' <Modulus>' . base64_encode($raw['modulus']) . "</Modulus>\r\n" .
747
+ ' <Exponent>' . base64_encode($raw['publicExponent']) . "</Exponent>\r\n" .
748
+ ' <P>' . base64_encode($raw['prime1']) . "</P>\r\n" .
749
+ ' <Q>' . base64_encode($raw['prime2']) . "</Q>\r\n" .
750
+ ' <DP>' . base64_encode($raw['exponent1']) . "</DP>\r\n" .
751
+ ' <DQ>' . base64_encode($raw['exponent2']) . "</DQ>\r\n" .
752
+ ' <InverseQ>' . base64_encode($raw['coefficient']) . "</InverseQ>\r\n" .
753
+ ' <D>' . base64_encode($raw['privateExponent']) . "</D>\r\n" .
754
+ '</RSAKeyValue>';
755
+ break;
756
+ case self::PRIVATE_FORMAT_PUTTY:
757
+ if ($num_primes != 2) {
758
+ return false;
759
+ }
760
+ $key = "PuTTY-User-Key-File-2: ssh-rsa\r\nEncryption: ";
761
+ $encryption = (!empty($this->password) || is_string($this->password)) ? 'aes256-cbc' : 'none';
762
+ $key.= $encryption;
763
+ $key.= "\r\nComment: " . $this->comment . "\r\n";
764
+ $public = pack(
765
+ 'Na*Na*Na*',
766
+ strlen('ssh-rsa'),
767
+ 'ssh-rsa',
768
+ strlen($raw['publicExponent']),
769
+ $raw['publicExponent'],
770
+ strlen($raw['modulus']),
771
+ $raw['modulus']
772
+ );
773
+ $source = pack(
774
+ 'Na*Na*Na*Na*',
775
+ strlen('ssh-rsa'),
776
+ 'ssh-rsa',
777
+ strlen($encryption),
778
+ $encryption,
779
+ strlen($this->comment),
780
+ $this->comment,
781
+ strlen($public),
782
+ $public
783
+ );
784
+ $public = base64_encode($public);
785
+ $key.= "Public-Lines: " . ((strlen($public) + 63) >> 6) . "\r\n";
786
+ $key.= chunk_split($public, 64);
787
+ $private = pack(
788
+ 'Na*Na*Na*Na*',
789
+ strlen($raw['privateExponent']),
790
+ $raw['privateExponent'],
791
+ strlen($raw['prime1']),
792
+ $raw['prime1'],
793
+ strlen($raw['prime2']),
794
+ $raw['prime2'],
795
+ strlen($raw['coefficient']),
796
+ $raw['coefficient']
797
+ );
798
+ if (empty($this->password) && !is_string($this->password)) {
799
+ $source.= pack('Na*', strlen($private), $private);
800
+ $hashkey = 'putty-private-key-file-mac-key';
801
+ } else {
802
+ $private.= Random::string(16 - (strlen($private) & 15));
803
+ $source.= pack('Na*', strlen($private), $private);
804
+ $sequence = 0;
805
+ $symkey = '';
806
+ while (strlen($symkey) < 32) {
807
+ $temp = pack('Na*', $sequence++, $this->password);
808
+ $symkey.= pack('H*', sha1($temp));
809
+ }
810
+ $symkey = substr($symkey, 0, 32);
811
+ $crypto = new AES();
812
+
813
+ $crypto->setKey($symkey);
814
+ $crypto->disablePadding();
815
+ $private = $crypto->encrypt($private);
816
+ $hashkey = 'putty-private-key-file-mac-key' . $this->password;
817
+ }
818
+
819
+ $private = base64_encode($private);
820
+ $key.= 'Private-Lines: ' . ((strlen($private) + 63) >> 6) . "\r\n";
821
+ $key.= chunk_split($private, 64);
822
+ $hash = new Hash('sha1');
823
+ $hash->setKey(pack('H*', sha1($hashkey)));
824
+ $key.= 'Private-MAC: ' . bin2hex($hash->hash($source)) . "\r\n";
825
+
826
+ return $key;
827
+ case self::PRIVATE_FORMAT_OPENSSH:
828
+ if ($num_primes != 2) {
829
+ return false;
830
+ }
831
+ $publicKey = pack('Na*Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($raw['publicExponent']), $raw['publicExponent'], strlen($raw['modulus']), $raw['modulus']);
832
+ $privateKey = pack(
833
+ 'Na*Na*Na*Na*Na*Na*Na*',
834
+ strlen('ssh-rsa'),
835
+ 'ssh-rsa',
836
+ strlen($raw['modulus']),
837
+ $raw['modulus'],
838
+ strlen($raw['publicExponent']),
839
+ $raw['publicExponent'],
840
+ strlen($raw['privateExponent']),
841
+ $raw['privateExponent'],
842
+ strlen($raw['coefficient']),
843
+ $raw['coefficient'],
844
+ strlen($raw['prime1']),
845
+ $raw['prime1'],
846
+ strlen($raw['prime2']),
847
+ $raw['prime2']
848
+ );
849
+ $checkint = Random::string(4);
850
+ $paddedKey = pack(
851
+ 'a*Na*',
852
+ $checkint . $checkint . $privateKey,
853
+ strlen($this->comment),
854
+ $this->comment
855
+ );
856
+ $paddingLength = (7 * strlen($paddedKey)) % 8;
857
+ for ($i = 1; $i <= $paddingLength; $i++) {
858
+ $paddedKey.= chr($i);
859
+ }
860
+ $key = pack(
861
+ 'Na*Na*Na*NNa*Na*',
862
+ strlen('none'),
863
+ 'none',
864
+ strlen('none'),
865
+ 'none',
866
+ 0,
867
+ '',
868
+ 1,
869
+ strlen($publicKey),
870
+ $publicKey,
871
+ strlen($paddedKey),
872
+ $paddedKey
873
+ );
874
+ $key = "openssh-key-v1\0$key";
875
+
876
+ return "-----BEGIN OPENSSH PRIVATE KEY-----\r\n" .
877
+ chunk_split(base64_encode($key), 70) .
878
+ "-----END OPENSSH PRIVATE KEY-----";
879
+ default: // eg. self::PRIVATE_FORMAT_PKCS1
880
+ $components = array();
881
+ foreach ($raw as $name => $value) {
882
+ $components[$name] = pack('Ca*a*', self::ASN1_INTEGER, $this->_encodeLength(strlen($value)), $value);
883
+ }
884
+
885
+ $RSAPrivateKey = implode('', $components);
886
+
887
+ if ($num_primes > 2) {
888
+ $OtherPrimeInfos = '';
889
+ for ($i = 3; $i <= $num_primes; $i++) {
890
+ // OtherPrimeInfos ::= SEQUENCE SIZE(1..MAX) OF OtherPrimeInfo
891
+ //
892
+ // OtherPrimeInfo ::= SEQUENCE {
893
+ // prime INTEGER, -- ri
894
+ // exponent INTEGER, -- di
895
+ // coefficient INTEGER -- ti
896
+ // }
897
+ $OtherPrimeInfo = pack('Ca*a*', self::ASN1_INTEGER, $this->_encodeLength(strlen($primes[$i]->toBytes(true))), $primes[$i]->toBytes(true));
898
+ $OtherPrimeInfo.= pack('Ca*a*', self::ASN1_INTEGER, $this->_encodeLength(strlen($exponents[$i]->toBytes(true))), $exponents[$i]->toBytes(true));
899
+ $OtherPrimeInfo.= pack('Ca*a*', self::ASN1_INTEGER, $this->_encodeLength(strlen($coefficients[$i]->toBytes(true))), $coefficients[$i]->toBytes(true));
900
+ $OtherPrimeInfos.= pack('Ca*a*', self::ASN1_SEQUENCE, $this->_encodeLength(strlen($OtherPrimeInfo)), $OtherPrimeInfo);
901
+ }
902
+ $RSAPrivateKey.= pack('Ca*a*', self::ASN1_SEQUENCE, $this->_encodeLength(strlen($OtherPrimeInfos)), $OtherPrimeInfos);
903
+ }
904
+
905
+ $RSAPrivateKey = pack('Ca*a*', self::ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);
906
+
907
+ if ($this->privateKeyFormat == self::PRIVATE_FORMAT_PKCS8) {
908
+ $rsaOID = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA
909
+ $RSAPrivateKey = pack(
910
+ 'Ca*a*Ca*a*',
911
+ self::ASN1_INTEGER,
912
+ "\01\00",
913
+ $rsaOID,
914
+ 4,
915
+ $this->_encodeLength(strlen($RSAPrivateKey)),
916
+ $RSAPrivateKey
917
+ );
918
+ $RSAPrivateKey = pack('Ca*a*', self::ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);
919
+ if (!empty($this->password) || is_string($this->password)) {
920
+ $salt = Random::string(8);
921
+ $iterationCount = 2048;
922
+
923
+ $crypto = new DES();
924
+ $crypto->setPassword($this->password, 'pbkdf1', 'md5', $salt, $iterationCount);
925
+ $RSAPrivateKey = $crypto->encrypt($RSAPrivateKey);
926
+
927
+ $parameters = pack(
928
+ 'Ca*a*Ca*N',
929
+ self::ASN1_OCTETSTRING,
930
+ $this->_encodeLength(strlen($salt)),
931
+ $salt,
932
+ self::ASN1_INTEGER,
933
+ $this->_encodeLength(4),
934
+ $iterationCount
935
+ );
936
+ $pbeWithMD5AndDES_CBC = "\x2a\x86\x48\x86\xf7\x0d\x01\x05\x03";
937
+
938
+ $encryptionAlgorithm = pack(
939
+ 'Ca*a*Ca*a*',
940
+ self::ASN1_OBJECT,
941
+ $this->_encodeLength(strlen($pbeWithMD5AndDES_CBC)),
942
+ $pbeWithMD5AndDES_CBC,
943
+ self::ASN1_SEQUENCE,
944
+ $this->_encodeLength(strlen($parameters)),
945
+ $parameters
946
+ );
947
+
948
+ $RSAPrivateKey = pack(
949
+ 'Ca*a*Ca*a*',
950
+ self::ASN1_SEQUENCE,
951
+ $this->_encodeLength(strlen($encryptionAlgorithm)),
952
+ $encryptionAlgorithm,
953
+ self::ASN1_OCTETSTRING,
954
+ $this->_encodeLength(strlen($RSAPrivateKey)),
955
+ $RSAPrivateKey
956
+ );
957
+
958
+ $RSAPrivateKey = pack('Ca*a*', self::ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);
959
+
960
+ $RSAPrivateKey = "-----BEGIN ENCRYPTED PRIVATE KEY-----\r\n" .
961
+ chunk_split(base64_encode($RSAPrivateKey), 64) .
962
+ '-----END ENCRYPTED PRIVATE KEY-----';
963
+ } else {
964
+ $RSAPrivateKey = "-----BEGIN PRIVATE KEY-----\r\n" .
965
+ chunk_split(base64_encode($RSAPrivateKey), 64) .
966
+ '-----END PRIVATE KEY-----';
967
+ }
968
+ return $RSAPrivateKey;
969
+ }
970
+
971
+ if (!empty($this->password) || is_string($this->password)) {
972
+ $iv = Random::string(8);
973
+ $symkey = pack('H*', md5($this->password . $iv)); // symkey is short for symmetric key
974
+ $symkey.= substr(pack('H*', md5($symkey . $this->password . $iv)), 0, 8);
975
+ $des = new TripleDES();
976
+ $des->setKey($symkey);
977
+ $des->setIV($iv);
978
+ $iv = strtoupper(bin2hex($iv));
979
+ $RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" .
980
+ "Proc-Type: 4,ENCRYPTED\r\n" .
981
+ "DEK-Info: DES-EDE3-CBC,$iv\r\n" .
982
+ "\r\n" .
983
+ chunk_split(base64_encode($des->encrypt($RSAPrivateKey)), 64) .
984
+ '-----END RSA PRIVATE KEY-----';
985
+ } else {
986
+ $RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" .
987
+ chunk_split(base64_encode($RSAPrivateKey), 64) .
988
+ '-----END RSA PRIVATE KEY-----';
989
+ }
990
+
991
+ return $RSAPrivateKey;
992
+ }
993
+ }
994
+
995
+ /**
996
+ * Convert a public key to the appropriate format
997
+ *
998
+ * @access private
999
+ * @see self::setPublicKeyFormat()
1000
+ * @param string $RSAPrivateKey
1001
+ * @return string
1002
+ */
1003
+ function _convertPublicKey($n, $e)
1004
+ {
1005
+ $signed = $this->publicKeyFormat != self::PUBLIC_FORMAT_XML;
1006
+
1007
+ $modulus = $n->toBytes($signed);
1008
+ $publicExponent = $e->toBytes($signed);
1009
+
1010
+ switch ($this->publicKeyFormat) {
1011
+ case self::PUBLIC_FORMAT_RAW:
1012
+ return array('e' => $e->copy(), 'n' => $n->copy());
1013
+ case self::PUBLIC_FORMAT_XML:
1014
+ return "<RSAKeyValue>\r\n" .
1015
+ ' <Modulus>' . base64_encode($modulus) . "</Modulus>\r\n" .
1016
+ ' <Exponent>' . base64_encode($publicExponent) . "</Exponent>\r\n" .
1017
+ '</RSAKeyValue>';
1018
+ break;
1019
+ case self::PUBLIC_FORMAT_OPENSSH:
1020
+ // from <http://tools.ietf.org/html/rfc4253#page-15>:
1021
+ // string "ssh-rsa"
1022
+ // mpint e
1023
+ // mpint n
1024
+ $RSAPublicKey = pack('Na*Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($publicExponent), $publicExponent, strlen($modulus), $modulus);
1025
+ $RSAPublicKey = 'ssh-rsa ' . base64_encode($RSAPublicKey) . ' ' . $this->comment;
1026
+
1027
+ return $RSAPublicKey;
1028
+ default: // eg. self::PUBLIC_FORMAT_PKCS1_RAW or self::PUBLIC_FORMAT_PKCS1
1029
+ // from <http://tools.ietf.org/html/rfc3447#appendix-A.1.1>:
1030
+ // RSAPublicKey ::= SEQUENCE {
1031
+ // modulus INTEGER, -- n
1032
+ // publicExponent INTEGER -- e
1033
+ // }
1034
+ $components = array(
1035
+ 'modulus' => pack('Ca*a*', self::ASN1_INTEGER, $this->_encodeLength(strlen($modulus)), $modulus),
1036
+ 'publicExponent' => pack('Ca*a*', self::ASN1_INTEGER, $this->_encodeLength(strlen($publicExponent)), $publicExponent)
1037
+ );
1038
+
1039
+ $RSAPublicKey = pack(
1040
+ 'Ca*a*a*',
1041
+ self::ASN1_SEQUENCE,
1042
+ $this->_encodeLength(strlen($components['modulus']) + strlen($components['publicExponent'])),
1043
+ $components['modulus'],
1044
+ $components['publicExponent']
1045
+ );
1046
+
1047
+ if ($this->publicKeyFormat == self::PUBLIC_FORMAT_PKCS1_RAW) {
1048
+ $RSAPublicKey = "-----BEGIN RSA PUBLIC KEY-----\r\n" .
1049
+ chunk_split(base64_encode($RSAPublicKey), 64) .
1050
+ '-----END RSA PUBLIC KEY-----';
1051
+ } else {
1052
+ // sequence(oid(1.2.840.113549.1.1.1), null)) = rsaEncryption.
1053
+ $rsaOID = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA
1054
+ $RSAPublicKey = chr(0) . $RSAPublicKey;
1055
+ $RSAPublicKey = chr(3) . $this->_encodeLength(strlen($RSAPublicKey)) . $RSAPublicKey;
1056
+
1057
+ $RSAPublicKey = pack(
1058
+ 'Ca*a*',
1059
+ self::ASN1_SEQUENCE,
1060
+ $this->_encodeLength(strlen($rsaOID . $RSAPublicKey)),
1061
+ $rsaOID . $RSAPublicKey
1062
+ );
1063
+
1064
+ $RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" .
1065
+ chunk_split(base64_encode($RSAPublicKey), 64) .
1066
+ '-----END PUBLIC KEY-----';
1067
+ }
1068
+
1069
+ return $RSAPublicKey;
1070
+ }
1071
+ }
1072
+
1073
+ /**
1074
+ * Break a public or private key down into its constituant components
1075
+ *
1076
+ * @access private
1077
+ * @see self::_convertPublicKey()
1078
+ * @see self::_convertPrivateKey()
1079
+ * @param string|array $key
1080
+ * @param int $type
1081
+ * @return array|bool
1082
+ */
1083
+ function _parseKey($key, $type)
1084
+ {
1085
+ if ($type != self::PUBLIC_FORMAT_RAW && !is_string($key)) {
1086
+ return false;
1087
+ }
1088
+
1089
+ switch ($type) {
1090
+ case self::PUBLIC_FORMAT_RAW:
1091
+ if (!is_array($key)) {
1092
+ return false;
1093
+ }
1094
+ $components = array();
1095
+ switch (true) {
1096
+ case isset($key['e']):
1097
+ $components['publicExponent'] = $key['e']->copy();
1098
+ break;
1099
+ case isset($key['exponent']):
1100
+ $components['publicExponent'] = $key['exponent']->copy();
1101
+ break;
1102
+ case isset($key['publicExponent']):
1103
+ $components['publicExponent'] = $key['publicExponent']->copy();
1104
+ break;
1105
+ case isset($key[0]):
1106
+ $components['publicExponent'] = $key[0]->copy();
1107
+ }
1108
+ switch (true) {
1109
+ case isset($key['n']):
1110
+ $components['modulus'] = $key['n']->copy();
1111
+ break;
1112
+ case isset($key['modulo']):
1113
+ $components['modulus'] = $key['modulo']->copy();
1114
+ break;
1115
+ case isset($key['modulus']):
1116
+ $components['modulus'] = $key['modulus']->copy();
1117
+ break;
1118
+ case isset($key[1]):
1119
+ $components['modulus'] = $key[1]->copy();
1120
+ }
1121
+ return isset($components['modulus']) && isset($components['publicExponent']) ? $components : false;
1122
+ case self::PRIVATE_FORMAT_PKCS1:
1123
+ case self::PRIVATE_FORMAT_PKCS8:
1124
+ case self::PUBLIC_FORMAT_PKCS1:
1125
+ /* Although PKCS#1 proposes a format that public and private keys can use, encrypting them is
1126
+ "outside the scope" of PKCS#1. PKCS#1 then refers you to PKCS#12 and PKCS#15 if you're wanting to
1127
+ protect private keys, however, that's not what OpenSSL* does. OpenSSL protects private keys by adding
1128
+ two new "fields" to the key - DEK-Info and Proc-Type. These fields are discussed here:
1129
+
1130
+ http://tools.ietf.org/html/rfc1421#section-4.6.1.1
1131
+ http://tools.ietf.org/html/rfc1421#section-4.6.1.3
1132
+
1133
+ DES-EDE3-CBC as an algorithm, however, is not discussed anywhere, near as I can tell.
1134
+ DES-CBC and DES-EDE are discussed in RFC1423, however, DES-EDE3-CBC isn't, nor is its key derivation
1135
+ function. As is, the definitive authority on this encoding scheme isn't the IETF but rather OpenSSL's
1136
+ own implementation. ie. the implementation *is* the standard and any bugs that may exist in that
1137
+ implementation are part of the standard, as well.
1138
+
1139
+ * OpenSSL is the de facto standard. It's utilized by OpenSSH and other projects */
1140
+ if (preg_match('#DEK-Info: (.+),(.+)#', $key, $matches)) {
1141
+ $iv = pack('H*', trim($matches[2]));
1142
+ $symkey = pack('H*', md5($this->password . substr($iv, 0, 8))); // symkey is short for symmetric key
1143
+ $symkey.= pack('H*', md5($symkey . $this->password . substr($iv, 0, 8)));
1144
+ // remove the Proc-Type / DEK-Info sections as they're no longer needed
1145
+ $key = preg_replace('#^(?:Proc-Type|DEK-Info): .*#m', '', $key);
1146
+ $ciphertext = $this->_extractBER($key);
1147
+ if ($ciphertext === false) {
1148
+ $ciphertext = $key;
1149
+ }
1150
+ switch ($matches[1]) {
1151
+ case 'AES-256-CBC':
1152
+ $crypto = new AES();
1153
+ break;
1154
+ case 'AES-128-CBC':
1155
+ $symkey = substr($symkey, 0, 16);
1156
+ $crypto = new AES();
1157
+ break;
1158
+ case 'DES-EDE3-CFB':
1159
+ $crypto = new TripleDES(Base::MODE_CFB);
1160
+ break;
1161
+ case 'DES-EDE3-CBC':
1162
+ $symkey = substr($symkey, 0, 24);
1163
+ $crypto = new TripleDES();
1164
+ break;
1165
+ case 'DES-CBC':
1166
+ $crypto = new DES();
1167
+ break;
1168
+ default:
1169
+ return false;
1170
+ }
1171
+ $crypto->setKey($symkey);
1172
+ $crypto->setIV($iv);
1173
+ $decoded = $crypto->decrypt($ciphertext);
1174
+ } else {
1175
+ $decoded = $this->_extractBER($key);
1176
+ }
1177
+
1178
+ if ($decoded !== false) {
1179
+ $key = $decoded;
1180
+ }
1181
+
1182
+ $components = array();
1183
+
1184
+ if (ord($this->_string_shift($key)) != self::ASN1_SEQUENCE) {
1185
+ return false;
1186
+ }
1187
+ if ($this->_decodeLength($key) != strlen($key)) {
1188
+ return false;
1189
+ }
1190
+
1191
+ $tag = ord($this->_string_shift($key));
1192
+ /* intended for keys for which OpenSSL's asn1parse returns the following:
1193
+
1194
+ 0:d=0 hl=4 l= 631 cons: SEQUENCE
1195
+ 4:d=1 hl=2 l= 1 prim: INTEGER :00
1196
+ 7:d=1 hl=2 l= 13 cons: SEQUENCE
1197
+ 9:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption
1198
+ 20:d=2 hl=2 l= 0 prim: NULL
1199
+ 22:d=1 hl=4 l= 609 prim: OCTET STRING
1200
+
1201
+ ie. PKCS8 keys*/
1202
+
1203
+ if ($tag == self::ASN1_INTEGER && substr($key, 0, 3) == "\x01\x00\x30") {
1204
+ $this->_string_shift($key, 3);
1205
+ $tag = self::ASN1_SEQUENCE;
1206
+ }
1207
+
1208
+ if ($tag == self::ASN1_SEQUENCE) {
1209
+ $temp = $this->_string_shift($key, $this->_decodeLength($key));
1210
+ if (ord($this->_string_shift($temp)) != self::ASN1_OBJECT) {
1211
+ return false;
1212
+ }
1213
+ $length = $this->_decodeLength($temp);
1214
+ switch ($this->_string_shift($temp, $length)) {
1215
+ case "\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01": // rsaEncryption
1216
+ break;
1217
+ case "\x2a\x86\x48\x86\xf7\x0d\x01\x05\x03": // pbeWithMD5AndDES-CBC
1218
+ /*
1219
+ PBEParameter ::= SEQUENCE {
1220
+ salt OCTET STRING (SIZE(8)),
1221
+ iterationCount INTEGER }
1222
+ */
1223
+ if (ord($this->_string_shift($temp)) != self::ASN1_SEQUENCE) {
1224
+ return false;
1225
+ }
1226
+ if ($this->_decodeLength($temp) != strlen($temp)) {
1227
+ return false;
1228
+ }
1229
+ $this->_string_shift($temp); // assume it's an octet string
1230
+ $salt = $this->_string_shift($temp, $this->_decodeLength($temp));
1231
+ if (ord($this->_string_shift($temp)) != self::ASN1_INTEGER) {
1232
+ return false;
1233
+ }
1234
+ $this->_decodeLength($temp);
1235
+ list(, $iterationCount) = unpack('N', str_pad($temp, 4, chr(0), STR_PAD_LEFT));
1236
+ $this->_string_shift($key); // assume it's an octet string
1237
+ $length = $this->_decodeLength($key);
1238
+ if (strlen($key) != $length) {
1239
+ return false;
1240
+ }
1241
+
1242
+ $crypto = new DES();
1243
+ $crypto->setPassword($this->password, 'pbkdf1', 'md5', $salt, $iterationCount);
1244
+ $key = $crypto->decrypt($key);
1245
+ if ($key === false) {
1246
+ return false;
1247
+ }
1248
+ return $this->_parseKey($key, self::PRIVATE_FORMAT_PKCS1);
1249
+ default:
1250
+ return false;
1251
+ }
1252
+ /* intended for keys for which OpenSSL's asn1parse returns the following:
1253
+
1254
+ 0:d=0 hl=4 l= 290 cons: SEQUENCE
1255
+ 4:d=1 hl=2 l= 13 cons: SEQUENCE
1256
+ 6:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption
1257
+ 17:d=2 hl=2 l= 0 prim: NULL
1258
+ 19:d=1 hl=4 l= 271 prim: BIT STRING */
1259
+ $tag = ord($this->_string_shift($key)); // skip over the BIT STRING / OCTET STRING tag
1260
+ $this->_decodeLength($key); // skip over the BIT STRING / OCTET STRING length
1261
+ // "The initial octet shall encode, as an unsigned binary integer wtih bit 1 as the least significant bit, the number of
1262
+ // unused bits in the final subsequent octet. The number shall be in the range zero to seven."
1263
+ // -- http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf (section 8.6.2.2)
1264
+ if ($tag == self::ASN1_BITSTRING) {
1265
+ $this->_string_shift($key);
1266
+ }
1267
+ if (ord($this->_string_shift($key)) != self::ASN1_SEQUENCE) {
1268
+ return false;
1269
+ }
1270
+ if ($this->_decodeLength($key) != strlen($key)) {
1271
+ return false;
1272
+ }
1273
+ $tag = ord($this->_string_shift($key));
1274
+ }
1275
+ if ($tag != self::ASN1_INTEGER) {
1276
+ return false;
1277
+ }
1278
+
1279
+ $length = $this->_decodeLength($key);
1280
+ $temp = $this->_string_shift($key, $length);
1281
+ if (strlen($temp) != 1 || ord($temp) > 2) {
1282
+ $components['modulus'] = new BigInteger($temp, 256);
1283
+ $this->_string_shift($key); // skip over self::ASN1_INTEGER
1284
+ $length = $this->_decodeLength($key);
1285
+ $components[$type == self::PUBLIC_FORMAT_PKCS1 ? 'publicExponent' : 'privateExponent'] = new BigInteger($this->_string_shift($key, $length), 256);
1286
+
1287
+ return $components;
1288
+ }
1289
+ if (ord($this->_string_shift($key)) != self::ASN1_INTEGER) {
1290
+ return false;
1291
+ }
1292
+ $length = $this->_decodeLength($key);
1293
+ $components['modulus'] = new BigInteger($this->_string_shift($key, $length), 256);
1294
+ $this->_string_shift($key);
1295
+ $length = $this->_decodeLength($key);
1296
+ $components['publicExponent'] = new BigInteger($this->_string_shift($key, $length), 256);
1297
+ $this->_string_shift($key);
1298
+ $length = $this->_decodeLength($key);
1299
+ $components['privateExponent'] = new BigInteger($this->_string_shift($key, $length), 256);
1300
+ $this->_string_shift($key);
1301
+ $length = $this->_decodeLength($key);
1302
+ $components['primes'] = array(1 => new BigInteger($this->_string_shift($key, $length), 256));
1303
+ $this->_string_shift($key);
1304
+ $length = $this->_decodeLength($key);
1305
+ $components['primes'][] = new BigInteger($this->_string_shift($key, $length), 256);
1306
+ $this->_string_shift($key);
1307
+ $length = $this->_decodeLength($key);
1308
+ $components['exponents'] = array(1 => new BigInteger($this->_string_shift($key, $length), 256));
1309
+ $this->_string_shift($key);
1310
+ $length = $this->_decodeLength($key);
1311
+ $components['exponents'][] = new BigInteger($this->_string_shift($key, $length), 256);
1312
+ $this->_string_shift($key);
1313
+ $length = $this->_decodeLength($key);
1314
+ $components['coefficients'] = array(2 => new BigInteger($this->_string_shift($key, $length), 256));
1315
+
1316
+ if (!empty($key)) {
1317
+ if (ord($this->_string_shift($key)) != self::ASN1_SEQUENCE) {
1318
+ return false;
1319
+ }
1320
+ $this->_decodeLength($key);
1321
+ while (!empty($key)) {
1322
+ if (ord($this->_string_shift($key)) != self::ASN1_SEQUENCE) {
1323
+ return false;
1324
+ }
1325
+ $this->_decodeLength($key);
1326
+ $key = substr($key, 1);
1327
+ $length = $this->_decodeLength($key);
1328
+ $components['primes'][] = new BigInteger($this->_string_shift($key, $length), 256);
1329
+ $this->_string_shift($key);
1330
+ $length = $this->_decodeLength($key);
1331
+ $components['exponents'][] = new BigInteger($this->_string_shift($key, $length), 256);
1332
+ $this->_string_shift($key);
1333
+ $length = $this->_decodeLength($key);
1334
+ $components['coefficients'][] = new BigInteger($this->_string_shift($key, $length), 256);
1335
+ }
1336
+ }
1337
+
1338
+ return $components;
1339
+ case self::PUBLIC_FORMAT_OPENSSH:
1340
+ $parts = explode(' ', $key, 3);
1341
+
1342
+ $key = isset($parts[1]) ? base64_decode($parts[1]) : false;
1343
+ if ($key === false) {
1344
+ return false;
1345
+ }
1346
+
1347
+ $comment = isset($parts[2]) ? $parts[2] : false;
1348
+
1349
+ $cleanup = substr($key, 0, 11) == "\0\0\0\7ssh-rsa";
1350
+
1351
+ if (strlen($key) <= 4) {
1352
+ return false;
1353
+ }
1354
+ extract(unpack('Nlength', $this->_string_shift($key, 4)));
1355
+ $publicExponent = new BigInteger($this->_string_shift($key, $length), -256);
1356
+ if (strlen($key) <= 4) {
1357
+ return false;
1358
+ }
1359
+ extract(unpack('Nlength', $this->_string_shift($key, 4)));
1360
+ $modulus = new BigInteger($this->_string_shift($key, $length), -256);
1361
+
1362
+ if ($cleanup && strlen($key)) {
1363
+ if (strlen($key) <= 4) {
1364
+ return false;
1365
+ }
1366
+ extract(unpack('Nlength', $this->_string_shift($key, 4)));
1367
+ $realModulus = new BigInteger($this->_string_shift($key, $length), -256);
1368
+ return strlen($key) ? false : array(
1369
+ 'modulus' => $realModulus,
1370
+ 'publicExponent' => $modulus,
1371
+ 'comment' => $comment
1372
+ );
1373
+ } else {
1374
+ return strlen($key) ? false : array(
1375
+ 'modulus' => $modulus,
1376
+ 'publicExponent' => $publicExponent,
1377
+ 'comment' => $comment
1378
+ );
1379
+ }
1380
+ // http://www.w3.org/TR/xmldsig-core/#sec-RSAKeyValue
1381
+ // http://en.wikipedia.org/wiki/XML_Signature
1382
+ case self::PRIVATE_FORMAT_XML:
1383
+ case self::PUBLIC_FORMAT_XML:
1384
+ $this->components = array();
1385
+
1386
+ $xml = xml_parser_create('UTF-8');
1387
+ xml_set_object($xml, $this);
1388
+ xml_set_element_handler($xml, '_start_element_handler', '_stop_element_handler');
1389
+ xml_set_character_data_handler($xml, '_data_handler');
1390
+ // add <xml></xml> to account for "dangling" tags like <BitStrength>...</BitStrength> that are sometimes added
1391
+ if (!xml_parse($xml, '<xml>' . $key . '</xml>')) {
1392
+ xml_parser_free($xml);
1393
+ unset($xml);
1394
+ return false;
1395
+ }
1396
+
1397
+ xml_parser_free($xml);
1398
+ unset($xml);
1399
+
1400
+ return isset($this->components['modulus']) && isset($this->components['publicExponent']) ? $this->components : false;
1401
+ // from PuTTY's SSHPUBK.C
1402
+ case self::PRIVATE_FORMAT_PUTTY:
1403
+ $components = array();
1404
+ $key = preg_split('#\r\n|\r|\n#', $key);
1405
+ $type = trim(preg_replace('#PuTTY-User-Key-File-2: (.+)#', '$1', $key[0]));
1406
+ if ($type != 'ssh-rsa') {
1407
+ return false;
1408
+ }
1409
+ $encryption = trim(preg_replace('#Encryption: (.+)#', '$1', $key[1]));
1410
+ $comment = trim(preg_replace('#Comment: (.+)#', '$1', $key[2]));
1411
+
1412
+ $publicLength = trim(preg_replace('#Public-Lines: (\d+)#', '$1', $key[3]));
1413
+ $public = base64_decode(implode('', array_map('trim', array_slice($key, 4, $publicLength))));
1414
+ $public = substr($public, 11);
1415
+ extract(unpack('Nlength', $this->_string_shift($public, 4)));
1416
+ $components['publicExponent'] = new BigInteger($this->_string_shift($public, $length), -256);
1417
+ extract(unpack('Nlength', $this->_string_shift($public, 4)));
1418
+ $components['modulus'] = new BigInteger($this->_string_shift($public, $length), -256);
1419
+
1420
+ $privateLength = trim(preg_replace('#Private-Lines: (\d+)#', '$1', $key[$publicLength + 4]));
1421
+ $private = base64_decode(implode('', array_map('trim', array_slice($key, $publicLength + 5, $privateLength))));
1422
+
1423
+ switch ($encryption) {
1424
+ case 'aes256-cbc':
1425
+ $symkey = '';
1426
+ $sequence = 0;
1427
+ while (strlen($symkey) < 32) {
1428
+ $temp = pack('Na*', $sequence++, $this->password);
1429
+ $symkey.= pack('H*', sha1($temp));
1430
+ }
1431
+ $symkey = substr($symkey, 0, 32);
1432
+ $crypto = new AES();
1433
+ }
1434
+
1435
+ if ($encryption != 'none') {
1436
+ $crypto->setKey($symkey);
1437
+ $crypto->disablePadding();
1438
+ $private = $crypto->decrypt($private);
1439
+ if ($private === false) {
1440
+ return false;
1441
+ }
1442
+ }
1443
+
1444
+ extract(unpack('Nlength', $this->_string_shift($private, 4)));
1445
+ if (strlen($private) < $length) {
1446
+ return false;
1447
+ }
1448
+ $components['privateExponent'] = new BigInteger($this->_string_shift($private, $length), -256);
1449
+ extract(unpack('Nlength', $this->_string_shift($private, 4)));
1450
+ if (strlen($private) < $length) {
1451
+ return false;
1452
+ }
1453
+ $components['primes'] = array(1 => new BigInteger($this->_string_shift($private, $length), -256));
1454
+ extract(unpack('Nlength', $this->_string_shift($private, 4)));
1455
+ if (strlen($private) < $length) {
1456
+ return false;
1457
+ }
1458
+ $components['primes'][] = new BigInteger($this->_string_shift($private, $length), -256);
1459
+
1460
+ $temp = $components['primes'][1]->subtract($this->one);
1461
+ $components['exponents'] = array(1 => $components['publicExponent']->modInverse($temp));
1462
+ $temp = $components['primes'][2]->subtract($this->one);
1463
+ $components['exponents'][] = $components['publicExponent']->modInverse($temp);
1464
+
1465
+ extract(unpack('Nlength', $this->_string_shift($private, 4)));
1466
+ if (strlen($private) < $length) {
1467
+ return false;
1468
+ }
1469
+ $components['coefficients'] = array(2 => new BigInteger($this->_string_shift($private, $length), -256));
1470
+
1471
+ return $components;
1472
+ case self::PRIVATE_FORMAT_OPENSSH:
1473
+ $components = array();
1474
+ $decoded = $this->_extractBER($key);
1475
+ $magic = $this->_string_shift($decoded, 15);
1476
+ if ($magic !== "openssh-key-v1\0") {
1477
+ return false;
1478
+ }
1479
+ $options = $this->_string_shift($decoded, 24);
1480
+ // \0\0\0\4none = ciphername
1481
+ // \0\0\0\4none = kdfname
1482
+ // \0\0\0\0 = kdfoptions
1483
+ // \0\0\0\1 = numkeys
1484
+ if ($options != "\0\0\0\4none\0\0\0\4none\0\0\0\0\0\0\0\1") {
1485
+ return false;
1486
+ }
1487
+ extract(unpack('Nlength', $this->_string_shift($decoded, 4)));
1488
+ if (strlen($decoded) < $length) {
1489
+ return false;
1490
+ }
1491
+ $publicKey = $this->_string_shift($decoded, $length);
1492
+ extract(unpack('Nlength', $this->_string_shift($decoded, 4)));
1493
+ if (strlen($decoded) < $length) {
1494
+ return false;
1495
+ }
1496
+ $paddedKey = $this->_string_shift($decoded, $length);
1497
+
1498
+ if ($this->_string_shift($publicKey, 11) !== "\0\0\0\7ssh-rsa") {
1499
+ return false;
1500
+ }
1501
+
1502
+ $checkint1 = $this->_string_shift($paddedKey, 4);
1503
+ $checkint2 = $this->_string_shift($paddedKey, 4);
1504
+ if (strlen($checkint1) != 4 || $checkint1 !== $checkint2) {
1505
+ return false;
1506
+ }
1507
+
1508
+ if ($this->_string_shift($paddedKey, 11) !== "\0\0\0\7ssh-rsa") {
1509
+ return false;
1510
+ }
1511
+
1512
+ $values = array(
1513
+ &$components['modulus'],
1514
+ &$components['publicExponent'],
1515
+ &$components['privateExponent'],
1516
+ &$components['coefficients'][2],
1517
+ &$components['primes'][1],
1518
+ &$components['primes'][2]
1519
+ );
1520
+
1521
+ foreach ($values as &$value) {
1522
+ extract(unpack('Nlength', $this->_string_shift($paddedKey, 4)));
1523
+ if (strlen($paddedKey) < $length) {
1524
+ return false;
1525
+ }
1526
+ $value = new BigInteger($this->_string_shift($paddedKey, $length), -256);
1527
+ }
1528
+
1529
+ extract(unpack('Nlength', $this->_string_shift($paddedKey, 4)));
1530
+ if (strlen($paddedKey) < $length) {
1531
+ return false;
1532
+ }
1533
+ $components['comment'] = $this->_string_shift($decoded, $length);
1534
+
1535
+ $temp = $components['primes'][1]->subtract($this->one);
1536
+ $components['exponents'] = array(1 => $components['publicExponent']->modInverse($temp));
1537
+ $temp = $components['primes'][2]->subtract($this->one);
1538
+ $components['exponents'][] = $components['publicExponent']->modInverse($temp);
1539
+
1540
+ return $components;
1541
+ }
1542
+ }
1543
+
1544
+ /**
1545
+ * Returns the key size
1546
+ *
1547
+ * More specifically, this returns the size of the modulo in bits.
1548
+ *
1549
+ * @access public
1550
+ * @return int
1551
+ */
1552
+ function getSize()
1553
+ {
1554
+ return !isset($this->modulus) ? 0 : strlen($this->modulus->toBits());
1555
+ }
1556
+
1557
+ /**
1558
+ * Start Element Handler
1559
+ *
1560
+ * Called by xml_set_element_handler()
1561
+ *
1562
+ * @access private
1563
+ * @param resource $parser
1564
+ * @param string $name
1565
+ * @param array $attribs
1566
+ */
1567
+ function _start_element_handler($parser, $name, $attribs)
1568
+ {
1569
+ //$name = strtoupper($name);
1570
+ switch ($name) {
1571
+ case 'MODULUS':
1572
+ $this->current = &$this->components['modulus'];
1573
+ break;
1574
+ case 'EXPONENT':
1575
+ $this->current = &$this->components['publicExponent'];
1576
+ break;
1577
+ case 'P':
1578
+ $this->current = &$this->components['primes'][1];
1579
+ break;
1580
+ case 'Q':
1581
+ $this->current = &$this->components['primes'][2];
1582
+ break;
1583
+ case 'DP':
1584
+ $this->current = &$this->components['exponents'][1];
1585
+ break;
1586
+ case 'DQ':
1587
+ $this->current = &$this->components['exponents'][2];
1588
+ break;
1589
+ case 'INVERSEQ':
1590
+ $this->current = &$this->components['coefficients'][2];
1591
+ break;
1592
+ case 'D':
1593
+ $this->current = &$this->components['privateExponent'];
1594
+ }
1595
+ $this->current = '';
1596
+ }
1597
+
1598
+ /**
1599
+ * Stop Element Handler
1600
+ *
1601
+ * Called by xml_set_element_handler()
1602
+ *
1603
+ * @access private
1604
+ * @param resource $parser
1605
+ * @param string $name
1606
+ */
1607
+ function _stop_element_handler($parser, $name)
1608
+ {
1609
+ if (isset($this->current)) {
1610
+ $this->current = new BigInteger(base64_decode($this->current), 256);
1611
+ unset($this->current);
1612
+ }
1613
+ }
1614
+
1615
+ /**
1616
+ * Data Handler
1617
+ *
1618
+ * Called by xml_set_character_data_handler()
1619
+ *
1620
+ * @access private
1621
+ * @param resource $parser
1622
+ * @param string $data
1623
+ */
1624
+ function _data_handler($parser, $data)
1625
+ {
1626
+ if (!isset($this->current) || is_object($this->current)) {
1627
+ return;
1628
+ }
1629
+ $this->current.= trim($data);
1630
+ }
1631
+
1632
+ /**
1633
+ * Loads a public or private key
1634
+ *
1635
+ * Returns true on success and false on failure (ie. an incorrect password was provided or the key was malformed)
1636
+ *
1637
+ * @access public
1638
+ * @param string|RSA|array $key
1639
+ * @param bool|int $type optional
1640
+ * @return bool
1641
+ */
1642
+ function loadKey($key, $type = false)
1643
+ {
1644
+ if ($key instanceof RSA) {
1645
+ $this->privateKeyFormat = $key->privateKeyFormat;
1646
+ $this->publicKeyFormat = $key->publicKeyFormat;
1647
+ $this->k = $key->k;
1648
+ $this->hLen = $key->hLen;
1649
+ $this->sLen = $key->sLen;
1650
+ $this->mgfHLen = $key->mgfHLen;
1651
+ $this->encryptionMode = $key->encryptionMode;
1652
+ $this->signatureMode = $key->signatureMode;
1653
+ $this->password = $key->password;
1654
+ $this->configFile = $key->configFile;
1655
+ $this->comment = $key->comment;
1656
+
1657
+ if (is_object($key->hash)) {
1658
+ $this->hash = new Hash($key->hash->getHash());
1659
+ }
1660
+ if (is_object($key->mgfHash)) {
1661
+ $this->mgfHash = new Hash($key->mgfHash->getHash());
1662
+ }
1663
+
1664
+ if (is_object($key->modulus)) {
1665
+ $this->modulus = $key->modulus->copy();
1666
+ }
1667
+ if (is_object($key->exponent)) {
1668
+ $this->exponent = $key->exponent->copy();
1669
+ }
1670
+ if (is_object($key->publicExponent)) {
1671
+ $this->publicExponent = $key->publicExponent->copy();
1672
+ }
1673
+
1674
+ $this->primes = array();
1675
+ $this->exponents = array();
1676
+ $this->coefficients = array();
1677
+
1678
+ foreach ($this->primes as $prime) {
1679
+ $this->primes[] = $prime->copy();
1680
+ }
1681
+ foreach ($this->exponents as $exponent) {
1682
+ $this->exponents[] = $exponent->copy();
1683
+ }
1684
+ foreach ($this->coefficients as $coefficient) {
1685
+ $this->coefficients[] = $coefficient->copy();
1686
+ }
1687
+
1688
+ return true;
1689
+ }
1690
+
1691
+ if ($type === false) {
1692
+ $types = array(
1693
+ self::PUBLIC_FORMAT_RAW,
1694
+ self::PRIVATE_FORMAT_PKCS1,
1695
+ self::PRIVATE_FORMAT_XML,
1696
+ self::PRIVATE_FORMAT_PUTTY,
1697
+ self::PUBLIC_FORMAT_OPENSSH,
1698
+ self::PRIVATE_FORMAT_OPENSSH
1699
+ );
1700
+ foreach ($types as $type) {
1701
+ $components = $this->_parseKey($key, $type);
1702
+ if ($components !== false) {
1703
+ break;
1704
+ }
1705
+ }
1706
+ } else {
1707
+ $components = $this->_parseKey($key, $type);
1708
+ }
1709
+
1710
+ if ($components === false) {
1711
+ $this->comment = null;
1712
+ $this->modulus = null;
1713
+ $this->k = null;
1714
+ $this->exponent = null;
1715
+ $this->primes = null;
1716
+ $this->exponents = null;
1717
+ $this->coefficients = null;
1718
+ $this->publicExponent = null;
1719
+
1720
+ return false;
1721
+ }
1722
+
1723
+ if (isset($components['comment']) && $components['comment'] !== false) {
1724
+ $this->comment = $components['comment'];
1725
+ }
1726
+ $this->modulus = $components['modulus'];
1727
+ $this->k = strlen($this->modulus->toBytes());
1728
+ $this->exponent = isset($components['privateExponent']) ? $components['privateExponent'] : $components['publicExponent'];
1729
+ if (isset($components['primes'])) {
1730
+ $this->primes = $components['primes'];
1731
+ $this->exponents = $components['exponents'];
1732
+ $this->coefficients = $components['coefficients'];
1733
+ $this->publicExponent = $components['publicExponent'];
1734
+ } else {
1735
+ $this->primes = array();
1736
+ $this->exponents = array();
1737
+ $this->coefficients = array();
1738
+ $this->publicExponent = false;
1739
+ }
1740
+
1741
+ switch ($type) {
1742
+ case self::PUBLIC_FORMAT_OPENSSH:
1743
+ case self::PUBLIC_FORMAT_RAW:
1744
+ $this->setPublicKey();
1745
+ break;
1746
+ case self::PRIVATE_FORMAT_PKCS1:
1747
+ switch (true) {
1748
+ case strpos($key, '-BEGIN PUBLIC KEY-') !== false:
1749
+ case strpos($key, '-BEGIN RSA PUBLIC KEY-') !== false:
1750
+ $this->setPublicKey();
1751
+ }
1752
+ }
1753
+
1754
+ return true;
1755
+ }
1756
+
1757
+ /**
1758
+ * Sets the password
1759
+ *
1760
+ * Private keys can be encrypted with a password. To unset the password, pass in the empty string or false.
1761
+ * Or rather, pass in $password such that empty($password) && !is_string($password) is true.
1762
+ *
1763
+ * @see self::createKey()
1764
+ * @see self::loadKey()
1765
+ * @access public
1766
+ * @param string $password
1767
+ */
1768
+ function setPassword($password = false)
1769
+ {
1770
+ $this->password = $password;
1771
+ }
1772
+
1773
+ /**
1774
+ * Defines the public key
1775
+ *
1776
+ * Some private key formats define the public exponent and some don't. Those that don't define it are problematic when
1777
+ * used in certain contexts. For example, in SSH-2, RSA authentication works by sending the public key along with a
1778
+ * message signed by the private key to the server. The SSH-2 server looks the public key up in an index of public keys
1779
+ * and if it's present then proceeds to verify the signature. Problem is, if your private key doesn't include the public
1780
+ * exponent this won't work unless you manually add the public exponent. phpseclib tries to guess if the key being used
1781
+ * is the public key but in the event that it guesses incorrectly you might still want to explicitly set the key as being
1782
+ * public.
1783
+ *
1784
+ * Do note that when a new key is loaded the index will be cleared.
1785
+ *
1786
+ * Returns true on success, false on failure
1787
+ *
1788
+ * @see self::getPublicKey()
1789
+ * @access public
1790
+ * @param string $key optional
1791
+ * @param int $type optional
1792
+ * @return bool
1793
+ */
1794
+ function setPublicKey($key = false, $type = false)
1795
+ {
1796
+ // if a public key has already been loaded return false
1797
+ if (!empty($this->publicExponent)) {
1798
+ return false;
1799
+ }
1800
+
1801
+ if ($key === false && !empty($this->modulus)) {
1802
+ $this->publicExponent = $this->exponent;
1803
+ return true;
1804
+ }
1805
+
1806
+ if ($type === false) {
1807
+ $types = array(
1808
+ self::PUBLIC_FORMAT_RAW,
1809
+ self::PUBLIC_FORMAT_PKCS1,
1810
+ self::PUBLIC_FORMAT_XML,
1811
+ self::PUBLIC_FORMAT_OPENSSH
1812
+ );
1813
+ foreach ($types as $type) {
1814
+ $components = $this->_parseKey($key, $type);
1815
+ if ($components !== false) {
1816
+ break;
1817
+ }
1818
+ }
1819
+ } else {
1820
+ $components = $this->_parseKey($key, $type);
1821
+ }
1822
+
1823
+ if ($components === false) {
1824
+ return false;
1825
+ }
1826
+
1827
+ if (empty($this->modulus) || !$this->modulus->equals($components['modulus'])) {
1828
+ $this->modulus = $components['modulus'];
1829
+ $this->exponent = $this->publicExponent = $components['publicExponent'];
1830
+ return true;
1831
+ }
1832
+
1833
+ $this->publicExponent = $components['publicExponent'];
1834
+
1835
+ return true;
1836
+ }
1837
+
1838
+ /**
1839
+ * Defines the private key
1840
+ *
1841
+ * If phpseclib guessed a private key was a public key and loaded it as such it might be desirable to force
1842
+ * phpseclib to treat the key as a private key. This function will do that.
1843
+ *
1844
+ * Do note that when a new key is loaded the index will be cleared.
1845
+ *
1846
+ * Returns true on success, false on failure
1847
+ *
1848
+ * @see self::getPublicKey()
1849
+ * @access public
1850
+ * @param string $key optional
1851
+ * @param int $type optional
1852
+ * @return bool
1853
+ */
1854
+ function setPrivateKey($key = false, $type = false)
1855
+ {
1856
+ if ($key === false && !empty($this->publicExponent)) {
1857
+ $this->publicExponent = false;
1858
+ return true;
1859
+ }
1860
+
1861
+ $rsa = new RSA();
1862
+ if (!$rsa->loadKey($key, $type)) {
1863
+ return false;
1864
+ }
1865
+ $rsa->publicExponent = false;
1866
+
1867
+ // don't overwrite the old key if the new key is invalid
1868
+ $this->loadKey($rsa);
1869
+ return true;
1870
+ }
1871
+
1872
+ /**
1873
+ * Returns the public key
1874
+ *
1875
+ * The public key is only returned under two circumstances - if the private key had the public key embedded within it
1876
+ * or if the public key was set via setPublicKey(). If the currently loaded key is supposed to be the public key this
1877
+ * function won't return it since this library, for the most part, doesn't distinguish between public and private keys.
1878
+ *
1879
+ * @see self::getPublicKey()
1880
+ * @access public
1881
+ * @param string $key
1882
+ * @param int $type optional
1883
+ */
1884
+ function getPublicKey($type = self::PUBLIC_FORMAT_PKCS8)
1885
+ {
1886
+ if (empty($this->modulus) || empty($this->publicExponent)) {
1887
+ return false;
1888
+ }
1889
+
1890
+ $oldFormat = $this->publicKeyFormat;
1891
+ $this->publicKeyFormat = $type;
1892
+ $temp = $this->_convertPublicKey($this->modulus, $this->publicExponent);
1893
+ $this->publicKeyFormat = $oldFormat;
1894
+ return $temp;
1895
+ }
1896
+
1897
+ /**
1898
+ * Returns the public key's fingerprint
1899
+ *
1900
+ * The public key's fingerprint is returned, which is equivalent to running `ssh-keygen -lf rsa.pub`. If there is
1901
+ * no public key currently loaded, false is returned.
1902
+ * Example output (md5): "c1:b1:30:29:d7:b8:de:6c:97:77:10:d7:46:41:63:87" (as specified by RFC 4716)
1903
+ *
1904
+ * @access public
1905
+ * @param string $algorithm The hashing algorithm to be used. Valid options are 'md5' and 'sha256'. False is returned
1906
+ * for invalid values.
1907
+ * @return mixed
1908
+ */
1909
+ function getPublicKeyFingerprint($algorithm = 'md5')
1910
+ {
1911
+ if (empty($this->modulus) || empty($this->publicExponent)) {
1912
+ return false;
1913
+ }
1914
+
1915
+ $modulus = $this->modulus->toBytes(true);
1916
+ $publicExponent = $this->publicExponent->toBytes(true);
1917
+
1918
+ $RSAPublicKey = pack('Na*Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($publicExponent), $publicExponent, strlen($modulus), $modulus);
1919
+
1920
+ switch ($algorithm) {
1921
+ case 'sha256':
1922
+ $hash = new Hash('sha256');
1923
+ $base = base64_encode($hash->hash($RSAPublicKey));
1924
+ return substr($base, 0, strlen($base) - 1);
1925
+ case 'md5':
1926
+ return substr(chunk_split(md5($RSAPublicKey), 2, ':'), 0, -1);
1927
+ default:
1928
+ return false;
1929
+ }
1930
+ }
1931
+
1932
+ /**
1933
+ * Returns the private key
1934
+ *
1935
+ * The private key is only returned if the currently loaded key contains the constituent prime numbers.
1936
+ *
1937
+ * @see self::getPublicKey()
1938
+ * @access public
1939
+ * @param string $key
1940
+ * @param int $type optional
1941
+ * @return mixed
1942
+ */
1943
+ function getPrivateKey($type = self::PUBLIC_FORMAT_PKCS1)
1944
+ {
1945
+ if (empty($this->primes)) {
1946
+ return false;
1947
+ }
1948
+
1949
+ $oldFormat = $this->privateKeyFormat;
1950
+ $this->privateKeyFormat = $type;
1951
+ $temp = $this->_convertPrivateKey($this->modulus, $this->publicExponent, $this->exponent, $this->primes, $this->exponents, $this->coefficients);
1952
+ $this->privateKeyFormat = $oldFormat;
1953
+ return $temp;
1954
+ }
1955
+
1956
+ /**
1957
+ * Returns a minimalistic private key
1958
+ *
1959
+ * Returns the private key without the prime number constituants. Structurally identical to a public key that
1960
+ * hasn't been set as the public key
1961
+ *
1962
+ * @see self::getPrivateKey()
1963
+ * @access private
1964
+ * @param string $key
1965
+ * @param int $type optional
1966
+ */
1967
+ function _getPrivatePublicKey($mode = self::PUBLIC_FORMAT_PKCS8)
1968
+ {
1969
+ if (empty($this->modulus) || empty($this->exponent)) {
1970
+ return false;
1971
+ }
1972
+
1973
+ $oldFormat = $this->publicKeyFormat;
1974
+ $this->publicKeyFormat = $mode;
1975
+ $temp = $this->_convertPublicKey($this->modulus, $this->exponent);
1976
+ $this->publicKeyFormat = $oldFormat;
1977
+ return $temp;
1978
+ }
1979
+
1980
+ /**
1981
+ * __toString() magic method
1982
+ *
1983
+ * @access public
1984
+ * @return string
1985
+ */
1986
+ function __toString()
1987
+ {
1988
+ $key = $this->getPrivateKey($this->privateKeyFormat);
1989
+ if ($key !== false) {
1990
+ return $key;
1991
+ }
1992
+ $key = $this->_getPrivatePublicKey($this->publicKeyFormat);
1993
+ return $key !== false ? $key : '';
1994
+ }
1995
+
1996
+ /**
1997
+ * __clone() magic method
1998
+ *
1999
+ * @access public
2000
+ * @return Crypt_RSA
2001
+ */
2002
+ function __clone()
2003
+ {
2004
+ $key = new RSA();
2005
+ $key->loadKey($this);
2006
+ return $key;
2007
+ }
2008
+
2009
+ /**
2010
+ * Generates the smallest and largest numbers requiring $bits bits
2011
+ *
2012
+ * @access private
2013
+ * @param int $bits
2014
+ * @return array
2015
+ */
2016
+ function _generateMinMax($bits)
2017
+ {
2018
+ $bytes = $bits >> 3;
2019
+ $min = str_repeat(chr(0), $bytes);
2020
+ $max = str_repeat(chr(0xFF), $bytes);
2021
+ $msb = $bits & 7;
2022
+ if ($msb) {
2023
+ $min = chr(1 << ($msb - 1)) . $min;
2024
+ $max = chr((1 << $msb) - 1) . $max;
2025
+ } else {
2026
+ $min[0] = chr(0x80);
2027
+ }
2028
+
2029
+ return array(
2030
+ 'min' => new BigInteger($min, 256),
2031
+ 'max' => new BigInteger($max, 256)
2032
+ );
2033
+ }
2034
+
2035
+ /**
2036
+ * DER-decode the length
2037
+ *
2038
+ * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See
2039
+ * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information.
2040
+ *
2041
+ * @access private
2042
+ * @param string $string
2043
+ * @return int
2044
+ */
2045
+ function _decodeLength(&$string)
2046
+ {
2047
+ $length = ord($this->_string_shift($string));
2048
+ if ($length & 0x80) { // definite length, long form
2049
+ $length&= 0x7F;
2050
+ $temp = $this->_string_shift($string, $length);
2051
+ list(, $length) = unpack('N', substr(str_pad($temp, 4, chr(0), STR_PAD_LEFT), -4));
2052
+ }
2053
+ return $length;
2054
+ }
2055
+
2056
+ /**
2057
+ * DER-encode the length
2058
+ *
2059
+ * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See
2060
+ * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information.
2061
+ *
2062
+ * @access private
2063
+ * @param int $length
2064
+ * @return string
2065
+ */
2066
+ function _encodeLength($length)
2067
+ {
2068
+ if ($length <= 0x7F) {
2069
+ return chr($length);
2070
+ }
2071
+
2072
+ $temp = ltrim(pack('N', $length), chr(0));
2073
+ return pack('Ca*', 0x80 | strlen($temp), $temp);
2074
+ }
2075
+
2076
+ /**
2077
+ * String Shift
2078
+ *
2079
+ * Inspired by array_shift
2080
+ *
2081
+ * @param string $string
2082
+ * @param int $index
2083
+ * @return string
2084
+ * @access private
2085
+ */
2086
+ function _string_shift(&$string, $index = 1)
2087
+ {
2088
+ $substr = substr($string, 0, $index);
2089
+ $string = substr($string, $index);
2090
+ return $substr;
2091
+ }
2092
+
2093
+ /**
2094
+ * Determines the private key format
2095
+ *
2096
+ * @see self::createKey()
2097
+ * @access public
2098
+ * @param int $format
2099
+ */
2100
+ function setPrivateKeyFormat($format)
2101
+ {
2102
+ $this->privateKeyFormat = $format;
2103
+ }
2104
+
2105
+ /**
2106
+ * Determines the public key format
2107
+ *
2108
+ * @see self::createKey()
2109
+ * @access public
2110
+ * @param int $format
2111
+ */
2112
+ function setPublicKeyFormat($format)
2113
+ {
2114
+ $this->publicKeyFormat = $format;
2115
+ }
2116
+
2117
+ /**
2118
+ * Determines which hashing function should be used
2119
+ *
2120
+ * Used with signature production / verification and (if the encryption mode is self::ENCRYPTION_OAEP) encryption and
2121
+ * decryption. If $hash isn't supported, sha1 is used.
2122
+ *
2123
+ * @access public
2124
+ * @param string $hash
2125
+ */
2126
+ function setHash($hash)
2127
+ {
2128
+ // \phpseclib\Crypt\Hash supports algorithms that PKCS#1 doesn't support. md5-96 and sha1-96, for example.
2129
+ switch ($hash) {
2130
+ case 'md2':
2131
+ case 'md5':
2132
+ case 'sha1':
2133
+ case 'sha256':
2134
+ case 'sha384':
2135
+ case 'sha512':
2136
+ $this->hash = new Hash($hash);
2137
+ $this->hashName = $hash;
2138
+ break;
2139
+ default:
2140
+ $this->hash = new Hash('sha1');
2141
+ $this->hashName = 'sha1';
2142
+ }
2143
+ $this->hLen = $this->hash->getLength();
2144
+ }
2145
+
2146
+ /**
2147
+ * Determines which hashing function should be used for the mask generation function
2148
+ *
2149
+ * The mask generation function is used by self::ENCRYPTION_OAEP and self::SIGNATURE_PSS and although it's
2150
+ * best if Hash and MGFHash are set to the same thing this is not a requirement.
2151
+ *
2152
+ * @access public
2153
+ * @param string $hash
2154
+ */
2155
+ function setMGFHash($hash)
2156
+ {
2157
+ // \phpseclib\Crypt\Hash supports algorithms that PKCS#1 doesn't support. md5-96 and sha1-96, for example.
2158
+ switch ($hash) {
2159
+ case 'md2':
2160
+ case 'md5':
2161
+ case 'sha1':
2162
+ case 'sha256':
2163
+ case 'sha384':
2164
+ case 'sha512':
2165
+ $this->mgfHash = new Hash($hash);
2166
+ break;
2167
+ default:
2168
+ $this->mgfHash = new Hash('sha1');
2169
+ }
2170
+ $this->mgfHLen = $this->mgfHash->getLength();
2171
+ }
2172
+
2173
+ /**
2174
+ * Determines the salt length
2175
+ *
2176
+ * To quote from {@link http://tools.ietf.org/html/rfc3447#page-38 RFC3447#page-38}:
2177
+ *
2178
+ * Typical salt lengths in octets are hLen (the length of the output
2179
+ * of the hash function Hash) and 0.
2180
+ *
2181
+ * @access public
2182
+ * @param int $format
2183
+ */
2184
+ function setSaltLength($sLen)
2185
+ {
2186
+ $this->sLen = $sLen;
2187
+ }
2188
+
2189
+ /**
2190
+ * Integer-to-Octet-String primitive
2191
+ *
2192
+ * See {@link http://tools.ietf.org/html/rfc3447#section-4.1 RFC3447#section-4.1}.
2193
+ *
2194
+ * @access private
2195
+ * @param \phpseclib\Math\BigInteger $x
2196
+ * @param int $xLen
2197
+ * @return string
2198
+ */
2199
+ function _i2osp($x, $xLen)
2200
+ {
2201
+ $x = $x->toBytes();
2202
+ if (strlen($x) > $xLen) {
2203
+ user_error('Integer too large');
2204
+ return false;
2205
+ }
2206
+ return str_pad($x, $xLen, chr(0), STR_PAD_LEFT);
2207
+ }
2208
+
2209
+ /**
2210
+ * Octet-String-to-Integer primitive
2211
+ *
2212
+ * See {@link http://tools.ietf.org/html/rfc3447#section-4.2 RFC3447#section-4.2}.
2213
+ *
2214
+ * @access private
2215
+ * @param string $x
2216
+ * @return \phpseclib\Math\BigInteger
2217
+ */
2218
+ function _os2ip($x)
2219
+ {
2220
+ return new BigInteger($x, 256);
2221
+ }
2222
+
2223
+ /**
2224
+ * Exponentiate with or without Chinese Remainder Theorem
2225
+ *
2226
+ * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.1 RFC3447#section-5.1.2}.
2227
+ *
2228
+ * @access private
2229
+ * @param \phpseclib\Math\BigInteger $x
2230
+ * @return \phpseclib\Math\BigInteger
2231
+ */
2232
+ function _exponentiate($x)
2233
+ {
2234
+ switch (true) {
2235
+ case empty($this->primes):
2236
+ case $this->primes[1]->equals($this->zero):
2237
+ case empty($this->coefficients):
2238
+ case $this->coefficients[2]->equals($this->zero):
2239
+ case empty($this->exponents):
2240
+ case $this->exponents[1]->equals($this->zero):
2241
+ return $x->modPow($this->exponent, $this->modulus);
2242
+ }
2243
+
2244
+ $num_primes = count($this->primes);
2245
+
2246
+ if (defined('CRYPT_RSA_DISABLE_BLINDING')) {
2247
+ $m_i = array(
2248
+ 1 => $x->modPow($this->exponents[1], $this->primes[1]),
2249
+ 2 => $x->modPow($this->exponents[2], $this->primes[2])
2250
+ );
2251
+ $h = $m_i[1]->subtract($m_i[2]);
2252
+ $h = $h->multiply($this->coefficients[2]);
2253
+ list(, $h) = $h->divide($this->primes[1]);
2254
+ $m = $m_i[2]->add($h->multiply($this->primes[2]));
2255
+
2256
+ $r = $this->primes[1];
2257
+ for ($i = 3; $i <= $num_primes; $i++) {
2258
+ $m_i = $x->modPow($this->exponents[$i], $this->primes[$i]);
2259
+
2260
+ $r = $r->multiply($this->primes[$i - 1]);
2261
+
2262
+ $h = $m_i->subtract($m);
2263
+ $h = $h->multiply($this->coefficients[$i]);
2264
+ list(, $h) = $h->divide($this->primes[$i]);
2265
+
2266
+ $m = $m->add($r->multiply($h));
2267
+ }
2268
+ } else {
2269
+ $smallest = $this->primes[1];
2270
+ for ($i = 2; $i <= $num_primes; $i++) {
2271
+ if ($smallest->compare($this->primes[$i]) > 0) {
2272
+ $smallest = $this->primes[$i];
2273
+ }
2274
+ }
2275
+
2276
+ $one = new BigInteger(1);
2277
+
2278
+ $r = $one->random($one, $smallest->subtract($one));
2279
+
2280
+ $m_i = array(
2281
+ 1 => $this->_blind($x, $r, 1),
2282
+ 2 => $this->_blind($x, $r, 2)
2283
+ );
2284
+ $h = $m_i[1]->subtract($m_i[2]);
2285
+ $h = $h->multiply($this->coefficients[2]);
2286
+ list(, $h) = $h->divide($this->primes[1]);
2287
+ $m = $m_i[2]->add($h->multiply($this->primes[2]));
2288
+
2289
+ $r = $this->primes[1];
2290
+ for ($i = 3; $i <= $num_primes; $i++) {
2291
+ $m_i = $this->_blind($x, $r, $i);
2292
+
2293
+ $r = $r->multiply($this->primes[$i - 1]);
2294
+
2295
+ $h = $m_i->subtract($m);
2296
+ $h = $h->multiply($this->coefficients[$i]);
2297
+ list(, $h) = $h->divide($this->primes[$i]);
2298
+
2299
+ $m = $m->add($r->multiply($h));
2300
+ }
2301
+ }
2302
+
2303
+ return $m;
2304
+ }
2305
+
2306
+ /**
2307
+ * Performs RSA Blinding
2308
+ *
2309
+ * Protects against timing attacks by employing RSA Blinding.
2310
+ * Returns $x->modPow($this->exponents[$i], $this->primes[$i])
2311
+ *
2312
+ * @access private
2313
+ * @param \phpseclib\Math\BigInteger $x
2314
+ * @param \phpseclib\Math\BigInteger $r
2315
+ * @param int $i
2316
+ * @return \phpseclib\Math\BigInteger
2317
+ */
2318
+ function _blind($x, $r, $i)
2319
+ {
2320
+ $x = $x->multiply($r->modPow($this->publicExponent, $this->primes[$i]));
2321
+ $x = $x->modPow($this->exponents[$i], $this->primes[$i]);
2322
+
2323
+ $r = $r->modInverse($this->primes[$i]);
2324
+ $x = $x->multiply($r);
2325
+ list(, $x) = $x->divide($this->primes[$i]);
2326
+
2327
+ return $x;
2328
+ }
2329
+
2330
+ /**
2331
+ * Performs blinded RSA equality testing
2332
+ *
2333
+ * Protects against a particular type of timing attack described.
2334
+ *
2335
+ * See {@link http://codahale.com/a-lesson-in-timing-attacks/ A Lesson In Timing Attacks (or, Don't use MessageDigest.isEquals)}
2336
+ *
2337
+ * Thanks for the heads up singpolyma!
2338
+ *
2339
+ * @access private
2340
+ * @param string $x
2341
+ * @param string $y
2342
+ * @return bool
2343
+ */
2344
+ function _equals($x, $y)
2345
+ {
2346
+ if (function_exists('hash_equals')) {
2347
+ return hash_equals($x, $y);
2348
+ }
2349
+
2350
+ if (strlen($x) != strlen($y)) {
2351
+ return false;
2352
+ }
2353
+
2354
+ $result = "\0";
2355
+ $x^= $y;
2356
+ for ($i = 0; $i < strlen($x); $i++) {
2357
+ $result|= $x[$i];
2358
+ }
2359
+
2360
+ return $result === "\0";
2361
+ }
2362
+
2363
+ /**
2364
+ * RSAEP
2365
+ *
2366
+ * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.1 RFC3447#section-5.1.1}.
2367
+ *
2368
+ * @access private
2369
+ * @param \phpseclib\Math\BigInteger $m
2370
+ * @return \phpseclib\Math\BigInteger
2371
+ */
2372
+ function _rsaep($m)
2373
+ {
2374
+ if ($m->compare($this->zero) < 0 || $m->compare($this->modulus) > 0) {
2375
+ user_error('Message representative out of range');
2376
+ return false;
2377
+ }
2378
+ return $this->_exponentiate($m);
2379
+ }
2380
+
2381
+ /**
2382
+ * RSADP
2383
+ *
2384
+ * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.2 RFC3447#section-5.1.2}.
2385
+ *
2386
+ * @access private
2387
+ * @param \phpseclib\Math\BigInteger $c
2388
+ * @return \phpseclib\Math\BigInteger
2389
+ */
2390
+ function _rsadp($c)
2391
+ {
2392
+ if ($c->compare($this->zero) < 0 || $c->compare($this->modulus) > 0) {
2393
+ user_error('Ciphertext representative out of range');
2394
+ return false;
2395
+ }
2396
+ return $this->_exponentiate($c);
2397
+ }
2398
+
2399
+ /**
2400
+ * RSASP1
2401
+ *
2402
+ * See {@link http://tools.ietf.org/html/rfc3447#section-5.2.1 RFC3447#section-5.2.1}.
2403
+ *
2404
+ * @access private
2405
+ * @param \phpseclib\Math\BigInteger $m
2406
+ * @return \phpseclib\Math\BigInteger
2407
+ */
2408
+ function _rsasp1($m)
2409
+ {
2410
+ if ($m->compare($this->zero) < 0 || $m->compare($this->modulus) > 0) {
2411
+ user_error('Message representative out of range');
2412
+ return false;
2413
+ }
2414
+ return $this->_exponentiate($m);
2415
+ }
2416
+
2417
+ /**
2418
+ * RSAVP1
2419
+ *
2420
+ * See {@link http://tools.ietf.org/html/rfc3447#section-5.2.2 RFC3447#section-5.2.2}.
2421
+ *
2422
+ * @access private
2423
+ * @param \phpseclib\Math\BigInteger $s
2424
+ * @return \phpseclib\Math\BigInteger
2425
+ */
2426
+ function _rsavp1($s)
2427
+ {
2428
+ if ($s->compare($this->zero) < 0 || $s->compare($this->modulus) > 0) {
2429
+ user_error('Signature representative out of range');
2430
+ return false;
2431
+ }
2432
+ return $this->_exponentiate($s);
2433
+ }
2434
+
2435
+ /**
2436
+ * MGF1
2437
+ *
2438
+ * See {@link http://tools.ietf.org/html/rfc3447#appendix-B.2.1 RFC3447#appendix-B.2.1}.
2439
+ *
2440
+ * @access private
2441
+ * @param string $mgfSeed
2442
+ * @param int $mgfLen
2443
+ * @return string
2444
+ */
2445
+ function _mgf1($mgfSeed, $maskLen)
2446
+ {
2447
+ // if $maskLen would yield strings larger than 4GB, PKCS#1 suggests a "Mask too long" error be output.
2448
+
2449
+ $t = '';
2450
+ $count = ceil($maskLen / $this->mgfHLen);
2451
+ for ($i = 0; $i < $count; $i++) {
2452
+ $c = pack('N', $i);
2453
+ $t.= $this->mgfHash->hash($mgfSeed . $c);
2454
+ }
2455
+
2456
+ return substr($t, 0, $maskLen);
2457
+ }
2458
+
2459
+ /**
2460
+ * RSAES-OAEP-ENCRYPT
2461
+ *
2462
+ * See {@link http://tools.ietf.org/html/rfc3447#section-7.1.1 RFC3447#section-7.1.1} and
2463
+ * {http://en.wikipedia.org/wiki/Optimal_Asymmetric_Encryption_Padding OAES}.
2464
+ *
2465
+ * @access private
2466
+ * @param string $m
2467
+ * @param string $l
2468
+ * @return string
2469
+ */
2470
+ function _rsaes_oaep_encrypt($m, $l = '')
2471
+ {
2472
+ $mLen = strlen($m);
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 ($mLen > $this->k - 2 * $this->hLen - 2) {
2480
+ user_error('Message too long');
2481
+ return false;
2482
+ }
2483
+
2484
+ // EME-OAEP encoding
2485
+
2486
+ $lHash = $this->hash->hash($l);
2487
+ $ps = str_repeat(chr(0), $this->k - $mLen - 2 * $this->hLen - 2);
2488
+ $db = $lHash . $ps . chr(1) . $m;
2489
+ $seed = Random::string($this->hLen);
2490
+ $dbMask = $this->_mgf1($seed, $this->k - $this->hLen - 1);
2491
+ $maskedDB = $db ^ $dbMask;
2492
+ $seedMask = $this->_mgf1($maskedDB, $this->hLen);
2493
+ $maskedSeed = $seed ^ $seedMask;
2494
+ $em = chr(0) . $maskedSeed . $maskedDB;
2495
+
2496
+ // RSA encryption
2497
+
2498
+ $m = $this->_os2ip($em);
2499
+ $c = $this->_rsaep($m);
2500
+ $c = $this->_i2osp($c, $this->k);
2501
+
2502
+ // Output the ciphertext C
2503
+
2504
+ return $c;
2505
+ }
2506
+
2507
+ /**
2508
+ * RSAES-OAEP-DECRYPT
2509
+ *
2510
+ * See {@link http://tools.ietf.org/html/rfc3447#section-7.1.2 RFC3447#section-7.1.2}. The fact that the error
2511
+ * messages aren't distinguishable from one another hinders debugging, but, to quote from RFC3447#section-7.1.2:
2512
+ *
2513
+ * Note. Care must be taken to ensure that an opponent cannot
2514
+ * distinguish the different error conditions in Step 3.g, whether by
2515
+ * error message or timing, or, more generally, learn partial
2516
+ * information about the encoded message EM. Otherwise an opponent may
2517
+ * be able to obtain useful information about the decryption of the
2518
+ * ciphertext C, leading to a chosen-ciphertext attack such as the one
2519
+ * observed by Manger [36].
2520
+ *
2521
+ * As for $l... to quote from {@link http://tools.ietf.org/html/rfc3447#page-17 RFC3447#page-17}:
2522
+ *
2523
+ * Both the encryption and the decryption operations of RSAES-OAEP take
2524
+ * the value of a label L as input. In this version of PKCS #1, L is
2525
+ * the empty string; other uses of the label are outside the scope of
2526
+ * this document.
2527
+ *
2528
+ * @access private
2529
+ * @param string $c
2530
+ * @param string $l
2531
+ * @return string
2532
+ */
2533
+ function _rsaes_oaep_decrypt($c, $l = '')
2534
+ {
2535
+ // Length checking
2536
+
2537
+ // if $l is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
2538
+ // be output.
2539
+
2540
+ if (strlen($c) != $this->k || $this->k < 2 * $this->hLen + 2) {
2541
+ user_error('Decryption error');
2542
+ return false;
2543
+ }
2544
+
2545
+ // RSA decryption
2546
+
2547
+ $c = $this->_os2ip($c);
2548
+ $m = $this->_rsadp($c);
2549
+ if ($m === false) {
2550
+ user_error('Decryption error');
2551
+ return false;
2552
+ }
2553
+ $em = $this->_i2osp($m, $this->k);
2554
+
2555
+ // EME-OAEP decoding
2556
+
2557
+ $lHash = $this->hash->hash($l);
2558
+ $y = ord($em[0]);
2559
+ $maskedSeed = substr($em, 1, $this->hLen);
2560
+ $maskedDB = substr($em, $this->hLen + 1);
2561
+ $seedMask = $this->_mgf1($maskedDB, $this->hLen);
2562
+ $seed = $maskedSeed ^ $seedMask;
2563
+ $dbMask = $this->_mgf1($seed, $this->k - $this->hLen - 1);
2564
+ $db = $maskedDB ^ $dbMask;
2565
+ $lHash2 = substr($db, 0, $this->hLen);
2566
+ $m = substr($db, $this->hLen);
2567
+ $hashesMatch = $this->_equals($lHash, $lHash2);
2568
+ $leadingZeros = 1;
2569
+ $patternMatch = 0;
2570
+ $offset = 0;
2571
+ for ($i = 0; $i < strlen($m); $i++) {
2572
+ $patternMatch|= $leadingZeros & ($m[$i] === "\1");
2573
+ $leadingZeros&= $m[$i] === "\0";
2574
+ $offset+= $patternMatch ? 0 : 1;
2575
+ }
2576
+
2577
+ // we do & instead of && to avoid https://en.wikipedia.org/wiki/Short-circuit_evaluation
2578
+ // to protect against timing attacks
2579
+ if (!$hashesMatch & !$patternMatch) {
2580
+ user_error('Decryption error');
2581
+ return false;
2582
+ }
2583
+
2584
+ // Output the message M
2585
+
2586
+ return substr($m, $offset + 1);
2587
+ }
2588
+
2589
+ /**
2590
+ * Raw Encryption / Decryption
2591
+ *
2592
+ * Doesn't use padding and is not recommended.
2593
+ *
2594
+ * @access private
2595
+ * @param string $m
2596
+ * @return string
2597
+ */
2598
+ function _raw_encrypt($m)
2599
+ {
2600
+ $temp = $this->_os2ip($m);
2601
+ $temp = $this->_rsaep($temp);
2602
+ return $this->_i2osp($temp, $this->k);
2603
+ }
2604
+
2605
+ /**
2606
+ * RSAES-PKCS1-V1_5-ENCRYPT
2607
+ *
2608
+ * See {@link http://tools.ietf.org/html/rfc3447#section-7.2.1 RFC3447#section-7.2.1}.
2609
+ *
2610
+ * @access private
2611
+ * @param string $m
2612
+ * @return string
2613
+ */
2614
+ function _rsaes_pkcs1_v1_5_encrypt($m)
2615
+ {
2616
+ $mLen = strlen($m);
2617
+
2618
+ // Length checking
2619
+
2620
+ if ($mLen > $this->k - 11) {
2621
+ user_error('Message too long');
2622
+ return false;
2623
+ }
2624
+
2625
+ // EME-PKCS1-v1_5 encoding
2626
+
2627
+ $psLen = $this->k - $mLen - 3;
2628
+ $ps = '';
2629
+ while (strlen($ps) != $psLen) {
2630
+ $temp = Random::string($psLen - strlen($ps));
2631
+ $temp = str_replace("\x00", '', $temp);
2632
+ $ps.= $temp;
2633
+ }
2634
+ $type = 2;
2635
+ // see the comments of _rsaes_pkcs1_v1_5_decrypt() to understand why this is being done
2636
+ if (defined('CRYPT_RSA_PKCS15_COMPAT') && (!isset($this->publicExponent) || $this->exponent !== $this->publicExponent)) {
2637
+ $type = 1;
2638
+ // "The padding string PS shall consist of k-3-||D|| octets. ... for block type 01, they shall have value FF"
2639
+ $ps = str_repeat("\xFF", $psLen);
2640
+ }
2641
+ $em = chr(0) . chr($type) . $ps . chr(0) . $m;
2642
+
2643
+ // RSA encryption
2644
+ $m = $this->_os2ip($em);
2645
+ $c = $this->_rsaep($m);
2646
+ $c = $this->_i2osp($c, $this->k);
2647
+
2648
+ // Output the ciphertext C
2649
+
2650
+ return $c;
2651
+ }
2652
+
2653
+ /**
2654
+ * RSAES-PKCS1-V1_5-DECRYPT
2655
+ *
2656
+ * See {@link http://tools.ietf.org/html/rfc3447#section-7.2.2 RFC3447#section-7.2.2}.
2657
+ *
2658
+ * For compatibility purposes, this function departs slightly from the description given in RFC3447.
2659
+ * The reason being that RFC2313#section-8.1 (PKCS#1 v1.5) states that ciphertext's encrypted by the
2660
+ * private key should have the second byte set to either 0 or 1 and that ciphertext's encrypted by the
2661
+ * public key should have the second byte set to 2. In RFC3447 (PKCS#1 v2.1), the second byte is supposed
2662
+ * to be 2 regardless of which key is used. For compatibility purposes, we'll just check to make sure the
2663
+ * second byte is 2 or less. If it is, we'll accept the decrypted string as valid.
2664
+ *
2665
+ * As a consequence of this, a private key encrypted ciphertext produced with \phpseclib\Crypt\RSA may not decrypt
2666
+ * with a strictly PKCS#1 v1.5 compliant RSA implementation. Public key encrypted ciphertext's should but
2667
+ * not private key encrypted ciphertext's.
2668
+ *
2669
+ * @access private
2670
+ * @param string $c
2671
+ * @return string
2672
+ */
2673
+ function _rsaes_pkcs1_v1_5_decrypt($c)
2674
+ {
2675
+ // Length checking
2676
+
2677
+ if (strlen($c) != $this->k) { // or if k < 11
2678
+ user_error('Decryption error');
2679
+ return false;
2680
+ }
2681
+
2682
+ // RSA decryption
2683
+
2684
+ $c = $this->_os2ip($c);
2685
+ $m = $this->_rsadp($c);
2686
+
2687
+ if ($m === false) {
2688
+ user_error('Decryption error');
2689
+ return false;
2690
+ }
2691
+ $em = $this->_i2osp($m, $this->k);
2692
+
2693
+ // EME-PKCS1-v1_5 decoding
2694
+
2695
+ if (ord($em[0]) != 0 || ord($em[1]) > 2) {
2696
+ user_error('Decryption error');
2697
+ return false;
2698
+ }
2699
+
2700
+ $ps = substr($em, 2, strpos($em, chr(0), 2) - 2);
2701
+ $m = substr($em, strlen($ps) + 3);
2702
+
2703
+ if (strlen($ps) < 8) {
2704
+ user_error('Decryption error');
2705
+ return false;
2706
+ }
2707
+
2708
+ // Output M
2709
+
2710
+ return $m;
2711
+ }
2712
+
2713
+ /**
2714
+ * EMSA-PSS-ENCODE
2715
+ *
2716
+ * See {@link http://tools.ietf.org/html/rfc3447#section-9.1.1 RFC3447#section-9.1.1}.
2717
+ *
2718
+ * @access private
2719
+ * @param string $m
2720
+ * @param int $emBits
2721
+ */
2722
+ function _emsa_pss_encode($m, $emBits)
2723
+ {
2724
+ // if $m is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
2725
+ // be output.
2726
+
2727
+ $emLen = ($emBits + 1) >> 3; // ie. ceil($emBits / 8)
2728
+ $sLen = $this->sLen !== null ? $this->sLen : $this->hLen;
2729
+
2730
+ $mHash = $this->hash->hash($m);
2731
+ if ($emLen < $this->hLen + $sLen + 2) {
2732
+ user_error('Encoding error');
2733
+ return false;
2734
+ }
2735
+
2736
+ $salt = Random::string($sLen);
2737
+ $m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt;
2738
+ $h = $this->hash->hash($m2);
2739
+ $ps = str_repeat(chr(0), $emLen - $sLen - $this->hLen - 2);
2740
+ $db = $ps . chr(1) . $salt;
2741
+ $dbMask = $this->_mgf1($h, $emLen - $this->hLen - 1);
2742
+ $maskedDB = $db ^ $dbMask;
2743
+ $maskedDB[0] = ~chr(0xFF << ($emBits & 7)) & $maskedDB[0];
2744
+ $em = $maskedDB . $h . chr(0xBC);
2745
+
2746
+ return $em;
2747
+ }
2748
+
2749
+ /**
2750
+ * EMSA-PSS-VERIFY
2751
+ *
2752
+ * See {@link http://tools.ietf.org/html/rfc3447#section-9.1.2 RFC3447#section-9.1.2}.
2753
+ *
2754
+ * @access private
2755
+ * @param string $m
2756
+ * @param string $em
2757
+ * @param int $emBits
2758
+ * @return string
2759
+ */
2760
+ function _emsa_pss_verify($m, $em, $emBits)
2761
+ {
2762
+ // if $m is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
2763
+ // be output.
2764
+
2765
+ $emLen = ($emBits + 1) >> 3; // ie. ceil($emBits / 8);
2766
+ $sLen = $this->sLen !== null ? $this->sLen : $this->hLen;
2767
+
2768
+ $mHash = $this->hash->hash($m);
2769
+ if ($emLen < $this->hLen + $sLen + 2) {
2770
+ return false;
2771
+ }
2772
+
2773
+ if ($em[strlen($em) - 1] != chr(0xBC)) {
2774
+ return false;
2775
+ }
2776
+
2777
+ $maskedDB = substr($em, 0, -$this->hLen - 1);
2778
+ $h = substr($em, -$this->hLen - 1, $this->hLen);
2779
+ $temp = chr(0xFF << ($emBits & 7));
2780
+ if ((~$maskedDB[0] & $temp) != $temp) {
2781
+ return false;
2782
+ }
2783
+ $dbMask = $this->_mgf1($h, $emLen - $this->hLen - 1);
2784
+ $db = $maskedDB ^ $dbMask;
2785
+ $db[0] = ~chr(0xFF << ($emBits & 7)) & $db[0];
2786
+ $temp = $emLen - $this->hLen - $sLen - 2;
2787
+ if (substr($db, 0, $temp) != str_repeat(chr(0), $temp) || ord($db[$temp]) != 1) {
2788
+ return false;
2789
+ }
2790
+ $salt = substr($db, $temp + 1); // should be $sLen long
2791
+ $m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt;
2792
+ $h2 = $this->hash->hash($m2);
2793
+ return $this->_equals($h, $h2);
2794
+ }
2795
+
2796
+ /**
2797
+ * RSASSA-PSS-SIGN
2798
+ *
2799
+ * See {@link http://tools.ietf.org/html/rfc3447#section-8.1.1 RFC3447#section-8.1.1}.
2800
+ *
2801
+ * @access private
2802
+ * @param string $m
2803
+ * @return string
2804
+ */
2805
+ function _rsassa_pss_sign($m)
2806
+ {
2807
+ // EMSA-PSS encoding
2808
+
2809
+ $em = $this->_emsa_pss_encode($m, 8 * $this->k - 1);
2810
+
2811
+ // RSA signature
2812
+
2813
+ $m = $this->_os2ip($em);
2814
+ $s = $this->_rsasp1($m);
2815
+ $s = $this->_i2osp($s, $this->k);
2816
+
2817
+ // Output the signature S
2818
+
2819
+ return $s;
2820
+ }
2821
+
2822
+ /**
2823
+ * RSASSA-PSS-VERIFY
2824
+ *
2825
+ * See {@link http://tools.ietf.org/html/rfc3447#section-8.1.2 RFC3447#section-8.1.2}.
2826
+ *
2827
+ * @access private
2828
+ * @param string $m
2829
+ * @param string $s
2830
+ * @return string
2831
+ */
2832
+ function _rsassa_pss_verify($m, $s)
2833
+ {
2834
+ // Length checking
2835
+
2836
+ if (strlen($s) != $this->k) {
2837
+ user_error('Invalid signature');
2838
+ return false;
2839
+ }
2840
+
2841
+ // RSA verification
2842
+
2843
+ $modBits = 8 * $this->k;
2844
+
2845
+ $s2 = $this->_os2ip($s);
2846
+ $m2 = $this->_rsavp1($s2);
2847
+ if ($m2 === false) {
2848
+ user_error('Invalid signature');
2849
+ return false;
2850
+ }
2851
+ $em = $this->_i2osp($m2, $modBits >> 3);
2852
+ if ($em === false) {
2853
+ user_error('Invalid signature');
2854
+ return false;
2855
+ }
2856
+
2857
+ // EMSA-PSS verification
2858
+
2859
+ return $this->_emsa_pss_verify($m, $em, $modBits - 1);
2860
+ }
2861
+
2862
+ /**
2863
+ * EMSA-PKCS1-V1_5-ENCODE
2864
+ *
2865
+ * See {@link http://tools.ietf.org/html/rfc3447#section-9.2 RFC3447#section-9.2}.
2866
+ *
2867
+ * @access private
2868
+ * @param string $m
2869
+ * @param int $emLen
2870
+ * @return string
2871
+ */
2872
+ function _emsa_pkcs1_v1_5_encode($m, $emLen)
2873
+ {
2874
+ $h = $this->hash->hash($m);
2875
+ if ($h === false) {
2876
+ return false;
2877
+ }
2878
+
2879
+ // see http://tools.ietf.org/html/rfc3447#page-43
2880
+ switch ($this->hashName) {
2881
+ case 'md2':
2882
+ $t = pack('H*', '3020300c06082a864886f70d020205000410');
2883
+ break;
2884
+ case 'md5':
2885
+ $t = pack('H*', '3020300c06082a864886f70d020505000410');
2886
+ break;
2887
+ case 'sha1':
2888
+ $t = pack('H*', '3021300906052b0e03021a05000414');
2889
+ break;
2890
+ case 'sha256':
2891
+ $t = pack('H*', '3031300d060960864801650304020105000420');
2892
+ break;
2893
+ case 'sha384':
2894
+ $t = pack('H*', '3041300d060960864801650304020205000430');
2895
+ break;
2896
+ case 'sha512':
2897
+ $t = pack('H*', '3051300d060960864801650304020305000440');
2898
+ }
2899
+ $t.= $h;
2900
+ $tLen = strlen($t);
2901
+
2902
+ if ($emLen < $tLen + 11) {
2903
+ user_error('Intended encoded message length too short');
2904
+ return false;
2905
+ }
2906
+
2907
+ $ps = str_repeat(chr(0xFF), $emLen - $tLen - 3);
2908
+
2909
+ $em = "\0\1$ps\0$t";
2910
+
2911
+ return $em;
2912
+ }
2913
+
2914
+ /**
2915
+ * RSASSA-PKCS1-V1_5-SIGN
2916
+ *
2917
+ * See {@link http://tools.ietf.org/html/rfc3447#section-8.2.1 RFC3447#section-8.2.1}.
2918
+ *
2919
+ * @access private
2920
+ * @param string $m
2921
+ * @return string
2922
+ */
2923
+ function _rsassa_pkcs1_v1_5_sign($m)
2924
+ {
2925
+ // EMSA-PKCS1-v1_5 encoding
2926
+
2927
+ $em = $this->_emsa_pkcs1_v1_5_encode($m, $this->k);
2928
+ if ($em === false) {
2929
+ user_error('RSA modulus too short');
2930
+ return false;
2931
+ }
2932
+
2933
+ // RSA signature
2934
+
2935
+ $m = $this->_os2ip($em);
2936
+ $s = $this->_rsasp1($m);
2937
+ $s = $this->_i2osp($s, $this->k);
2938
+
2939
+ // Output the signature S
2940
+
2941
+ return $s;
2942
+ }
2943
+
2944
+ /**
2945
+ * RSASSA-PKCS1-V1_5-VERIFY
2946
+ *
2947
+ * See {@link http://tools.ietf.org/html/rfc3447#section-8.2.2 RFC3447#section-8.2.2}.
2948
+ *
2949
+ * @access private
2950
+ * @param string $m
2951
+ * @return string
2952
+ */
2953
+ function _rsassa_pkcs1_v1_5_verify($m, $s)
2954
+ {
2955
+ // Length checking
2956
+
2957
+ if (strlen($s) != $this->k) {
2958
+ user_error('Invalid signature');
2959
+ return false;
2960
+ }
2961
+
2962
+ // RSA verification
2963
+
2964
+ $s = $this->_os2ip($s);
2965
+ $m2 = $this->_rsavp1($s);
2966
+ if ($m2 === false) {
2967
+ user_error('Invalid signature');
2968
+ return false;
2969
+ }
2970
+ $em = $this->_i2osp($m2, $this->k);
2971
+ if ($em === false) {
2972
+ user_error('Invalid signature');
2973
+ return false;
2974
+ }
2975
+
2976
+ // EMSA-PKCS1-v1_5 encoding
2977
+
2978
+ $em2 = $this->_emsa_pkcs1_v1_5_encode($m, $this->k);
2979
+ if ($em2 === false) {
2980
+ user_error('RSA modulus too short');
2981
+ return false;
2982
+ }
2983
+
2984
+ // Compare
2985
+ return $this->_equals($em, $em2);
2986
+ }
2987
+
2988
+ /**
2989
+ * Set Encryption Mode
2990
+ *
2991
+ * Valid values include self::ENCRYPTION_OAEP and self::ENCRYPTION_PKCS1.
2992
+ *
2993
+ * @access public
2994
+ * @param int $mode
2995
+ */
2996
+ function setEncryptionMode($mode)
2997
+ {
2998
+ $this->encryptionMode = $mode;
2999
+ }
3000
+
3001
+ /**
3002
+ * Set Signature Mode
3003
+ *
3004
+ * Valid values include self::SIGNATURE_PSS and self::SIGNATURE_PKCS1
3005
+ *
3006
+ * @access public
3007
+ * @param int $mode
3008
+ */
3009
+ function setSignatureMode($mode)
3010
+ {
3011
+ $this->signatureMode = $mode;
3012
+ }
3013
+
3014
+ /**
3015
+ * Set public key comment.
3016
+ *
3017
+ * @access public
3018
+ * @param string $comment
3019
+ */
3020
+ function setComment($comment)
3021
+ {
3022
+ $this->comment = $comment;
3023
+ }
3024
+
3025
+ /**
3026
+ * Get public key comment.
3027
+ *
3028
+ * @access public
3029
+ * @return string
3030
+ */
3031
+ function getComment()
3032
+ {
3033
+ return $this->comment;
3034
+ }
3035
+
3036
+ /**
3037
+ * Encryption
3038
+ *
3039
+ * Both self::ENCRYPTION_OAEP and self::ENCRYPTION_PKCS1 both place limits on how long $plaintext can be.
3040
+ * If $plaintext exceeds those limits it will be broken up so that it does and the resultant ciphertext's will
3041
+ * be concatenated together.
3042
+ *
3043
+ * @see self::decrypt()
3044
+ * @access public
3045
+ * @param string $plaintext
3046
+ * @return string
3047
+ */
3048
+ function encrypt($plaintext)
3049
+ {
3050
+ switch ($this->encryptionMode) {
3051
+ case self::ENCRYPTION_NONE:
3052
+ $plaintext = str_split($plaintext, $this->k);
3053
+ $ciphertext = '';
3054
+ foreach ($plaintext as $m) {
3055
+ $ciphertext.= $this->_raw_encrypt($m);
3056
+ }
3057
+ return $ciphertext;
3058
+ case self::ENCRYPTION_PKCS1:
3059
+ $length = $this->k - 11;
3060
+ if ($length <= 0) {
3061
+ return false;
3062
+ }
3063
+
3064
+ $plaintext = str_split($plaintext, $length);
3065
+ $ciphertext = '';
3066
+ foreach ($plaintext as $m) {
3067
+ $ciphertext.= $this->_rsaes_pkcs1_v1_5_encrypt($m);
3068
+ }
3069
+ return $ciphertext;
3070
+ //case self::ENCRYPTION_OAEP:
3071
+ default:
3072
+ $length = $this->k - 2 * $this->hLen - 2;
3073
+ if ($length <= 0) {
3074
+ return false;
3075
+ }
3076
+
3077
+ $plaintext = str_split($plaintext, $length);
3078
+ $ciphertext = '';
3079
+ foreach ($plaintext as $m) {
3080
+ $ciphertext.= $this->_rsaes_oaep_encrypt($m);
3081
+ }
3082
+ return $ciphertext;
3083
+ }
3084
+ }
3085
+
3086
+ /**
3087
+ * Decryption
3088
+ *
3089
+ * @see self::encrypt()
3090
+ * @access public
3091
+ * @param string $plaintext
3092
+ * @return string
3093
+ */
3094
+ function decrypt($ciphertext)
3095
+ {
3096
+ if ($this->k <= 0) {
3097
+ return false;
3098
+ }
3099
+
3100
+ $ciphertext = str_split($ciphertext, $this->k);
3101
+ $ciphertext[count($ciphertext) - 1] = str_pad($ciphertext[count($ciphertext) - 1], $this->k, chr(0), STR_PAD_LEFT);
3102
+
3103
+ $plaintext = '';
3104
+
3105
+ switch ($this->encryptionMode) {
3106
+ case self::ENCRYPTION_NONE:
3107
+ $decrypt = '_raw_encrypt';
3108
+ break;
3109
+ case self::ENCRYPTION_PKCS1:
3110
+ $decrypt = '_rsaes_pkcs1_v1_5_decrypt';
3111
+ break;
3112
+ //case self::ENCRYPTION_OAEP:
3113
+ default:
3114
+ $decrypt = '_rsaes_oaep_decrypt';
3115
+ }
3116
+
3117
+ foreach ($ciphertext as $c) {
3118
+ $temp = $this->$decrypt($c);
3119
+ if ($temp === false) {
3120
+ return false;
3121
+ }
3122
+ $plaintext.= $temp;
3123
+ }
3124
+
3125
+ return $plaintext;
3126
+ }
3127
+
3128
+ /**
3129
+ * Create a signature
3130
+ *
3131
+ * @see self::verify()
3132
+ * @access public
3133
+ * @param string $message
3134
+ * @return string
3135
+ */
3136
+ function sign($message)
3137
+ {
3138
+ if (empty($this->modulus) || empty($this->exponent)) {
3139
+ return false;
3140
+ }
3141
+
3142
+ switch ($this->signatureMode) {
3143
+ case self::SIGNATURE_PKCS1:
3144
+ return $this->_rsassa_pkcs1_v1_5_sign($message);
3145
+ //case self::SIGNATURE_PSS:
3146
+ default:
3147
+ return $this->_rsassa_pss_sign($message);
3148
+ }
3149
+ }
3150
+
3151
+ /**
3152
+ * Verifies a signature
3153
+ *
3154
+ * @see self::sign()
3155
+ * @access public
3156
+ * @param string $message
3157
+ * @param string $signature
3158
+ * @return bool
3159
+ */
3160
+ function verify($message, $signature)
3161
+ {
3162
+ if (empty($this->modulus) || empty($this->exponent)) {
3163
+ return false;
3164
+ }
3165
+
3166
+ switch ($this->signatureMode) {
3167
+ case self::SIGNATURE_PKCS1:
3168
+ return $this->_rsassa_pkcs1_v1_5_verify($message, $signature);
3169
+ //case self::SIGNATURE_PSS:
3170
+ default:
3171
+ return $this->_rsassa_pss_verify($message, $signature);
3172
+ }
3173
+ }
3174
+
3175
+ /**
3176
+ * Extract raw BER from Base64 encoding
3177
+ *
3178
+ * @access private
3179
+ * @param string $str
3180
+ * @return string
3181
+ */
3182
+ function _extractBER($str)
3183
+ {
3184
+ /* X.509 certs are assumed to be base64 encoded but sometimes they'll have additional things in them
3185
+ * above and beyond the ceritificate.
3186
+ * ie. some may have the following preceding the -----BEGIN CERTIFICATE----- line:
3187
+ *
3188
+ * Bag Attributes
3189
+ * localKeyID: 01 00 00 00
3190
+ * subject=/O=organization/OU=org unit/CN=common name
3191
+ * issuer=/O=organization/CN=common name
3192
+ */
3193
+ $temp = preg_replace('#.*?^-+[^-]+-+[\r\n ]*$#ms', '', $str, 1);
3194
+ // remove the -----BEGIN CERTIFICATE----- and -----END CERTIFICATE----- stuff
3195
+ $temp = preg_replace('#-+[^-]+-+#', '', $temp);
3196
+ // remove new lines
3197
+ $temp = str_replace(array("\r", "\n", ' '), '', $temp);
3198
+ $temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? base64_decode($temp) : false;
3199
+ return $temp != false ? $temp : $str;
3200
+ }
3201
+ }
vendor/phpseclib/phpseclib/phpseclib/Crypt/Random.php CHANGED
@@ -1,274 +1,274 @@
1
- <?php
2
-
3
- /**
4
- * Random Number Generator
5
- *
6
- * PHP version 5
7
- *
8
- * Here's a short example of how to use this library:
9
- * <code>
10
- * <?php
11
- * include 'vendor/autoload.php';
12
- *
13
- * echo bin2hex(\phpseclib\Crypt\Random::string(8));
14
- * ?>
15
- * </code>
16
- *
17
- * @category Crypt
18
- * @package Random
19
- * @author Jim Wigginton <terrafrost@php.net>
20
- * @copyright 2007 Jim Wigginton
21
- * @license http://www.opensource.org/licenses/mit-license.html MIT License
22
- * @link http://phpseclib.sourceforge.net
23
- */
24
-
25
- namespace phpseclib\Crypt;
26
-
27
- /**
28
- * Pure-PHP Random Number Generator
29
- *
30
- * @package Random
31
- * @author Jim Wigginton <terrafrost@php.net>
32
- * @access public
33
- */
34
- class Random
35
- {
36
- /**
37
- * Generate a random string.
38
- *
39
- * Although microoptimizations are generally discouraged as they impair readability this function is ripe with
40
- * microoptimizations because this function has the potential of being called a huge number of times.
41
- * eg. for RSA key generation.
42
- *
43
- * @param int $length
44
- * @return string
45
- */
46
- static function string($length)
47
- {
48
- if (!$length) {
49
- return '';
50
- }
51
-
52
- if (version_compare(PHP_VERSION, '7.0.0', '>=')) {
53
- try {
54
- return \random_bytes($length);
55
- } catch (\Throwable $e) {
56
- // If a sufficient source of randomness is unavailable, random_bytes() will throw an
57
- // object that implements the Throwable interface (Exception, TypeError, Error).
58
- // We don't actually need to do anything here. The string() method should just continue
59
- // as normal. Note, however, that if we don't have a sufficient source of randomness for
60
- // random_bytes(), most of the other calls here will fail too, so we'll end up using
61
- // the PHP implementation.
62
- }
63
- }
64
-
65
- if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
66
- // method 1. prior to PHP 5.3 this would call rand() on windows hence the function_exists('class_alias') call.
67
- // ie. class_alias is a function that was introduced in PHP 5.3
68
- if (extension_loaded('mcrypt') && function_exists('class_alias')) {
69
- return @mcrypt_create_iv($length);
70
- }
71
- // method 2. openssl_random_pseudo_bytes was introduced in PHP 5.3.0 but prior to PHP 5.3.4 there was,
72
- // to quote <http://php.net/ChangeLog-5.php#5.3.4>, "possible blocking behavior". as of 5.3.4
73
- // openssl_random_pseudo_bytes and mcrypt_create_iv do the exact same thing on Windows. ie. they both
74
- // call php_win32_get_random_bytes():
75
- //
76
- // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/openssl/openssl.c#L5008
77
- // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/mcrypt/mcrypt.c#L1392
78
- //
79
- // php_win32_get_random_bytes() is defined thusly:
80
- //
81
- // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/win32/winutil.c#L80
82
- //
83
- // we're calling it, all the same, in the off chance that the mcrypt extension is not available
84
- if (extension_loaded('openssl') && version_compare(PHP_VERSION, '5.3.4', '>=')) {
85
- return openssl_random_pseudo_bytes($length);
86
- }
87
- } else {
88
- // method 1. the fastest
89
- if (extension_loaded('openssl')) {
90
- return openssl_random_pseudo_bytes($length);
91
- }
92
- // method 2
93
- static $fp = true;
94
- if ($fp === true) {
95
- // warning's will be output unles the error suppression operator is used. errors such as
96
- // "open_basedir restriction in effect", "Permission denied", "No such file or directory", etc.
97
- $fp = @fopen('/dev/urandom', 'rb');
98
- }
99
- if ($fp !== true && $fp !== false) { // surprisingly faster than !is_bool() or is_resource()
100
- return fread($fp, $length);
101
- }
102
- // method 3. pretty much does the same thing as method 2 per the following url:
103
- // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/mcrypt/mcrypt.c#L1391
104
- // surprisingly slower than method 2. maybe that's because mcrypt_create_iv does a bunch of error checking that we're
105
- // not doing. regardless, this'll only be called if this PHP script couldn't open /dev/urandom due to open_basedir
106
- // restrictions or some such
107
- if (extension_loaded('mcrypt')) {
108
- return @mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
109
- }
110
- }
111
- // at this point we have no choice but to use a pure-PHP CSPRNG
112
-
113
- // cascade entropy across multiple PHP instances by fixing the session and collecting all
114
- // environmental variables, including the previous session data and the current session
115
- // data.
116
- //
117
- // mt_rand seeds itself by looking at the PID and the time, both of which are (relatively)
118
- // easy to guess at. linux uses mouse clicks, keyboard timings, etc, as entropy sources, but
119
- // PHP isn't low level to be able to use those as sources and on a web server there's not likely
120
- // going to be a ton of keyboard or mouse action. web servers do have one thing that we can use
121
- // however, a ton of people visiting the website. obviously you don't want to base your seeding
122
- // soley on parameters a potential attacker sends but (1) not everything in $_SERVER is controlled
123
- // by the user and (2) this isn't just looking at the data sent by the current user - it's based
124
- // on the data sent by all users. one user requests the page and a hash of their info is saved.
125
- // another user visits the page and the serialization of their data is utilized along with the
126
- // server envirnment stuff and a hash of the previous http request data (which itself utilizes
127
- // a hash of the session data before that). certainly an attacker should be assumed to have
128
- // full control over his own http requests. he, however, is not going to have control over
129
- // everyone's http requests.
130
- static $crypto = false, $v;
131
- if ($crypto === false) {
132
- // save old session data
133
- $old_session_id = session_id();
134
- $old_use_cookies = ini_get('session.use_cookies');
135
- $old_session_cache_limiter = session_cache_limiter();
136
- $_OLD_SESSION = isset($_SESSION) ? $_SESSION : false;
137
- if ($old_session_id != '') {
138
- session_write_close();
139
- }
140
-
141
- session_id(1);
142
- ini_set('session.use_cookies', 0);
143
- session_cache_limiter('');
144
- session_start();
145
-
146
- $v = $seed = $_SESSION['seed'] = pack('H*', sha1(
147
- (isset($_SERVER) ? phpseclib_safe_serialize($_SERVER) : '') .
148
- (isset($_POST) ? phpseclib_safe_serialize($_POST) : '') .
149
- (isset($_GET) ? phpseclib_safe_serialize($_GET) : '') .
150
- (isset($_COOKIE) ? phpseclib_safe_serialize($_COOKIE) : '') .
151
- phpseclib_safe_serialize($GLOBALS) .
152
- phpseclib_safe_serialize($_SESSION) .
153
- phpseclib_safe_serialize($_OLD_SESSION)
154
- ));
155
- if (!isset($_SESSION['count'])) {
156
- $_SESSION['count'] = 0;
157
- }
158
- $_SESSION['count']++;
159
-
160
- session_write_close();
161
-
162
- // restore old session data
163
- if ($old_session_id != '') {
164
- session_id($old_session_id);
165
- session_start();
166
- ini_set('session.use_cookies', $old_use_cookies);
167
- session_cache_limiter($old_session_cache_limiter);
168
- } else {
169
- if ($_OLD_SESSION !== false) {
170
- $_SESSION = $_OLD_SESSION;
171
- unset($_OLD_SESSION);
172
- } else {
173
- unset($_SESSION);
174
- }
175
- }
176
-
177
- // in SSH2 a shared secret and an exchange hash are generated through the key exchange process.
178
- // 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.
179
- // if the hash doesn't produce enough a key or an IV that's long enough concat successive hashes of the
180
- // original hash and the current hash. we'll be emulating that. for more info see the following URL:
181
- //
182
- // http://tools.ietf.org/html/rfc4253#section-7.2
183
- //
184
- // see the is_string($crypto) part for an example of how to expand the keys
185
- $key = pack('H*', sha1($seed . 'A'));
186
- $iv = pack('H*', sha1($seed . 'C'));
187
-
188
- // ciphers are used as per the nist.gov link below. also, see this link:
189
- //
190
- // http://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator#Designs_based_on_cryptographic_primitives
191
- switch (true) {
192
- case class_exists('\phpseclib\Crypt\AES'):
193
- $crypto = new AES(Base::MODE_CTR);
194
- break;
195
- case class_exists('\phpseclib\Crypt\Twofish'):
196
- $crypto = new Twofish(Base::MODE_CTR);
197
- break;
198
- case class_exists('\phpseclib\Crypt\Blowfish'):
199
- $crypto = new Blowfish(Base::MODE_CTR);
200
- break;
201
- case class_exists('\phpseclib\Crypt\TripleDES'):
202
- $crypto = new TripleDES(Base::MODE_CTR);
203
- break;
204
- case class_exists('\phpseclib\Crypt\DES'):
205
- $crypto = new DES(Base::MODE_CTR);
206
- break;
207
- case class_exists('\phpseclib\Crypt\RC4'):
208
- $crypto = new RC4();
209
- break;
210
- default:
211
- user_error(__CLASS__ . ' requires at least one symmetric cipher be loaded');
212
- return false;
213
- }
214
-
215
- $crypto->setKey($key);
216
- $crypto->setIV($iv);
217
- $crypto->enableContinuousBuffer();
218
- }
219
-
220
- //return $crypto->encrypt(str_repeat("\0", $length));
221
-
222
- // the following is based off of ANSI X9.31:
223
- //
224
- // http://csrc.nist.gov/groups/STM/cavp/documents/rng/931rngext.pdf
225
- //
226
- // OpenSSL uses that same standard for it's random numbers:
227
- //
228
- // http://www.opensource.apple.com/source/OpenSSL/OpenSSL-38/openssl/fips-1.0/rand/fips_rand.c
229
- // (do a search for "ANS X9.31 A.2.4")
230
- $result = '';
231
- while (strlen($result) < $length) {
232
- $i = $crypto->encrypt(microtime()); // strlen(microtime()) == 21
233
- $r = $crypto->encrypt($i ^ $v); // strlen($v) == 20
234
- $v = $crypto->encrypt($r ^ $i); // strlen($r) == 20
235
- $result.= $r;
236
- }
237
- return substr($result, 0, $length);
238
- }
239
- }
240
-
241
- if (!function_exists('phpseclib_safe_serialize')) {
242
- /**
243
- * Safely serialize variables
244
- *
245
- * If a class has a private __sleep() method it'll give a fatal error on PHP 5.2 and earlier.
246
- * PHP 5.3 will emit a warning.
247
- *
248
- * @param mixed $arr
249
- * @access public
250
- */
251
- function phpseclib_safe_serialize(&$arr)
252
- {
253
- if (is_object($arr)) {
254
- return '';
255
- }
256
- if (!is_array($arr)) {
257
- return serialize($arr);
258
- }
259
- // prevent circular array recursion
260
- if (isset($arr['__phpseclib_marker'])) {
261
- return '';
262
- }
263
- $safearr = array();
264
- $arr['__phpseclib_marker'] = true;
265
- foreach (array_keys($arr) as $key) {
266
- // do not recurse on the '__phpseclib_marker' key itself, for smaller memory usage
267
- if ($key !== '__phpseclib_marker') {
268
- $safearr[$key] = phpseclib_safe_serialize($arr[$key]);
269
- }
270
- }
271
- unset($arr['__phpseclib_marker']);
272
- return serialize($safearr);
273
- }
274
- }
1
+ <?php
2
+
3
+ /**
4
+ * Random Number Generator
5
+ *
6
+ * PHP version 5
7
+ *
8
+ * Here's a short example of how to use this library:
9
+ * <code>
10
+ * <?php
11
+ * include 'vendor/autoload.php';
12
+ *
13
+ * echo bin2hex(\phpseclib\Crypt\Random::string(8));
14
+ * ?>
15
+ * </code>
16
+ *
17
+ * @category Crypt
18
+ * @package Random
19
+ * @author Jim Wigginton <terrafrost@php.net>
20
+ * @copyright 2007 Jim Wigginton
21
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
22
+ * @link http://phpseclib.sourceforge.net
23
+ */
24
+
25
+ namespace phpseclib\Crypt;
26
+
27
+ /**
28
+ * Pure-PHP Random Number Generator
29
+ *
30
+ * @package Random
31
+ * @author Jim Wigginton <terrafrost@php.net>
32
+ * @access public
33
+ */
34
+ class Random
35
+ {
36
+ /**
37
+ * Generate a random string.
38
+ *
39
+ * Although microoptimizations are generally discouraged as they impair readability this function is ripe with
40
+ * microoptimizations because this function has the potential of being called a huge number of times.
41
+ * eg. for RSA key generation.
42
+ *
43
+ * @param int $length
44
+ * @return string
45
+ */
46
+ static function string($length)
47
+ {
48
+ if (!$length) {
49
+ return '';
50
+ }
51
+
52
+ if (version_compare(PHP_VERSION, '7.0.0', '>=')) {
53
+ try {
54
+ return \random_bytes($length);
55
+ } catch (\Throwable $e) {
56
+ // If a sufficient source of randomness is unavailable, random_bytes() will throw an
57
+ // object that implements the Throwable interface (Exception, TypeError, Error).
58
+ // We don't actually need to do anything here. The string() method should just continue
59
+ // as normal. Note, however, that if we don't have a sufficient source of randomness for
60
+ // random_bytes(), most of the other calls here will fail too, so we'll end up using
61
+ // the PHP implementation.
62
+ }
63
+ }
64
+
65
+ if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
66
+ // method 1. prior to PHP 5.3 this would call rand() on windows hence the function_exists('class_alias') call.
67
+ // ie. class_alias is a function that was introduced in PHP 5.3
68
+ if (extension_loaded('mcrypt') && function_exists('class_alias')) {
69
+ return @mcrypt_create_iv($length);
70
+ }
71
+ // method 2. openssl_random_pseudo_bytes was introduced in PHP 5.3.0 but prior to PHP 5.3.4 there was,
72
+ // to quote <http://php.net/ChangeLog-5.php#5.3.4>, "possible blocking behavior". as of 5.3.4
73
+ // openssl_random_pseudo_bytes and mcrypt_create_iv do the exact same thing on Windows. ie. they both
74
+ // call php_win32_get_random_bytes():
75
+ //
76
+ // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/openssl/openssl.c#L5008
77
+ // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/mcrypt/mcrypt.c#L1392
78
+ //
79
+ // php_win32_get_random_bytes() is defined thusly:
80
+ //
81
+ // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/win32/winutil.c#L80
82
+ //
83
+ // we're calling it, all the same, in the off chance that the mcrypt extension is not available
84
+ if (extension_loaded('openssl') && version_compare(PHP_VERSION, '5.3.4', '>=')) {
85
+ return openssl_random_pseudo_bytes($length);
86
+ }
87
+ } else {
88
+ // method 1. the fastest
89
+ if (extension_loaded('openssl')) {
90
+ return openssl_random_pseudo_bytes($length);
91
+ }
92
+ // method 2
93
+ static $fp = true;
94
+ if ($fp === true) {
95
+ // warning's will be output unles the error suppression operator is used. errors such as
96
+ // "open_basedir restriction in effect", "Permission denied", "No such file or directory", etc.
97
+ $fp = @fopen('/dev/urandom', 'rb');
98
+ }
99
+ if ($fp !== true && $fp !== false) { // surprisingly faster than !is_bool() or is_resource()
100
+ return fread($fp, $length);
101
+ }
102
+ // method 3. pretty much does the same thing as method 2 per the following url:
103
+ // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/mcrypt/mcrypt.c#L1391
104
+ // surprisingly slower than method 2. maybe that's because mcrypt_create_iv does a bunch of error checking that we're
105
+ // not doing. regardless, this'll only be called if this PHP script couldn't open /dev/urandom due to open_basedir
106
+ // restrictions or some such
107
+ if (extension_loaded('mcrypt')) {
108
+ return @mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
109
+ }
110
+ }
111
+ // at this point we have no choice but to use a pure-PHP CSPRNG
112
+
113
+ // cascade entropy across multiple PHP instances by fixing the session and collecting all
114
+ // environmental variables, including the previous session data and the current session
115
+ // data.
116
+ //
117
+ // mt_rand seeds itself by looking at the PID and the time, both of which are (relatively)
118
+ // easy to guess at. linux uses mouse clicks, keyboard timings, etc, as entropy sources, but
119
+ // PHP isn't low level to be able to use those as sources and on a web server there's not likely
120
+ // going to be a ton of keyboard or mouse action. web servers do have one thing that we can use
121
+ // however, a ton of people visiting the website. obviously you don't want to base your seeding
122
+ // soley on parameters a potential attacker sends but (1) not everything in $_SERVER is controlled
123
+ // by the user and (2) this isn't just looking at the data sent by the current user - it's based
124
+ // on the data sent by all users. one user requests the page and a hash of their info is saved.
125
+ // another user visits the page and the serialization of their data is utilized along with the
126
+ // server envirnment stuff and a hash of the previous http request data (which itself utilizes
127
+ // a hash of the session data before that). certainly an attacker should be assumed to have
128
+ // full control over his own http requests. he, however, is not going to have control over
129
+ // everyone's http requests.
130
+ static $crypto = false, $v;
131
+ if ($crypto === false) {
132
+ // save old session data
133
+ $old_session_id = session_id();
134
+ $old_use_cookies = ini_get('session.use_cookies');
135
+ $old_session_cache_limiter = session_cache_limiter();
136
+ $_OLD_SESSION = isset($_SESSION) ? $_SESSION : false;
137
+ if ($old_session_id != '') {
138
+ session_write_close();
139
+ }
140
+
141
+ session_id(1);
142
+ ini_set('session.use_cookies', 0);
143
+ session_cache_limiter('');
144
+ session_start();
145
+
146
+ $v = $seed = $_SESSION['seed'] = pack('H*', sha1(
147
+ (isset($_SERVER) ? phpseclib_safe_serialize($_SERVER) : '') .
148
+ (isset($_POST) ? phpseclib_safe_serialize($_POST) : '') .
149
+ (isset($_GET) ? phpseclib_safe_serialize($_GET) : '') .
150
+ (isset($_COOKIE) ? phpseclib_safe_serialize($_COOKIE) : '') .
151
+ phpseclib_safe_serialize($GLOBALS) .
152
+ phpseclib_safe_serialize($_SESSION) .
153
+ phpseclib_safe_serialize($_OLD_SESSION)
154
+ ));
155
+ if (!isset($_SESSION['count'])) {
156
+ $_SESSION['count'] = 0;
157
+ }
158
+ $_SESSION['count']++;
159
+
160
+ session_write_close();
161
+
162
+ // restore old session data
163
+ if ($old_session_id != '') {
164
+ session_id($old_session_id);
165
+ session_start();
166
+ ini_set('session.use_cookies', $old_use_cookies);
167
+ session_cache_limiter($old_session_cache_limiter);
168
+ } else {
169
+ if ($_OLD_SESSION !== false) {
170
+ $_SESSION = $_OLD_SESSION;
171
+ unset($_OLD_SESSION);
172
+ } else {
173
+ unset($_SESSION);
174
+ }
175
+ }
176
+
177
+ // in SSH2 a shared secret and an exchange hash are generated through the key exchange process.
178
+ // 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.
179
+ // if the hash doesn't produce enough a key or an IV that's long enough concat successive hashes of the
180
+ // original hash and the current hash. we'll be emulating that. for more info see the following URL:
181
+ //
182
+ // http://tools.ietf.org/html/rfc4253#section-7.2
183
+ //
184
+ // see the is_string($crypto) part for an example of how to expand the keys
185
+ $key = pack('H*', sha1($seed . 'A'));
186
+ $iv = pack('H*', sha1($seed . 'C'));
187
+
188
+ // ciphers are used as per the nist.gov link below. also, see this link:
189
+ //
190
+ // http://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator#Designs_based_on_cryptographic_primitives
191
+ switch (true) {
192
+ case class_exists('\phpseclib\Crypt\AES'):
193
+ $crypto = new AES(Base::MODE_CTR);
194
+ break;
195
+ case class_exists('\phpseclib\Crypt\Twofish'):
196
+ $crypto = new Twofish(Base::MODE_CTR);
197
+ break;
198
+ case class_exists('\phpseclib\Crypt\Blowfish'):
199
+ $crypto = new Blowfish(Base::MODE_CTR);
200
+ break;
201
+ case class_exists('\phpseclib\Crypt\TripleDES'):
202
+ $crypto = new TripleDES(Base::MODE_CTR);
203
+ break;
204
+ case class_exists('\phpseclib\Crypt\DES'):
205
+ $crypto = new DES(Base::MODE_CTR);
206
+ break;
207
+ case class_exists('\phpseclib\Crypt\RC4'):
208
+ $crypto = new RC4();
209
+ break;
210
+ default:
211
+ user_error(__CLASS__ . ' requires at least one symmetric cipher be loaded');
212
+ return false;
213
+ }
214
+
215
+ $crypto->setKey($key);
216
+ $crypto->setIV($iv);
217
+ $crypto->enableContinuousBuffer();
218
+ }
219
+
220
+ //return $crypto->encrypt(str_repeat("\0", $length));
221
+
222
+ // the following is based off of ANSI X9.31:
223
+ //
224
+ // http://csrc.nist.gov/groups/STM/cavp/documents/rng/931rngext.pdf
225
+ //
226
+ // OpenSSL uses that same standard for it's random numbers:
227
+ //
228
+ // http://www.opensource.apple.com/source/OpenSSL/OpenSSL-38/openssl/fips-1.0/rand/fips_rand.c
229
+ // (do a search for "ANS X9.31 A.2.4")
230
+ $result = '';
231
+ while (strlen($result) < $length) {
232
+ $i = $crypto->encrypt(microtime()); // strlen(microtime()) == 21
233
+ $r = $crypto->encrypt($i ^ $v); // strlen($v) == 20
234
+ $v = $crypto->encrypt($r ^ $i); // strlen($r) == 20
235
+ $result.= $r;
236
+ }
237
+ return substr($result, 0, $length);
238
+ }
239
+ }
240
+
241
+ if (!function_exists('phpseclib_safe_serialize')) {
242
+ /**
243
+ * Safely serialize variables
244
+ *
245
+ * If a class has a private __sleep() method it'll give a fatal error on PHP 5.2 and earlier.
246
+ * PHP 5.3 will emit a warning.
247
+ *
248
+ * @param mixed $arr
249
+ * @access public
250
+ */
251
+ function phpseclib_safe_serialize(&$arr)
252
+ {
253
+ if (is_object($arr)) {
254
+ return '';
255
+ }
256
+ if (!is_array($arr)) {
257
+ return serialize($arr);
258
+ }
259
+ // prevent circular array recursion
260
+ if (isset($arr['__phpseclib_marker'])) {
261
+ return '';
262
+ }
263
+ $safearr = array();
264
+ $arr['__phpseclib_marker'] = true;
265
+ foreach (array_keys($arr) as $key) {
266
+ // do not recurse on the '__phpseclib_marker' key itself, for smaller memory usage
267
+ if ($key !== '__phpseclib_marker') {
268
+ $safearr[$key] = phpseclib_safe_serialize($arr[$key]);
269
+ }
270
+ }
271
+ unset($arr['__phpseclib_marker']);
272
+ return serialize($safearr);
273
+ }
274
+ }
vendor/phpseclib/phpseclib/phpseclib/Crypt/Rijndael.php CHANGED
@@ -1,936 +1,936 @@
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 version 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 'vendor/autoload.php';
32
- *
33
- * $rijndael = new \phpseclib\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
- * @category Crypt
48
- * @package Rijndael
49
- * @author Jim Wigginton <terrafrost@php.net>
50
- * @copyright 2008 Jim Wigginton
51
- * @license http://www.opensource.org/licenses/mit-license.html MIT License
52
- * @link http://phpseclib.sourceforge.net
53
- */
54
-
55
- namespace phpseclib\Crypt;
56
-
57
- /**
58
- * Pure-PHP implementation of Rijndael.
59
- *
60
- * @package Rijndael
61
- * @author Jim Wigginton <terrafrost@php.net>
62
- * @access public
63
- */
64
- class Rijndael extends Base
65
- {
66
- /**
67
- * The mcrypt specific name of the cipher
68
- *
69
- * Mcrypt is useable for 128/192/256-bit $block_size/$key_length. For 160/224 not.
70
- * \phpseclib\Crypt\Rijndael determines automatically whether mcrypt is useable
71
- * or not for the current $block_size/$key_length.
72
- * In case of, $cipher_name_mcrypt will be set dynamically at run time accordingly.
73
- *
74
- * @see \phpseclib\Crypt\Base::cipher_name_mcrypt
75
- * @see \phpseclib\Crypt\Base::engine
76
- * @see self::isValidEngine()
77
- * @var string
78
- * @access private
79
- */
80
- var $cipher_name_mcrypt = 'rijndael-128';
81
-
82
- /**
83
- * The default salt used by setPassword()
84
- *
85
- * @see \phpseclib\Crypt\Base::password_default_salt
86
- * @see \phpseclib\Crypt\Base::setPassword()
87
- * @var string
88
- * @access private
89
- */
90
- var $password_default_salt = 'phpseclib';
91
-
92
- /**
93
- * The Key Schedule
94
- *
95
- * @see self::_setup()
96
- * @var array
97
- * @access private
98
- */
99
- var $w;
100
-
101
- /**
102
- * The Inverse Key Schedule
103
- *
104
- * @see self::_setup()
105
- * @var array
106
- * @access private
107
- */
108
- var $dw;
109
-
110
- /**
111
- * The Block Length divided by 32
112
- *
113
- * @see self::setBlockLength()
114
- * @var int
115
- * @access private
116
- * @internal The max value is 256 / 32 = 8, the min value is 128 / 32 = 4. Exists in conjunction with $block_size
117
- * because the encryption / decryption / key schedule creation requires this number and not $block_size. We could
118
- * derive this from $block_size or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu
119
- * of that, we'll just precompute it once.
120
- */
121
- var $Nb = 4;
122
-
123
- /**
124
- * The Key Length (in bytes)
125
- *
126
- * @see self::setKeyLength()
127
- * @var int
128
- * @access private
129
- * @internal The max value is 256 / 8 = 32, the min value is 128 / 8 = 16. Exists in conjunction with $Nk
130
- * because the encryption / decryption / key schedule creation requires this number and not $key_length. We could
131
- * derive this from $key_length or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu
132
- * of that, we'll just precompute it once.
133
- */
134
- var $key_length = 16;
135
-
136
- /**
137
- * The Key Length divided by 32
138
- *
139
- * @see self::setKeyLength()
140
- * @var int
141
- * @access private
142
- * @internal The max value is 256 / 32 = 8, the min value is 128 / 32 = 4
143
- */
144
- var $Nk = 4;
145
-
146
- /**
147
- * The Number of Rounds
148
- *
149
- * @var int
150
- * @access private
151
- * @internal The max value is 14, the min value is 10.
152
- */
153
- var $Nr;
154
-
155
- /**
156
- * Shift offsets
157
- *
158
- * @var array
159
- * @access private
160
- */
161
- var $c;
162
-
163
- /**
164
- * Holds the last used key- and block_size information
165
- *
166
- * @var array
167
- * @access private
168
- */
169
- var $kl;
170
-
171
- /**
172
- * Sets the key length.
173
- *
174
- * Valid key lengths are 128, 160, 192, 224, and 256. If the length is less than 128, it will be rounded up to
175
- * 128. If the length is greater than 128 and invalid, it will be rounded down to the closest valid amount.
176
- *
177
- * Note: phpseclib extends Rijndael (and AES) for using 160- and 224-bit keys but they are officially not defined
178
- * and the most (if not all) implementations are not able using 160/224-bit keys but round/pad them up to
179
- * 192/256 bits as, for example, mcrypt will do.
180
- *
181
- * That said, if you want be compatible with other Rijndael and AES implementations,
182
- * you should not setKeyLength(160) or setKeyLength(224).
183
- *
184
- * Additional: In case of 160- and 224-bit keys, phpseclib will/can, for that reason, not use
185
- * the mcrypt php extension, even if available.
186
- * This results then in slower encryption.
187
- *
188
- * @access public
189
- * @param int $length
190
- */
191
- function setKeyLength($length)
192
- {
193
- switch (true) {
194
- case $length <= 128:
195
- $this->key_length = 16;
196
- break;
197
- case $length <= 160:
198
- $this->key_length = 20;
199
- break;
200
- case $length <= 192:
201
- $this->key_length = 24;
202
- break;
203
- case $length <= 224:
204
- $this->key_length = 28;
205
- break;
206
- default:
207
- $this->key_length = 32;
208
- }
209
-
210
- parent::setKeyLength($length);
211
- }
212
-
213
- /**
214
- * Sets the block length
215
- *
216
- * Valid block lengths are 128, 160, 192, 224, and 256. If the length is less than 128, it will be rounded up to
217
- * 128. If the length is greater than 128 and invalid, it will be rounded down to the closest valid amount.
218
- *
219
- * @access public
220
- * @param int $length
221
- */
222
- function setBlockLength($length)
223
- {
224
- $length >>= 5;
225
- if ($length > 8) {
226
- $length = 8;
227
- } elseif ($length < 4) {
228
- $length = 4;
229
- }
230
- $this->Nb = $length;
231
- $this->block_size = $length << 2;
232
- $this->changed = true;
233
- $this->_setEngine();
234
- }
235
-
236
- /**
237
- * Test for engine validity
238
- *
239
- * This is mainly just a wrapper to set things up for \phpseclib\Crypt\Base::isValidEngine()
240
- *
241
- * @see \phpseclib\Crypt\Base::__construct()
242
- * @param int $engine
243
- * @access public
244
- * @return bool
245
- */
246
- function isValidEngine($engine)
247
- {
248
- switch ($engine) {
249
- case self::ENGINE_OPENSSL:
250
- if ($this->block_size != 16) {
251
- return false;
252
- }
253
- $this->cipher_name_openssl_ecb = 'aes-' . ($this->key_length << 3) . '-ecb';
254
- $this->cipher_name_openssl = 'aes-' . ($this->key_length << 3) . '-' . $this->_openssl_translate_mode();
255
- break;
256
- case self::ENGINE_MCRYPT:
257
- $this->cipher_name_mcrypt = 'rijndael-' . ($this->block_size << 3);
258
- if ($this->key_length % 8) { // is it a 160/224-bit key?
259
- // mcrypt is not usable for them, only for 128/192/256-bit keys
260
- return false;
261
- }
262
- }
263
-
264
- return parent::isValidEngine($engine);
265
- }
266
-
267
- /**
268
- * Encrypts a block
269
- *
270
- * @access private
271
- * @param string $in
272
- * @return string
273
- */
274
- function _encryptBlock($in)
275
- {
276
- static $tables;
277
- if (empty($tables)) {
278
- $tables = &$this->_getTables();
279
- }
280
- $t0 = $tables[0];
281
- $t1 = $tables[1];
282
- $t2 = $tables[2];
283
- $t3 = $tables[3];
284
- $sbox = $tables[4];
285
-
286
- $state = array();
287
- $words = unpack('N*', $in);
288
-
289
- $c = $this->c;
290
- $w = $this->w;
291
- $Nb = $this->Nb;
292
- $Nr = $this->Nr;
293
-
294
- // addRoundKey
295
- $wc = $Nb - 1;
296
- foreach ($words as $word) {
297
- $state[] = $word ^ $w[++$wc];
298
- }
299
-
300
- // fips-197.pdf#page=19, "Figure 5. Pseudo Code for the Cipher", states that this loop has four components -
301
- // subBytes, shiftRows, mixColumns, and addRoundKey. fips-197.pdf#page=30, "Implementation Suggestions Regarding
302
- // Various Platforms" suggests that performs enhanced implementations are described in Rijndael-ammended.pdf.
303
- // Rijndael-ammended.pdf#page=20, "Implementation aspects / 32-bit processor", discusses such an optimization.
304
- // Unfortunately, the description given there is not quite correct. Per aes.spec.v316.pdf#page=19 [1],
305
- // equation (7.4.7) is supposed to use addition instead of subtraction, so we'll do that here, as well.
306
-
307
- // [1] http://fp.gladman.plus.com/cryptography_technology/rijndael/aes.spec.v316.pdf
308
- $temp = array();
309
- for ($round = 1; $round < $Nr; ++$round) {
310
- $i = 0; // $c[0] == 0
311
- $j = $c[1];
312
- $k = $c[2];
313
- $l = $c[3];
314
-
315
- while ($i < $Nb) {
316
- $temp[$i] = $t0[$state[$i] >> 24 & 0x000000FF] ^
317
- $t1[$state[$j] >> 16 & 0x000000FF] ^
318
- $t2[$state[$k] >> 8 & 0x000000FF] ^
319
- $t3[$state[$l] & 0x000000FF] ^
320
- $w[++$wc];
321
- ++$i;
322
- $j = ($j + 1) % $Nb;
323
- $k = ($k + 1) % $Nb;
324
- $l = ($l + 1) % $Nb;
325
- }
326
- $state = $temp;
327
- }
328
-
329
- // subWord
330
- for ($i = 0; $i < $Nb; ++$i) {
331
- $state[$i] = $sbox[$state[$i] & 0x000000FF] |
332
- ($sbox[$state[$i] >> 8 & 0x000000FF] << 8) |
333
- ($sbox[$state[$i] >> 16 & 0x000000FF] << 16) |
334
- ($sbox[$state[$i] >> 24 & 0x000000FF] << 24);
335
- }
336
-
337
- // shiftRows + addRoundKey
338
- $i = 0; // $c[0] == 0
339
- $j = $c[1];
340
- $k = $c[2];
341
- $l = $c[3];
342
- while ($i < $Nb) {
343
- $temp[$i] = ($state[$i] & 0xFF000000) ^
344
- ($state[$j] & 0x00FF0000) ^
345
- ($state[$k] & 0x0000FF00) ^
346
- ($state[$l] & 0x000000FF) ^
347
- $w[$i];
348
- ++$i;
349
- $j = ($j + 1) % $Nb;
350
- $k = ($k + 1) % $Nb;
351
- $l = ($l + 1) % $Nb;
352
- }
353
-
354
- switch ($Nb) {
355
- case 8:
356
- return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6], $temp[7]);
357
- case 7:
358
- return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6]);
359
- case 6:
360
- return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5]);
361
- case 5:
362
- return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4]);
363
- default:
364
- return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3]);
365
- }
366
- }
367
-
368
- /**
369
- * Decrypts a block
370
- *
371
- * @access private
372
- * @param string $in
373
- * @return string
374
- */
375
- function _decryptBlock($in)
376
- {
377
- static $invtables;
378
- if (empty($invtables)) {
379
- $invtables = &$this->_getInvTables();
380
- }
381
- $dt0 = $invtables[0];
382
- $dt1 = $invtables[1];
383
- $dt2 = $invtables[2];
384
- $dt3 = $invtables[3];
385
- $isbox = $invtables[4];
386
-
387
- $state = array();
388
- $words = unpack('N*', $in);
389
-
390
- $c = $this->c;
391
- $dw = $this->dw;
392
- $Nb = $this->Nb;
393
- $Nr = $this->Nr;
394
-
395
- // addRoundKey
396
- $wc = $Nb - 1;
397
- foreach ($words as $word) {
398
- $state[] = $word ^ $dw[++$wc];
399
- }
400
-
401
- $temp = array();
402
- for ($round = $Nr - 1; $round > 0; --$round) {
403
- $i = 0; // $c[0] == 0
404
- $j = $Nb - $c[1];
405
- $k = $Nb - $c[2];
406
- $l = $Nb - $c[3];
407
-
408
- while ($i < $Nb) {
409
- $temp[$i] = $dt0[$state[$i] >> 24 & 0x000000FF] ^
410
- $dt1[$state[$j] >> 16 & 0x000000FF] ^
411
- $dt2[$state[$k] >> 8 & 0x000000FF] ^
412
- $dt3[$state[$l] & 0x000000FF] ^
413
- $dw[++$wc];
414
- ++$i;
415
- $j = ($j + 1) % $Nb;
416
- $k = ($k + 1) % $Nb;
417
- $l = ($l + 1) % $Nb;
418
- }
419
- $state = $temp;
420
- }
421
-
422
- // invShiftRows + invSubWord + addRoundKey
423
- $i = 0; // $c[0] == 0
424
- $j = $Nb - $c[1];
425
- $k = $Nb - $c[2];
426
- $l = $Nb - $c[3];
427
-
428
- while ($i < $Nb) {
429
- $word = ($state[$i] & 0xFF000000) |
430
- ($state[$j] & 0x00FF0000) |
431
- ($state[$k] & 0x0000FF00) |
432
- ($state[$l] & 0x000000FF);
433
-
434
- $temp[$i] = $dw[$i] ^ ($isbox[$word & 0x000000FF] |
435
- ($isbox[$word >> 8 & 0x000000FF] << 8) |
436
- ($isbox[$word >> 16 & 0x000000FF] << 16) |
437
- ($isbox[$word >> 24 & 0x000000FF] << 24));
438
- ++$i;
439
- $j = ($j + 1) % $Nb;
440
- $k = ($k + 1) % $Nb;
441
- $l = ($l + 1) % $Nb;
442
- }
443
-
444
- switch ($Nb) {
445
- case 8:
446
- return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6], $temp[7]);
447
- case 7:
448
- return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6]);
449
- case 6:
450
- return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5]);
451
- case 5:
452
- return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4]);
453
- default:
454
- return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3]);
455
- }
456
- }
457
-
458
- /**
459
- * Setup the key (expansion)
460
- *
461
- * @see \phpseclib\Crypt\Base::_setupKey()
462
- * @access private
463
- */
464
- function _setupKey()
465
- {
466
- // Each number in $rcon is equal to the previous number multiplied by two in Rijndael's finite field.
467
- // See http://en.wikipedia.org/wiki/Finite_field_arithmetic#Multiplicative_inverse
468
- static $rcon = array(0,
469
- 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000,
470
- 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000,
471
- 0x6C000000, 0xD8000000, 0xAB000000, 0x4D000000, 0x9A000000,
472
- 0x2F000000, 0x5E000000, 0xBC000000, 0x63000000, 0xC6000000,
473
- 0x97000000, 0x35000000, 0x6A000000, 0xD4000000, 0xB3000000,
474
- 0x7D000000, 0xFA000000, 0xEF000000, 0xC5000000, 0x91000000
475
- );
476
-
477
- if (isset($this->kl['key']) && $this->key === $this->kl['key'] && $this->key_length === $this->kl['key_length'] && $this->block_size === $this->kl['block_size']) {
478
- // already expanded
479
- return;
480
- }
481
- $this->kl = array('key' => $this->key, 'key_length' => $this->key_length, 'block_size' => $this->block_size);
482
-
483
- $this->Nk = $this->key_length >> 2;
484
- // see Rijndael-ammended.pdf#page=44
485
- $this->Nr = max($this->Nk, $this->Nb) + 6;
486
-
487
- // shift offsets for Nb = 5, 7 are defined in Rijndael-ammended.pdf#page=44,
488
- // "Table 8: Shift offsets in Shiftrow for the alternative block lengths"
489
- // shift offsets for Nb = 4, 6, 8 are defined in Rijndael-ammended.pdf#page=14,
490
- // "Table 2: Shift offsets for different block lengths"
491
- switch ($this->Nb) {
492
- case 4:
493
- case 5:
494
- case 6:
495
- $this->c = array(0, 1, 2, 3);
496
- break;
497
- case 7:
498
- $this->c = array(0, 1, 2, 4);
499
- break;
500
- case 8:
501
- $this->c = array(0, 1, 3, 4);
502
- }
503
-
504
- $w = array_values(unpack('N*words', $this->key));
505
-
506
- $length = $this->Nb * ($this->Nr + 1);
507
- for ($i = $this->Nk; $i < $length; $i++) {
508
- $temp = $w[$i - 1];
509
- if ($i % $this->Nk == 0) {
510
- // according to <http://php.net/language.types.integer>, "the size of an integer is platform-dependent".
511
- // on a 32-bit machine, it's 32-bits, and on a 64-bit machine, it's 64-bits. on a 32-bit machine,
512
- // 0xFFFFFFFF << 8 == 0xFFFFFF00, but on a 64-bit machine, it equals 0xFFFFFFFF00. as such, doing 'and'
513
- // with 0xFFFFFFFF (or 0xFFFFFF00) on a 32-bit machine is unnecessary, but on a 64-bit machine, it is.
514
- $temp = (($temp << 8) & 0xFFFFFF00) | (($temp >> 24) & 0x000000FF); // rotWord
515
- $temp = $this->_subWord($temp) ^ $rcon[$i / $this->Nk];
516
- } elseif ($this->Nk > 6 && $i % $this->Nk == 4) {
517
- $temp = $this->_subWord($temp);
518
- }
519
- $w[$i] = $w[$i - $this->Nk] ^ $temp;
520
- }
521
-
522
- // convert the key schedule from a vector of $Nb * ($Nr + 1) length to a matrix with $Nr + 1 rows and $Nb columns
523
- // and generate the inverse key schedule. more specifically,
524
- // according to <http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=23> (section 5.3.3),
525
- // "The key expansion for the Inverse Cipher is defined as follows:
526
- // 1. Apply the Key Expansion.
527
- // 2. Apply InvMixColumn to all Round Keys except the first and the last one."
528
- // also, see fips-197.pdf#page=27, "5.3.5 Equivalent Inverse Cipher"
529
- list($dt0, $dt1, $dt2, $dt3) = $this->_getInvTables();
530
- $temp = $this->w = $this->dw = array();
531
- for ($i = $row = $col = 0; $i < $length; $i++, $col++) {
532
- if ($col == $this->Nb) {
533
- if ($row == 0) {
534
- $this->dw[0] = $this->w[0];
535
- } else {
536
- // subWord + invMixColumn + invSubWord = invMixColumn
537
- $j = 0;
538
- while ($j < $this->Nb) {
539
- $dw = $this->_subWord($this->w[$row][$j]);
540
- $temp[$j] = $dt0[$dw >> 24 & 0x000000FF] ^
541
- $dt1[$dw >> 16 & 0x000000FF] ^
542
- $dt2[$dw >> 8 & 0x000000FF] ^
543
- $dt3[$dw & 0x000000FF];
544
- $j++;
545
- }
546
- $this->dw[$row] = $temp;
547
- }
548
-
549
- $col = 0;
550
- $row++;
551
- }
552
- $this->w[$row][$col] = $w[$i];
553
- }
554
-
555
- $this->dw[$row] = $this->w[$row];
556
-
557
- // Converting to 1-dim key arrays (both ascending)
558
- $this->dw = array_reverse($this->dw);
559
- $w = array_pop($this->w);
560
- $dw = array_pop($this->dw);
561
- foreach ($this->w as $r => $wr) {
562
- foreach ($wr as $c => $wc) {
563
- $w[] = $wc;
564
- $dw[] = $this->dw[$r][$c];
565
- }
566
- }
567
- $this->w = $w;
568
- $this->dw = $dw;
569
- }
570
-
571
- /**
572
- * Performs S-Box substitutions
573
- *
574
- * @access private
575
- * @param int $word
576
- */
577
- function _subWord($word)
578
- {
579
- static $sbox;
580
- if (empty($sbox)) {
581
- list(, , , , $sbox) = $this->_getTables();
582
- }
583
-
584
- return $sbox[$word & 0x000000FF] |
585
- ($sbox[$word >> 8 & 0x000000FF] << 8) |
586
- ($sbox[$word >> 16 & 0x000000FF] << 16) |
587
- ($sbox[$word >> 24 & 0x000000FF] << 24);
588
- }
589
-
590
- /**
591
- * Provides the mixColumns and sboxes tables
592
- *
593
- * @see self::_encryptBlock()
594
- * @see self::_setupInlineCrypt()
595
- * @see self::_subWord()
596
- * @access private
597
- * @return array &$tables
598
- */
599
- function &_getTables()
600
- {
601
- static $tables;
602
- if (empty($tables)) {
603
- // according to <http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=19> (section 5.2.1),
604
- // precomputed tables can be used in the mixColumns phase. in that example, they're assigned t0...t3, so
605
- // those are the names we'll use.
606
- $t3 = array_map('intval', array(
607
- // with array_map('intval', ...) we ensure we have only int's and not
608
- // some slower floats converted by php automatically on high values
609
- 0x6363A5C6, 0x7C7C84F8, 0x777799EE, 0x7B7B8DF6, 0xF2F20DFF, 0x6B6BBDD6, 0x6F6FB1DE, 0xC5C55491,
610
- 0x30305060, 0x01010302, 0x6767A9CE, 0x2B2B7D56, 0xFEFE19E7, 0xD7D762B5, 0xABABE64D, 0x76769AEC,
611
- 0xCACA458F, 0x82829D1F, 0xC9C94089, 0x7D7D87FA, 0xFAFA15EF, 0x5959EBB2, 0x4747C98E, 0xF0F00BFB,
612
- 0xADADEC41, 0xD4D467B3, 0xA2A2FD5F, 0xAFAFEA45, 0x9C9CBF23, 0xA4A4F753, 0x727296E4, 0xC0C05B9B,
613
- 0xB7B7C275, 0xFDFD1CE1, 0x9393AE3D, 0x26266A4C, 0x36365A6C, 0x3F3F417E, 0xF7F702F5, 0xCCCC4F83,
614
- 0x34345C68, 0xA5A5F451, 0xE5E534D1, 0xF1F108F9, 0x717193E2, 0xD8D873AB, 0x31315362, 0x15153F2A,
615
- 0x04040C08, 0xC7C75295, 0x23236546, 0xC3C35E9D, 0x18182830, 0x9696A137, 0x05050F0A, 0x9A9AB52F,
616
- 0x0707090E, 0x12123624, 0x80809B1B, 0xE2E23DDF, 0xEBEB26CD, 0x2727694E, 0xB2B2CD7F, 0x75759FEA,
617
- 0x09091B12, 0x83839E1D, 0x2C2C7458, 0x1A1A2E34, 0x1B1B2D36, 0x6E6EB2DC, 0x5A5AEEB4, 0xA0A0FB5B,
618
- 0x5252F6A4, 0x3B3B4D76, 0xD6D661B7, 0xB3B3CE7D, 0x29297B52, 0xE3E33EDD, 0x2F2F715E, 0x84849713,
619
- 0x5353F5A6, 0xD1D168B9, 0x00000000, 0xEDED2CC1, 0x20206040, 0xFCFC1FE3, 0xB1B1C879, 0x5B5BEDB6,
620
- 0x6A6ABED4, 0xCBCB468D, 0xBEBED967, 0x39394B72, 0x4A4ADE94, 0x4C4CD498, 0x5858E8B0, 0xCFCF4A85,
621
- 0xD0D06BBB, 0xEFEF2AC5, 0xAAAAE54F, 0xFBFB16ED, 0x4343C586, 0x4D4DD79A, 0x33335566, 0x85859411,
622
- 0x4545CF8A, 0xF9F910E9, 0x02020604, 0x7F7F81FE, 0x5050F0A0, 0x3C3C4478, 0x9F9FBA25, 0xA8A8E34B,
623
- 0x5151F3A2, 0xA3A3FE5D, 0x4040C080, 0x8F8F8A05, 0x9292AD3F, 0x9D9DBC21, 0x38384870, 0xF5F504F1,
624
- 0xBCBCDF63, 0xB6B6C177, 0xDADA75AF, 0x21216342, 0x10103020, 0xFFFF1AE5, 0xF3F30EFD, 0xD2D26DBF,
625
- 0xCDCD4C81, 0x0C0C1418, 0x13133526, 0xECEC2FC3, 0x5F5FE1BE, 0x9797A235, 0x4444CC88, 0x1717392E,
626
- 0xC4C45793, 0xA7A7F255, 0x7E7E82FC, 0x3D3D477A, 0x6464ACC8, 0x5D5DE7BA, 0x19192B32, 0x737395E6,
627
- 0x6060A0C0, 0x81819819, 0x4F4FD19E, 0xDCDC7FA3, 0x22226644, 0x2A2A7E54, 0x9090AB3B, 0x8888830B,
628
- 0x4646CA8C, 0xEEEE29C7, 0xB8B8D36B, 0x14143C28, 0xDEDE79A7, 0x5E5EE2BC, 0x0B0B1D16, 0xDBDB76AD,
629
- 0xE0E03BDB, 0x32325664, 0x3A3A4E74, 0x0A0A1E14, 0x4949DB92, 0x06060A0C, 0x24246C48, 0x5C5CE4B8,
630
- 0xC2C25D9F, 0xD3D36EBD, 0xACACEF43, 0x6262A6C4, 0x9191A839, 0x9595A431, 0xE4E437D3, 0x79798BF2,
631
- 0xE7E732D5, 0xC8C8438B, 0x3737596E, 0x6D6DB7DA, 0x8D8D8C01, 0xD5D564B1, 0x4E4ED29C, 0xA9A9E049,
632
- 0x6C6CB4D8, 0x5656FAAC, 0xF4F407F3, 0xEAEA25CF, 0x6565AFCA, 0x7A7A8EF4, 0xAEAEE947, 0x08081810,
633
- 0xBABAD56F, 0x787888F0, 0x25256F4A, 0x2E2E725C, 0x1C1C2438, 0xA6A6F157, 0xB4B4C773, 0xC6C65197,
634
- 0xE8E823CB, 0xDDDD7CA1, 0x74749CE8, 0x1F1F213E, 0x4B4BDD96, 0xBDBDDC61, 0x8B8B860D, 0x8A8A850F,
635
- 0x707090E0, 0x3E3E427C, 0xB5B5C471, 0x6666AACC, 0x4848D890, 0x03030506, 0xF6F601F7, 0x0E0E121C,
636
- 0x6161A3C2, 0x35355F6A, 0x5757F9AE, 0xB9B9D069, 0x86869117, 0xC1C15899, 0x1D1D273A, 0x9E9EB927,
637
- 0xE1E138D9, 0xF8F813EB, 0x9898B32B, 0x11113322, 0x6969BBD2, 0xD9D970A9, 0x8E8E8907, 0x9494A733,
638
- 0x9B9BB62D, 0x1E1E223C, 0x87879215, 0xE9E920C9, 0xCECE4987, 0x5555FFAA, 0x28287850, 0xDFDF7AA5,
639
- 0x8C8C8F03, 0xA1A1F859, 0x89898009, 0x0D0D171A, 0xBFBFDA65, 0xE6E631D7, 0x4242C684, 0x6868B8D0,
640
- 0x4141C382, 0x9999B029, 0x2D2D775A, 0x0F0F111E, 0xB0B0CB7B, 0x5454FCA8, 0xBBBBD66D, 0x16163A2C
641
- ));
642
-
643
- foreach ($t3 as $t3i) {
644
- $t0[] = (($t3i << 24) & 0xFF000000) | (($t3i >> 8) & 0x00FFFFFF);
645
- $t1[] = (($t3i << 16) & 0xFFFF0000) | (($t3i >> 16) & 0x0000FFFF);
646
- $t2[] = (($t3i << 8) & 0xFFFFFF00) | (($t3i >> 24) & 0x000000FF);
647
- }
648
-
649
- $tables = array(
650
- // The Precomputed mixColumns tables t0 - t3
651
- $t0,
652
- $t1,
653
- $t2,
654
- $t3,
655
- // The SubByte S-Box
656
- array(
657
- 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
658
- 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
659
- 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
660
- 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
661
- 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
662
- 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
663
- 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
664
- 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
665
- 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
666
- 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
667
- 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
668
- 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
669
- 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
670
- 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
671
- 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
672
- 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
673
- )
674
- );
675
- }
676
- return $tables;
677
- }
678
-
679
- /**
680
- * Provides the inverse mixColumns and inverse sboxes tables
681
- *
682
- * @see self::_decryptBlock()
683
- * @see self::_setupInlineCrypt()
684
- * @see self::_setupKey()
685
- * @access private
686
- * @return array &$tables
687
- */
688
- function &_getInvTables()
689
- {
690
- static $tables;
691
- if (empty($tables)) {
692
- $dt3 = array_map('intval', array(
693
- 0xF4A75051, 0x4165537E, 0x17A4C31A, 0x275E963A, 0xAB6BCB3B, 0x9D45F11F, 0xFA58ABAC, 0xE303934B,
694
- 0x30FA5520, 0x766DF6AD, 0xCC769188, 0x024C25F5, 0xE5D7FC4F, 0x2ACBD7C5, 0x35448026, 0x62A38FB5,
695
- 0xB15A49DE, 0xBA1B6725, 0xEA0E9845, 0xFEC0E15D, 0x2F7502C3, 0x4CF01281, 0x4697A38D, 0xD3F9C66B,
696
- 0x8F5FE703, 0x929C9515, 0x6D7AEBBF, 0x5259DA95, 0xBE832DD4, 0x7421D358, 0xE0692949, 0xC9C8448E,
697
- 0xC2896A75, 0x8E7978F4, 0x583E6B99, 0xB971DD27, 0xE14FB6BE, 0x88AD17F0, 0x20AC66C9, 0xCE3AB47D,
698
- 0xDF4A1863, 0x1A3182E5, 0x51336097, 0x537F4562, 0x6477E0B1, 0x6BAE84BB, 0x81A01CFE, 0x082B94F9,
699
- 0x48685870, 0x45FD198F, 0xDE6C8794, 0x7BF8B752, 0x73D323AB, 0x4B02E272, 0x1F8F57E3, 0x55AB2A66,
700
- 0xEB2807B2, 0xB5C2032F, 0xC57B9A86, 0x3708A5D3, 0x2887F230, 0xBFA5B223, 0x036ABA02, 0x16825CED,
701
- 0xCF1C2B8A, 0x79B492A7, 0x07F2F0F3, 0x69E2A14E, 0xDAF4CD65, 0x05BED506, 0x34621FD1, 0xA6FE8AC4,
702
- 0x2E539D34, 0xF355A0A2, 0x8AE13205, 0xF6EB75A4, 0x83EC390B, 0x60EFAA40, 0x719F065E, 0x6E1051BD,
703
- 0x218AF93E, 0xDD063D96, 0x3E05AEDD, 0xE6BD464D, 0x548DB591, 0xC45D0571, 0x06D46F04, 0x5015FF60,
704
- 0x98FB2419, 0xBDE997D6, 0x4043CC89, 0xD99E7767, 0xE842BDB0, 0x898B8807, 0x195B38E7, 0xC8EEDB79,
705
- 0x7C0A47A1, 0x420FE97C, 0x841EC9F8, 0x00000000, 0x80868309, 0x2BED4832, 0x1170AC1E, 0x5A724E6C,
706
- 0x0EFFFBFD, 0x8538560F, 0xAED51E3D, 0x2D392736, 0x0FD9640A, 0x5CA62168, 0x5B54D19B, 0x362E3A24,
707
- 0x0A67B10C, 0x57E70F93, 0xEE96D2B4, 0x9B919E1B, 0xC0C54F80, 0xDC20A261, 0x774B695A, 0x121A161C,
708
- 0x93BA0AE2, 0xA02AE5C0, 0x22E0433C, 0x1B171D12, 0x090D0B0E, 0x8BC7ADF2, 0xB6A8B92D, 0x1EA9C814,
709
- 0xF1198557, 0x75074CAF, 0x99DDBBEE, 0x7F60FDA3, 0x01269FF7, 0x72F5BC5C, 0x663BC544, 0xFB7E345B,
710
- 0x4329768B, 0x23C6DCCB, 0xEDFC68B6, 0xE4F163B8, 0x31DCCAD7, 0x63851042, 0x97224013, 0xC6112084,
711
- 0x4A247D85, 0xBB3DF8D2, 0xF93211AE, 0x29A16DC7, 0x9E2F4B1D, 0xB230F3DC, 0x8652EC0D, 0xC1E3D077,
712
- 0xB3166C2B, 0x70B999A9, 0x9448FA11, 0xE9642247, 0xFC8CC4A8, 0xF03F1AA0, 0x7D2CD856, 0x3390EF22,
713
- 0x494EC787, 0x38D1C1D9, 0xCAA2FE8C, 0xD40B3698, 0xF581CFA6, 0x7ADE28A5, 0xB78E26DA, 0xADBFA43F,
714
- 0x3A9DE42C, 0x78920D50, 0x5FCC9B6A, 0x7E466254, 0x8D13C2F6, 0xD8B8E890, 0x39F75E2E, 0xC3AFF582,
715
- 0x5D80BE9F, 0xD0937C69, 0xD52DA96F, 0x2512B3CF, 0xAC993BC8, 0x187DA710, 0x9C636EE8, 0x3BBB7BDB,
716
- 0x267809CD, 0x5918F46E, 0x9AB701EC, 0x4F9AA883, 0x956E65E6, 0xFFE67EAA, 0xBCCF0821, 0x15E8E6EF,
717
- 0xE79BD9BA, 0x6F36CE4A, 0x9F09D4EA, 0xB07CD629, 0xA4B2AF31, 0x3F23312A, 0xA59430C6, 0xA266C035,
718
- 0x4EBC3774, 0x82CAA6FC, 0x90D0B0E0, 0xA7D81533, 0x04984AF1, 0xECDAF741, 0xCD500E7F, 0x91F62F17,
719
- 0x4DD68D76, 0xEFB04D43, 0xAA4D54CC, 0x9604DFE4, 0xD1B5E39E, 0x6A881B4C, 0x2C1FB8C1, 0x65517F46,
720
- 0x5EEA049D, 0x8C355D01, 0x877473FA, 0x0B412EFB, 0x671D5AB3, 0xDBD25292, 0x105633E9, 0xD647136D,
721
- 0xD7618C9A, 0xA10C7A37, 0xF8148E59, 0x133C89EB, 0xA927EECE, 0x61C935B7, 0x1CE5EDE1, 0x47B13C7A,
722
- 0xD2DF599C, 0xF2733F55, 0x14CE7918, 0xC737BF73, 0xF7CDEA53, 0xFDAA5B5F, 0x3D6F14DF, 0x44DB8678,
723
- 0xAFF381CA, 0x68C43EB9, 0x24342C38, 0xA3405FC2, 0x1DC37216, 0xE2250CBC, 0x3C498B28, 0x0D9541FF,
724
- 0xA8017139, 0x0CB3DE08, 0xB4E49CD8, 0x56C19064, 0xCB84617B, 0x32B670D5, 0x6C5C7448, 0xB85742D0
725
- ));
726
-
727
- foreach ($dt3 as $dt3i) {
728
- $dt0[] = (($dt3i << 24) & 0xFF000000) | (($dt3i >> 8) & 0x00FFFFFF);
729
- $dt1[] = (($dt3i << 16) & 0xFFFF0000) | (($dt3i >> 16) & 0x0000FFFF);
730
- $dt2[] = (($dt3i << 8) & 0xFFFFFF00) | (($dt3i >> 24) & 0x000000FF);
731
- };
732
-
733
- $tables = array(
734
- // The Precomputed inverse mixColumns tables dt0 - dt3
735
- $dt0,
736
- $dt1,
737
- $dt2,
738
- $dt3,
739
- // The inverse SubByte S-Box
740
- array(
741
- 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB,
742
- 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB,
743
- 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
744
- 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25,
745
- 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92,
746
- 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
747
- 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06,
748
- 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B,
749
- 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
750
- 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E,
751
- 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B,
752
- 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
753
- 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F,
754
- 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF,
755
- 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
756
- 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D
757
- )
758
- );
759
- }
760
- return $tables;
761
- }
762
-
763
- /**
764
- * Setup the performance-optimized function for de/encrypt()
765
- *
766
- * @see \phpseclib\Crypt\Base::_setupInlineCrypt()
767
- * @access private
768
- */
769
- function _setupInlineCrypt()
770
- {
771
- // Note: _setupInlineCrypt() will be called only if $this->changed === true
772
- // So here we are'nt under the same heavy timing-stress as we are in _de/encryptBlock() or de/encrypt().
773
- // However...the here generated function- $code, stored as php callback in $this->inline_crypt, must work as fast as even possible.
774
-
775
- $lambda_functions =& self::_getLambdaFunctions();
776
-
777
- // We create max. 10 hi-optimized code for memory reason. Means: For each $key one ultra fast inline-crypt function.
778
- // (Currently, for Crypt_Rijndael/AES, one generated $lambda_function cost on php5.5@32bit ~80kb unfreeable mem and ~130kb on php5.5@64bit)
779
- // After that, we'll still create very fast optimized code but not the hi-ultimative code, for each $mode one.
780
- $gen_hi_opt_code = (bool)(count($lambda_functions) < 10);
781
-
782
- // Generation of a uniqe hash for our generated code
783
- $code_hash = "Crypt_Rijndael, {$this->mode}, {$this->Nr}, {$this->Nb}";
784
- if ($gen_hi_opt_code) {
785
- $code_hash = str_pad($code_hash, 32) . $this->_hashInlineCryptFunction($this->key);
786
- }
787
-
788
- if (!isset($lambda_functions[$code_hash])) {
789
- switch (true) {
790
- case $gen_hi_opt_code:
791
- // The hi-optimized $lambda_functions will use the key-words hardcoded for better performance.
792
- $w = $this->w;
793
- $dw = $this->dw;
794
- $init_encrypt = '';
795
- $init_decrypt = '';
796
- break;
797
- default:
798
- for ($i = 0, $cw = count($this->w); $i < $cw; ++$i) {
799
- $w[] = '$w[' . $i . ']';
800
- $dw[] = '$dw[' . $i . ']';
801
- }
802
- $init_encrypt = '$w = $self->w;';
803
- $init_decrypt = '$dw = $self->dw;';
804
- }
805
-
806
- $Nr = $this->Nr;
807
- $Nb = $this->Nb;
808
- $c = $this->c;
809
-
810
- // Generating encrypt code:
811
- $init_encrypt.= '
812
- static $tables;
813
- if (empty($tables)) {
814
- $tables = &$self->_getTables();
815
- }
816
- $t0 = $tables[0];
817
- $t1 = $tables[1];
818
- $t2 = $tables[2];
819
- $t3 = $tables[3];
820
- $sbox = $tables[4];
821
- ';
822
-
823
- $s = 'e';
824
- $e = 's';
825
- $wc = $Nb - 1;
826
-
827
- // Preround: addRoundKey
828
- $encrypt_block = '$in = unpack("N*", $in);'."\n";
829
- for ($i = 0; $i < $Nb; ++$i) {
830
- $encrypt_block .= '$s'.$i.' = $in['.($i + 1).'] ^ '.$w[++$wc].";\n";
831
- }
832
-
833
- // Mainrounds: shiftRows + subWord + mixColumns + addRoundKey
834
- for ($round = 1; $round < $Nr; ++$round) {
835
- list($s, $e) = array($e, $s);
836
- for ($i = 0; $i < $Nb; ++$i) {
837
- $encrypt_block.=
838
- '$'.$e.$i.' =
839
- $t0[($'.$s.$i .' >> 24) & 0xff] ^
840
- $t1[($'.$s.(($i + $c[1]) % $Nb).' >> 16) & 0xff] ^
841
- $t2[($'.$s.(($i + $c[2]) % $Nb).' >> 8) & 0xff] ^
842
- $t3[ $'.$s.(($i + $c[3]) % $Nb).' & 0xff] ^
843
- '.$w[++$wc].";\n";
844
- }
845
- }
846
-
847
- // Finalround: subWord + shiftRows + addRoundKey
848
- for ($i = 0; $i < $Nb; ++$i) {
849
- $encrypt_block.=
850
- '$'.$e.$i.' =
851
- $sbox[ $'.$e.$i.' & 0xff] |
852
- ($sbox[($'.$e.$i.' >> 8) & 0xff] << 8) |
853
- ($sbox[($'.$e.$i.' >> 16) & 0xff] << 16) |
854
- ($sbox[($'.$e.$i.' >> 24) & 0xff] << 24);'."\n";
855
- }
856
- $encrypt_block .= '$in = pack("N*"'."\n";
857
- for ($i = 0; $i < $Nb; ++$i) {
858
- $encrypt_block.= ',
859
- ($'.$e.$i .' & '.((int)0xFF000000).') ^
860
- ($'.$e.(($i + $c[1]) % $Nb).' & 0x00FF0000 ) ^
861
- ($'.$e.(($i + $c[2]) % $Nb).' & 0x0000FF00 ) ^
862
- ($'.$e.(($i + $c[3]) % $Nb).' & 0x000000FF ) ^
863
- '.$w[$i]."\n";
864
- }
865
- $encrypt_block .= ');';
866
-
867
- // Generating decrypt code:
868
- $init_decrypt.= '
869
- static $invtables;
870
- if (empty($invtables)) {
871
- $invtables = &$self->_getInvTables();
872
- }
873
- $dt0 = $invtables[0];
874
- $dt1 = $invtables[1];
875
- $dt2 = $invtables[2];
876
- $dt3 = $invtables[3];
877
- $isbox = $invtables[4];
878
- ';
879
-
880
- $s = 'e';
881
- $e = 's';
882
- $wc = $Nb - 1;
883
-
884
- // Preround: addRoundKey
885
- $decrypt_block = '$in = unpack("N*", $in);'."\n";
886
- for ($i = 0; $i < $Nb; ++$i) {
887
- $decrypt_block .= '$s'.$i.' = $in['.($i + 1).'] ^ '.$dw[++$wc].';'."\n";
888
- }
889
-
890
- // Mainrounds: shiftRows + subWord + mixColumns + addRoundKey
891
- for ($round = 1; $round < $Nr; ++$round) {
892
- list($s, $e) = array($e, $s);
893
- for ($i = 0; $i < $Nb; ++$i) {
894
- $decrypt_block.=
895
- '$'.$e.$i.' =
896
- $dt0[($'.$s.$i .' >> 24) & 0xff] ^
897
- $dt1[($'.$s.(($Nb + $i - $c[1]) % $Nb).' >> 16) & 0xff] ^
898
- $dt2[($'.$s.(($Nb + $i - $c[2]) % $Nb).' >> 8) & 0xff] ^
899
- $dt3[ $'.$s.(($Nb + $i - $c[3]) % $Nb).' & 0xff] ^
900
- '.$dw[++$wc].";\n";
901
- }
902
- }
903
-
904
- // Finalround: subWord + shiftRows + addRoundKey
905
- for ($i = 0; $i < $Nb; ++$i) {
906
- $decrypt_block.=
907
- '$'.$e.$i.' =
908
- $isbox[ $'.$e.$i.' & 0xff] |
909
- ($isbox[($'.$e.$i.' >> 8) & 0xff] << 8) |
910
- ($isbox[($'.$e.$i.' >> 16) & 0xff] << 16) |
911
- ($isbox[($'.$e.$i.' >> 24) & 0xff] << 24);'."\n";
912
- }
913
- $decrypt_block .= '$in = pack("N*"'."\n";
914
- for ($i = 0; $i < $Nb; ++$i) {
915
- $decrypt_block.= ',
916
- ($'.$e.$i. ' & '.((int)0xFF000000).') ^
917
- ($'.$e.(($Nb + $i - $c[1]) % $Nb).' & 0x00FF0000 ) ^
918
- ($'.$e.(($Nb + $i - $c[2]) % $Nb).' & 0x0000FF00 ) ^
919
- ($'.$e.(($Nb + $i - $c[3]) % $Nb).' & 0x000000FF ) ^
920
- '.$dw[$i]."\n";
921
- }
922
- $decrypt_block .= ');';
923
-
924
- $lambda_functions[$code_hash] = $this->_createInlineCryptFunction(
925
- array(
926
- 'init_crypt' => '',
927
- 'init_encrypt' => $init_encrypt,
928
- 'init_decrypt' => $init_decrypt,
929
- 'encrypt_block' => $encrypt_block,
930
- 'decrypt_block' => $decrypt_block
931
- )
932
- );
933
- }
934
- $this->inline_crypt = $lambda_functions[$code_hash];
935
- }
936
- }
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 version 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 'vendor/autoload.php';
32
+ *
33
+ * $rijndael = new \phpseclib\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
+ * @category Crypt
48
+ * @package Rijndael
49
+ * @author Jim Wigginton <terrafrost@php.net>
50
+ * @copyright 2008 Jim Wigginton
51
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
52
+ * @link http://phpseclib.sourceforge.net
53
+ */
54
+
55
+ namespace phpseclib\Crypt;
56
+
57
+ /**
58
+ * Pure-PHP implementation of Rijndael.
59
+ *
60
+ * @package Rijndael
61
+ * @author Jim Wigginton <terrafrost@php.net>
62
+ * @access public
63
+ */
64
+ class Rijndael extends Base
65
+ {
66
+ /**
67
+ * The mcrypt specific name of the cipher
68
+ *
69
+ * Mcrypt is useable for 128/192/256-bit $block_size/$key_length. For 160/224 not.
70
+ * \phpseclib\Crypt\Rijndael determines automatically whether mcrypt is useable
71
+ * or not for the current $block_size/$key_length.
72
+ * In case of, $cipher_name_mcrypt will be set dynamically at run time accordingly.
73
+ *
74
+ * @see \phpseclib\Crypt\Base::cipher_name_mcrypt
75
+ * @see \phpseclib\Crypt\Base::engine
76
+ * @see self::isValidEngine()
77
+ * @var string
78
+ * @access private
79
+ */
80
+ var $cipher_name_mcrypt = 'rijndael-128';
81
+
82
+ /**
83
+ * The default salt used by setPassword()
84
+ *
85
+ * @see \phpseclib\Crypt\Base::password_default_salt
86
+ * @see \phpseclib\Crypt\Base::setPassword()
87
+ * @var string
88
+ * @access private
89
+ */
90
+ var $password_default_salt = 'phpseclib';
91
+
92
+ /**
93
+ * The Key Schedule
94
+ *
95
+ * @see self::_setup()
96
+ * @var array
97
+ * @access private
98
+ */
99
+ var $w;
100
+
101
+ /**
102
+ * The Inverse Key Schedule
103
+ *
104
+ * @see self::_setup()
105
+ * @var array
106
+ * @access private
107
+ */
108
+ var $dw;
109
+
110
+ /**
111
+ * The Block Length divided by 32
112
+ *
113
+ * @see self::setBlockLength()
114
+ * @var int
115
+ * @access private
116
+ * @internal The max value is 256 / 32 = 8, the min value is 128 / 32 = 4. Exists in conjunction with $block_size
117
+ * because the encryption / decryption / key schedule creation requires this number and not $block_size. We could
118
+ * derive this from $block_size or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu
119
+ * of that, we'll just precompute it once.
120
+ */
121
+ var $Nb = 4;
122
+
123
+ /**
124
+ * The Key Length (in bytes)
125
+ *
126
+ * @see self::setKeyLength()
127
+ * @var int
128
+ * @access private
129
+ * @internal The max value is 256 / 8 = 32, the min value is 128 / 8 = 16. Exists in conjunction with $Nk
130
+ * because the encryption / decryption / key schedule creation requires this number and not $key_length. We could
131
+ * derive this from $key_length or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu
132
+ * of that, we'll just precompute it once.
133
+ */
134
+ var $key_length = 16;
135
+
136
+ /**
137
+ * The Key Length divided by 32
138
+ *
139
+ * @see self::setKeyLength()
140
+ * @var int
141
+ * @access private
142
+ * @internal The max value is 256 / 32 = 8, the min value is 128 / 32 = 4
143
+ */
144
+ var $Nk = 4;
145
+
146
+ /**
147
+ * The Number of Rounds
148
+ *
149
+ * @var int
150
+ * @access private
151
+ * @internal The max value is 14, the min value is 10.
152
+ */
153
+ var $Nr;
154
+
155
+ /**
156
+ * Shift offsets
157
+ *
158
+ * @var array
159
+ * @access private
160
+ */
161
+ var $c;
162
+
163
+ /**
164
+ * Holds the last used key- and block_size information
165
+ *
166
+ * @var array
167
+ * @access private
168
+ */
169
+ var $kl;
170
+
171
+ /**
172
+ * Sets the key length.
173
+ *
174
+ * Valid key lengths are 128, 160, 192, 224, and 256. If the length is less than 128, it will be rounded up to
175
+ * 128. If the length is greater than 128 and invalid, it will be rounded down to the closest valid amount.
176
+ *
177
+ * Note: phpseclib extends Rijndael (and AES) for using 160- and 224-bit keys but they are officially not defined
178
+ * and the most (if not all) implementations are not able using 160/224-bit keys but round/pad them up to
179
+ * 192/256 bits as, for example, mcrypt will do.
180
+ *
181
+ * That said, if you want be compatible with other Rijndael and AES implementations,
182
+ * you should not setKeyLength(160) or setKeyLength(224).
183
+ *
184
+ * Additional: In case of 160- and 224-bit keys, phpseclib will/can, for that reason, not use
185
+ * the mcrypt php extension, even if available.
186
+ * This results then in slower encryption.
187
+ *
188
+ * @access public
189
+ * @param int $length
190
+ */
191
+ function setKeyLength($length)
192
+ {
193
+ switch (true) {
194
+ case $length <= 128:
195
+ $this->key_length = 16;
196
+ break;
197
+ case $length <= 160:
198
+ $this->key_length = 20;
199
+ break;
200
+ case $length <= 192:
201
+ $this->key_length = 24;
202
+ break;
203
+ case $length <= 224:
204
+ $this->key_length = 28;
205
+ break;
206
+ default:
207
+ $this->key_length = 32;
208
+ }
209
+
210
+ parent::setKeyLength($length);
211
+ }
212
+
213
+ /**
214
+ * Sets the block length
215
+ *
216
+ * Valid block lengths are 128, 160, 192, 224, and 256. If the length is less than 128, it will be rounded up to
217
+ * 128. If the length is greater than 128 and invalid, it will be rounded down to the closest valid amount.
218
+ *
219
+ * @access public
220
+ * @param int $length
221
+ */
222
+ function setBlockLength($length)
223
+ {
224
+ $length >>= 5;
225
+ if ($length > 8) {
226
+ $length = 8;
227
+ } elseif ($length < 4) {
228
+ $length = 4;
229
+ }
230
+ $this->Nb = $length;
231
+ $this->block_size = $length << 2;
232
+ $this->changed = true;
233
+ $this->_setEngine();
234
+ }
235
+
236
+ /**
237
+ * Test for engine validity
238
+ *
239
+ * This is mainly just a wrapper to set things up for \phpseclib\Crypt\Base::isValidEngine()
240
+ *
241
+ * @see \phpseclib\Crypt\Base::__construct()
242
+ * @param int $engine
243
+ * @access public
244
+ * @return bool
245
+ */
246
+ function isValidEngine($engine)
247
+ {
248
+ switch ($engine) {
249
+ case self::ENGINE_OPENSSL:
250
+ if ($this->block_size != 16) {
251
+ return false;
252
+ }
253
+ $this->cipher_name_openssl_ecb = 'aes-' . ($this->key_length << 3) . '-ecb';
254
+ $this->cipher_name_openssl = 'aes-' . ($this->key_length << 3) . '-' . $this->_openssl_translate_mode();
255
+ break;
256
+ case self::ENGINE_MCRYPT:
257
+ $this->cipher_name_mcrypt = 'rijndael-' . ($this->block_size << 3);
258
+ if ($this->key_length % 8) { // is it a 160/224-bit key?
259
+ // mcrypt is not usable for them, only for 128/192/256-bit keys
260
+ return false;
261
+ }
262
+ }
263
+
264
+ return parent::isValidEngine($engine);
265
+ }
266
+
267
+ /**
268
+ * Encrypts a block
269
+ *
270
+ * @access private
271
+ * @param string $in
272
+ * @return string
273
+ */
274
+ function _encryptBlock($in)
275
+ {
276
+ static $tables;
277
+ if (empty($tables)) {
278
+ $tables = &$this->_getTables();
279
+ }
280
+ $t0 = $tables[0];
281
+ $t1 = $tables[1];
282
+ $t2 = $tables[2];
283
+ $t3 = $tables[3];
284
+ $sbox = $tables[4];
285
+
286
+ $state = array();
287
+ $words = unpack('N*', $in);
288
+
289
+ $c = $this->c;
290
+ $w = $this->w;
291
+ $Nb = $this->Nb;
292
+ $Nr = $this->Nr;
293
+
294
+ // addRoundKey
295
+ $wc = $Nb - 1;
296
+ foreach ($words as $word) {
297
+ $state[] = $word ^ $w[++$wc];
298
+ }
299
+
300
+ // fips-197.pdf#page=19, "Figure 5. Pseudo Code for the Cipher", states that this loop has four components -
301
+ // subBytes, shiftRows, mixColumns, and addRoundKey. fips-197.pdf#page=30, "Implementation Suggestions Regarding
302
+ // Various Platforms" suggests that performs enhanced implementations are described in Rijndael-ammended.pdf.
303
+ // Rijndael-ammended.pdf#page=20, "Implementation aspects / 32-bit processor", discusses such an optimization.
304
+ // Unfortunately, the description given there is not quite correct. Per aes.spec.v316.pdf#page=19 [1],
305
+ // equation (7.4.7) is supposed to use addition instead of subtraction, so we'll do that here, as well.
306
+
307
+ // [1] http://fp.gladman.plus.com/cryptography_technology/rijndael/aes.spec.v316.pdf
308
+ $temp = array();
309
+ for ($round = 1; $round < $Nr; ++$round) {
310
+ $i = 0; // $c[0] == 0
311
+ $j = $c[1];
312
+ $k = $c[2];
313
+ $l = $c[3];
314
+
315
+ while ($i < $Nb) {
316
+ $temp[$i] = $t0[$state[$i] >> 24 & 0x000000FF] ^
317
+ $t1[$state[$j] >> 16 & 0x000000FF] ^
318
+ $t2[$state[$k] >> 8 & 0x000000FF] ^
319
+ $t3[$state[$l] & 0x000000FF] ^
320
+ $w[++$wc];
321
+ ++$i;
322
+ $j = ($j + 1) % $Nb;
323
+ $k = ($k + 1) % $Nb;
324
+ $l = ($l + 1) % $Nb;
325
+ }
326
+ $state = $temp;
327
+ }
328
+
329
+ // subWord
330
+ for ($i = 0; $i < $Nb; ++$i) {
331
+ $state[$i] = $sbox[$state[$i] & 0x000000FF] |
332
+ ($sbox[$state[$i] >> 8 & 0x000000FF] << 8) |
333
+ ($sbox[$state[$i] >> 16 & 0x000000FF] << 16) |
334
+ ($sbox[$state[$i] >> 24 & 0x000000FF] << 24);
335
+ }
336
+
337
+ // shiftRows + addRoundKey
338
+ $i = 0; // $c[0] == 0
339
+ $j = $c[1];
340
+ $k = $c[2];
341
+ $l = $c[3];
342
+ while ($i < $Nb) {
343
+ $temp[$i] = ($state[$i] & 0xFF000000) ^
344
+ ($state[$j] & 0x00FF0000) ^
345
+ ($state[$k] & 0x0000FF00) ^
346
+ ($state[$l] & 0x000000FF) ^
347
+ $w[$i];
348
+ ++$i;
349
+ $j = ($j + 1) % $Nb;
350
+ $k = ($k + 1) % $Nb;
351
+ $l = ($l + 1) % $Nb;
352
+ }
353
+
354
+ switch ($Nb) {
355
+ case 8:
356
+ return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6], $temp[7]);
357
+ case 7:
358
+ return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6]);
359
+ case 6:
360
+ return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5]);
361
+ case 5:
362
+ return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4]);
363
+ default:
364
+ return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3]);
365
+ }
366
+ }
367
+
368
+ /**
369
+ * Decrypts a block
370
+ *
371
+ * @access private
372
+ * @param string $in
373
+ * @return string
374
+ */
375
+ function _decryptBlock($in)
376
+ {
377
+ static $invtables;
378
+ if (empty($invtables)) {
379
+ $invtables = &$this->_getInvTables();
380
+ }
381
+ $dt0 = $invtables[0];
382
+ $dt1 = $invtables[1];
383
+ $dt2 = $invtables[2];
384
+ $dt3 = $invtables[3];
385
+ $isbox = $invtables[4];
386
+
387
+ $state = array();
388
+ $words = unpack('N*', $in);
389
+
390
+ $c = $this->c;
391
+ $dw = $this->dw;
392
+ $Nb = $this->Nb;
393
+ $Nr = $this->Nr;
394
+
395
+ // addRoundKey
396
+ $wc = $Nb - 1;
397
+ foreach ($words as $word) {
398
+ $state[] = $word ^ $dw[++$wc];
399
+ }
400
+
401
+ $temp = array();
402
+ for ($round = $Nr - 1; $round > 0; --$round) {
403
+ $i = 0; // $c[0] == 0
404
+ $j = $Nb - $c[1];
405
+ $k = $Nb - $c[2];
406
+ $l = $Nb - $c[3];
407
+
408
+ while ($i < $Nb) {
409
+ $temp[$i] = $dt0[$state[$i] >> 24 & 0x000000FF] ^
410
+ $dt1[$state[$j] >> 16 & 0x000000FF] ^
411
+ $dt2[$state[$k] >> 8 & 0x000000FF] ^
412
+ $dt3[$state[$l] & 0x000000FF] ^
413
+ $dw[++$wc];
414
+ ++$i;
415
+ $j = ($j + 1) % $Nb;
416
+ $k = ($k + 1) % $Nb;
417
+ $l = ($l + 1) % $Nb;
418
+ }
419
+ $state = $temp;
420
+ }
421
+
422
+ // invShiftRows + invSubWord + addRoundKey
423
+ $i = 0; // $c[0] == 0
424
+ $j = $Nb - $c[1];
425
+ $k = $Nb - $c[2];
426
+ $l = $Nb - $c[3];
427
+
428
+ while ($i < $Nb) {
429
+ $word = ($state[$i] & 0xFF000000) |
430
+ ($state[$j] & 0x00FF0000) |
431
+ ($state[$k] & 0x0000FF00) |
432
+ ($state[$l] & 0x000000FF);
433
+
434
+ $temp[$i] = $dw[$i] ^ ($isbox[$word & 0x000000FF] |
435
+ ($isbox[$word >> 8 & 0x000000FF] << 8) |
436
+ ($isbox[$word >> 16 & 0x000000FF] << 16) |
437
+ ($isbox[$word >> 24 & 0x000000FF] << 24));
438
+ ++$i;
439
+ $j = ($j + 1) % $Nb;
440
+ $k = ($k + 1) % $Nb;
441
+ $l = ($l + 1) % $Nb;
442
+ }
443
+
444
+ switch ($Nb) {
445
+ case 8:
446
+ return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6], $temp[7]);
447
+ case 7:
448
+ return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6]);
449
+ case 6:
450
+ return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5]);
451
+ case 5:
452
+ return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4]);
453
+ default:
454
+ return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3]);
455
+ }
456
+ }
457
+
458
+ /**
459
+ * Setup the key (expansion)
460
+ *
461
+ * @see \phpseclib\Crypt\Base::_setupKey()
462
+ * @access private
463
+ */
464
+ function _setupKey()
465
+ {
466
+ // Each number in $rcon is equal to the previous number multiplied by two in Rijndael's finite field.
467
+ // See http://en.wikipedia.org/wiki/Finite_field_arithmetic#Multiplicative_inverse
468
+ static $rcon = array(0,
469
+ 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000,
470
+ 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000,
471
+ 0x6C000000, 0xD8000000, 0xAB000000, 0x4D000000, 0x9A000000,
472
+ 0x2F000000, 0x5E000000, 0xBC000000, 0x63000000, 0xC6000000,
473
+ 0x97000000, 0x35000000, 0x6A000000, 0xD4000000, 0xB3000000,
474
+ 0x7D000000, 0xFA000000, 0xEF000000, 0xC5000000, 0x91000000
475
+ );
476
+
477
+ if (isset($this->kl['key']) && $this->key === $this->kl['key'] && $this->key_length === $this->kl['key_length'] && $this->block_size === $this->kl['block_size']) {
478
+ // already expanded
479
+ return;
480
+ }
481
+ $this->kl = array('key' => $this->key, 'key_length' => $this->key_length, 'block_size' => $this->block_size);
482
+
483
+ $this->Nk = $this->key_length >> 2;
484
+ // see Rijndael-ammended.pdf#page=44
485
+ $this->Nr = max($this->Nk, $this->Nb) + 6;
486
+
487
+ // shift offsets for Nb = 5, 7 are defined in Rijndael-ammended.pdf#page=44,
488
+ // "Table 8: Shift offsets in Shiftrow for the alternative block lengths"
489
+ // shift offsets for Nb = 4, 6, 8 are defined in Rijndael-ammended.pdf#page=14,
490
+ // "Table 2: Shift offsets for different block lengths"
491
+ switch ($this->Nb) {
492
+ case 4:
493
+ case 5:
494
+ case 6:
495
+ $this->c = array(0, 1, 2, 3);
496
+ break;
497
+ case 7:
498
+ $this->c = array(0, 1, 2, 4);
499
+ break;
500
+ case 8:
501
+ $this->c = array(0, 1, 3, 4);
502
+ }
503
+
504
+ $w = array_values(unpack('N*words', $this->key));
505
+
506
+ $length = $this->Nb * ($this->Nr + 1);
507
+ for ($i = $this->Nk; $i < $length; $i++) {
508
+ $temp = $w[$i - 1];
509
+ if ($i % $this->Nk == 0) {
510
+ // according to <http://php.net/language.types.integer>, "the size of an integer is platform-dependent".
511
+ // on a 32-bit machine, it's 32-bits, and on a 64-bit machine, it's 64-bits. on a 32-bit machine,
512
+ // 0xFFFFFFFF << 8 == 0xFFFFFF00, but on a 64-bit machine, it equals 0xFFFFFFFF00. as such, doing 'and'
513
+ // with 0xFFFFFFFF (or 0xFFFFFF00) on a 32-bit machine is unnecessary, but on a 64-bit machine, it is.
514
+ $temp = (($temp << 8) & 0xFFFFFF00) | (($temp >> 24) & 0x000000FF); // rotWord
515
+ $temp = $this->_subWord($temp) ^ $rcon[$i / $this->Nk];
516
+ } elseif ($this->Nk > 6 && $i % $this->Nk == 4) {
517
+ $temp = $this->_subWord($temp);
518
+ }
519
+ $w[$i] = $w[$i - $this->Nk] ^ $temp;
520
+ }
521
+
522
+ // convert the key schedule from a vector of $Nb * ($Nr + 1) length to a matrix with $Nr + 1 rows and $Nb columns
523
+ // and generate the inverse key schedule. more specifically,
524
+ // according to <http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=23> (section 5.3.3),
525
+ // "The key expansion for the Inverse Cipher is defined as follows:
526
+ // 1. Apply the Key Expansion.
527
+ // 2. Apply InvMixColumn to all Round Keys except the first and the last one."
528
+ // also, see fips-197.pdf#page=27, "5.3.5 Equivalent Inverse Cipher"
529
+ list($dt0, $dt1, $dt2, $dt3) = $this->_getInvTables();
530
+ $temp = $this->w = $this->dw = array();
531
+ for ($i = $row = $col = 0; $i < $length; $i++, $col++) {
532
+ if ($col == $this->Nb) {
533
+ if ($row == 0) {
534
+ $this->dw[0] = $this->w[0];
535
+ } else {
536
+ // subWord + invMixColumn + invSubWord = invMixColumn
537
+ $j = 0;
538
+ while ($j < $this->Nb) {
539
+ $dw = $this->_subWord($this->w[$row][$j]);
540
+ $temp[$j] = $dt0[$dw >> 24 & 0x000000FF] ^
541
+ $dt1[$dw >> 16 & 0x000000FF] ^
542
+ $dt2[$dw >> 8 & 0x000000FF] ^
543
+ $dt3[$dw & 0x000000FF];
544
+ $j++;
545
+ }
546
+ $this->dw[$row] = $temp;
547
+ }
548
+
549
+ $col = 0;
550
+ $row++;
551
+ }
552
+ $this->w[$row][$col] = $w[$i];
553
+ }
554
+
555
+ $this->dw[$row] = $this->w[$row];
556
+
557
+ // Converting to 1-dim key arrays (both ascending)
558
+ $this->dw = array_reverse($this->dw);
559
+ $w = array_pop($this->w);
560
+ $dw = array_pop($this->dw);
561
+ foreach ($this->w as $r => $wr) {
562
+ foreach ($wr as $c => $wc) {
563
+ $w[] = $wc;
564
+ $dw[] = $this->dw[$r][$c];
565
+ }
566
+ }
567
+ $this->w = $w;
568
+ $this->dw = $dw;
569
+ }
570
+
571
+ /**
572
+ * Performs S-Box substitutions
573
+ *
574
+ * @access private
575
+ * @param int $word
576
+ */
577
+ function _subWord($word)
578
+ {
579
+ static $sbox;
580
+ if (empty($sbox)) {
581
+ list(, , , , $sbox) = $this->_getTables();
582
+ }
583
+
584
+ return $sbox[$word & 0x000000FF] |
585
+ ($sbox[$word >> 8 & 0x000000FF] << 8) |
586
+ ($sbox[$word >> 16 & 0x000000FF] << 16) |
587
+ ($sbox[$word >> 24 & 0x000000FF] << 24);
588
+ }
589
+
590
+ /**
591
+ * Provides the mixColumns and sboxes tables
592
+ *
593
+ * @see self::_encryptBlock()
594
+ * @see self::_setupInlineCrypt()
595
+ * @see self::_subWord()
596
+ * @access private
597
+ * @return array &$tables
598
+ */
599
+ function &_getTables()
600
+ {
601
+ static $tables;
602
+ if (empty($tables)) {
603
+ // according to <http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=19> (section 5.2.1),
604
+ // precomputed tables can be used in the mixColumns phase. in that example, they're assigned t0...t3, so
605
+ // those are the names we'll use.
606
+ $t3 = array_map('intval', array(
607
+ // with array_map('intval', ...) we ensure we have only int's and not
608
+ // some slower floats converted by php automatically on high values
609
+ 0x6363A5C6, 0x7C7C84F8, 0x777799EE, 0x7B7B8DF6, 0xF2F20DFF, 0x6B6BBDD6, 0x6F6FB1DE, 0xC5C55491,
610
+ 0x30305060, 0x01010302, 0x6767A9CE, 0x2B2B7D56, 0xFEFE19E7, 0xD7D762B5, 0xABABE64D, 0x76769AEC,
611
+ 0xCACA458F, 0x82829D1F, 0xC9C94089, 0x7D7D87FA, 0xFAFA15EF, 0x5959EBB2, 0x4747C98E, 0xF0F00BFB,
612
+ 0xADADEC41, 0xD4D467B3, 0xA2A2FD5F, 0xAFAFEA45, 0x9C9CBF23, 0xA4A4F753, 0x727296E4, 0xC0C05B9B,
613
+ 0xB7B7C275, 0xFDFD1CE1, 0x9393AE3D, 0x26266A4C, 0x36365A6C, 0x3F3F417E, 0xF7F702F5, 0xCCCC4F83,
614
+ 0x34345C68, 0xA5A5F451, 0xE5E534D1, 0xF1F108F9, 0x717193E2, 0xD8D873AB, 0x31315362, 0x15153F2A,
615
+ 0x04040C08, 0xC7C75295, 0x23236546, 0xC3C35E9D, 0x18182830, 0x9696A137, 0x05050F0A, 0x9A9AB52F,
616
+ 0x0707090E, 0x12123624, 0x80809B1B, 0xE2E23DDF, 0xEBEB26CD, 0x2727694E, 0xB2B2CD7F, 0x75759FEA,
617
+ 0x09091B12, 0x83839E1D, 0x2C2C7458, 0x1A1A2E34, 0x1B1B2D36, 0x6E6EB2DC, 0x5A5AEEB4, 0xA0A0FB5B,
618
+ 0x5252F6A4, 0x3B3B4D76, 0xD6D661B7, 0xB3B3CE7D, 0x29297B52, 0xE3E33EDD, 0x2F2F715E, 0x84849713,
619
+ 0x5353F5A6, 0xD1D168B9, 0x00000000, 0xEDED2CC1, 0x20206040, 0xFCFC1FE3, 0xB1B1C879, 0x5B5BEDB6,
620
+ 0x6A6ABED4, 0xCBCB468D, 0xBEBED967, 0x39394B72, 0x4A4ADE94, 0x4C4CD498, 0x5858E8B0, 0xCFCF4A85,
621
+ 0xD0D06BBB, 0xEFEF2AC5, 0xAAAAE54F, 0xFBFB16ED, 0x4343C586, 0x4D4DD79A, 0x33335566, 0x85859411,
622
+ 0x4545CF8A, 0xF9F910E9, 0x02020604, 0x7F7F81FE, 0x5050F0A0, 0x3C3C4478, 0x9F9FBA25, 0xA8A8E34B,
623
+ 0x5151F3A2, 0xA3A3FE5D, 0x4040C080, 0x8F8F8A05, 0x9292AD3F, 0x9D9DBC21, 0x38384870, 0xF5F504F1,
624
+ 0xBCBCDF63, 0xB6B6C177, 0xDADA75AF, 0x21216342, 0x10103020, 0xFFFF1AE5, 0xF3F30EFD, 0xD2D26DBF,
625
+ 0xCDCD4C81, 0x0C0C1418, 0x13133526, 0xECEC2FC3, 0x5F5FE1BE, 0x9797A235, 0x4444CC88, 0x1717392E,
626
+ 0xC4C45793, 0xA7A7F255, 0x7E7E82FC, 0x3D3D477A, 0x6464ACC8, 0x5D5DE7BA, 0x19192B32, 0x737395E6,
627
+ 0x6060A0C0, 0x81819819, 0x4F4FD19E, 0xDCDC7FA3, 0x22226644, 0x2A2A7E54, 0x9090AB3B, 0x8888830B,
628
+ 0x4646CA8C, 0xEEEE29C7, 0xB8B8D36B, 0x14143C28, 0xDEDE79A7, 0x5E5EE2BC, 0x0B0B1D16, 0xDBDB76AD,
629
+ 0xE0E03BDB, 0x32325664, 0x3A3A4E74, 0x0A0A1E14, 0x4949DB92, 0x06060A0C, 0x24246C48, 0x5C5CE4B8,
630
+ 0xC2C25D9F, 0xD3D36EBD, 0xACACEF43, 0x6262A6C4, 0x9191A839, 0x9595A431, 0xE4E437D3, 0x79798BF2,
631
+ 0xE7E732D5, 0xC8C8438B, 0x3737596E, 0x6D6DB7DA, 0x8D8D8C01, 0xD5D564B1, 0x4E4ED29C, 0xA9A9E049,
632
+ 0x6C6CB4D8, 0x5656FAAC, 0xF4F407F3, 0xEAEA25CF, 0x6565AFCA, 0x7A7A8EF4, 0xAEAEE947, 0x08081810,
633
+ 0xBABAD56F, 0x787888F0, 0x25256F4A, 0x2E2E725C, 0x1C1C2438, 0xA6A6F157, 0xB4B4C773, 0xC6C65197,
634
+ 0xE8E823CB, 0xDDDD7CA1, 0x74749CE8, 0x1F1F213E, 0x4B4BDD96, 0xBDBDDC61, 0x8B8B860D, 0x8A8A850F,
635
+ 0x707090E0, 0x3E3E427C, 0xB5B5C471, 0x6666AACC, 0x4848D890, 0x03030506, 0xF6F601F7, 0x0E0E121C,
636
+ 0x6161A3C2, 0x35355F6A, 0x5757F9AE, 0xB9B9D069, 0x86869117, 0xC1C15899, 0x1D1D273A, 0x9E9EB927,
637
+ 0xE1E138D9, 0xF8F813EB, 0x9898B32B, 0x11113322, 0x6969BBD2, 0xD9D970A9, 0x8E8E8907, 0x9494A733,
638
+ 0x9B9BB62D, 0x1E1E223C, 0x87879215, 0xE9E920C9, 0xCECE4987, 0x5555FFAA, 0x28287850, 0xDFDF7AA5,
639
+ 0x8C8C8F03, 0xA1A1F859, 0x89898009, 0x0D0D171A, 0xBFBFDA65, 0xE6E631D7, 0x4242C684, 0x6868B8D0,
640
+ 0x4141C382, 0x9999B029, 0x2D2D775A, 0x0F0F111E, 0xB0B0CB7B, 0x5454FCA8, 0xBBBBD66D, 0x16163A2C
641
+ ));
642
+
643
+ foreach ($t3 as $t3i) {
644
+ $t0[] = (($t3i << 24) & 0xFF000000) | (($t3i >> 8) & 0x00FFFFFF);
645
+ $t1[] = (($t3i << 16) & 0xFFFF0000) | (($t3i >> 16) & 0x0000FFFF);
646
+ $t2[] = (($t3i << 8) & 0xFFFFFF00) | (($t3i >> 24) & 0x000000FF);
647
+ }
648
+
649
+ $tables = array(
650
+ // The Precomputed mixColumns tables t0 - t3
651
+ $t0,
652
+ $t1,
653
+ $t2,
654
+ $t3,
655
+ // The SubByte S-Box
656
+ array(
657
+ 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
658
+ 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
659
+ 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
660
+ 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
661
+ 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
662
+ 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
663
+ 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
664
+ 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
665
+ 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
666
+ 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
667
+ 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
668
+ 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
669
+ 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
670
+ 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
671
+ 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
672
+ 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
673
+ )
674
+ );
675
+ }
676
+ return $tables;
677
+ }
678
+
679
+ /**
680
+ * Provides the inverse mixColumns and inverse sboxes tables
681
+ *
682
+ * @see self::_decryptBlock()
683
+ * @see self::_setupInlineCrypt()
684
+ * @see self::_setupKey()
685
+ * @access private
686
+ * @return array &$tables
687
+ */
688
+ function &_getInvTables()
689
+ {
690
+ static $tables;
691
+ if (empty($tables)) {
692
+ $dt3 = array_map('intval', array(
693
+ 0xF4A75051, 0x4165537E, 0x17A4C31A, 0x275E963A, 0xAB6BCB3B, 0x9D45F11F, 0xFA58ABAC, 0xE303934B,
694
+ 0x30FA5520, 0x766DF6AD, 0xCC769188, 0x024C25F5, 0xE5D7FC4F, 0x2ACBD7C5, 0x35448026, 0x62A38FB5,
695
+ 0xB15A49DE, 0xBA1B6725, 0xEA0E9845, 0xFEC0E15D, 0x2F7502C3, 0x4CF01281, 0x4697A38D, 0xD3F9C66B,
696
+ 0x8F5FE703, 0x929C9515, 0x6D7AEBBF, 0x5259DA95, 0xBE832DD4, 0x7421D358, 0xE0692949, 0xC9C8448E,
697
+ 0xC2896A75, 0x8E7978F4, 0x583E6B99, 0xB971DD27, 0xE14FB6BE, 0x88AD17F0, 0x20AC66C9, 0xCE3AB47D,
698
+ 0xDF4A1863, 0x1A3182E5, 0x51336097, 0x537F4562, 0x6477E0B1, 0x6BAE84BB, 0x81A01CFE, 0x082B94F9,
699
+ 0x48685870, 0x45FD198F, 0xDE6C8794, 0x7BF8B752, 0x73D323AB, 0x4B02E272, 0x1F8F57E3, 0x55AB2A66,
700
+ 0xEB2807B2, 0xB5C2032F, 0xC57B9A86, 0x3708A5D3, 0x2887F230, 0xBFA5B223, 0x036ABA02, 0x16825CED,
701
+ 0xCF1C2B8A, 0x79B492A7, 0x07F2F0F3, 0x69E2A14E, 0xDAF4CD65, 0x05BED506, 0x34621FD1, 0xA6FE8AC4,
702
+ 0x2E539D34, 0xF355A0A2, 0x8AE13205, 0xF6EB75A4, 0x83EC390B, 0x60EFAA40, 0x719F065E, 0x6E1051BD,
703
+ 0x218AF93E, 0xDD063D96, 0x3E05AEDD, 0xE6BD464D, 0x548DB591, 0xC45D0571, 0x06D46F04, 0x5015FF60,
704
+ 0x98FB2419, 0xBDE997D6, 0x4043CC89, 0xD99E7767, 0xE842BDB0, 0x898B8807, 0x195B38E7, 0xC8EEDB79,
705
+ 0x7C0A47A1, 0x420FE97C, 0x841EC9F8, 0x00000000, 0x80868309, 0x2BED4832, 0x1170AC1E, 0x5A724E6C,
706
+ 0x0EFFFBFD, 0x8538560F, 0xAED51E3D, 0x2D392736, 0x0FD9640A, 0x5CA62168, 0x5B54D19B, 0x362E3A24,
707
+ 0x0A67B10C, 0x57E70F93, 0xEE96D2B4, 0x9B919E1B, 0xC0C54F80, 0xDC20A261, 0x774B695A, 0x121A161C,
708
+ 0x93BA0AE2, 0xA02AE5C0, 0x22E0433C, 0x1B171D12, 0x090D0B0E, 0x8BC7ADF2, 0xB6A8B92D, 0x1EA9C814,
709
+ 0xF1198557, 0x75074CAF, 0x99DDBBEE, 0x7F60FDA3, 0x01269FF7, 0x72F5BC5C, 0x663BC544, 0xFB7E345B,
710
+ 0x4329768B, 0x23C6DCCB, 0xEDFC68B6, 0xE4F163B8, 0x31DCCAD7, 0x63851042, 0x97224013, 0xC6112084,
711
+ 0x4A247D85, 0xBB3DF8D2, 0xF93211AE, 0x29A16DC7, 0x9E2F4B1D, 0xB230F3DC, 0x8652EC0D, 0xC1E3D077,
712
+ 0xB3166C2B, 0x70B999A9, 0x9448FA11, 0xE9642247, 0xFC8CC4A8, 0xF03F1AA0, 0x7D2CD856, 0x3390EF22,
713
+ 0x494EC787, 0x38D1C1D9, 0xCAA2FE8C, 0xD40B3698, 0xF581CFA6, 0x7ADE28A5, 0xB78E26DA, 0xADBFA43F,
714
+ 0x3A9DE42C, 0x78920D50, 0x5FCC9B6A, 0x7E466254, 0x8D13C2F6, 0xD8B8E890, 0x39F75E2E, 0xC3AFF582,
715
+ 0x5D80BE9F, 0xD0937C69, 0xD52DA96F, 0x2512B3CF, 0xAC993BC8, 0x187DA710, 0x9C636EE8, 0x3BBB7BDB,
716
+ 0x267809CD, 0x5918F46E, 0x9AB701EC, 0x4F9AA883, 0x956E65E6, 0xFFE67EAA, 0xBCCF0821, 0x15E8E6EF,
717
+ 0xE79BD9BA, 0x6F36CE4A, 0x9F09D4EA, 0xB07CD629, 0xA4B2AF31, 0x3F23312A, 0xA59430C6, 0xA266C035,
718
+ 0x4EBC3774, 0x82CAA6FC, 0x90D0B0E0, 0xA7D81533, 0x04984AF1, 0xECDAF741, 0xCD500E7F, 0x91F62F17,
719
+ 0x4DD68D76, 0xEFB04D43, 0xAA4D54CC, 0x9604DFE4, 0xD1B5E39E, 0x6A881B4C, 0x2C1FB8C1, 0x65517F46,
720
+ 0x5EEA049D, 0x8C355D01, 0x877473FA, 0x0B412EFB, 0x671D5AB3, 0xDBD25292, 0x105633E9, 0xD647136D,
721
+ 0xD7618C9A, 0xA10C7A37, 0xF8148E59, 0x133C89EB, 0xA927EECE, 0x61C935B7, 0x1CE5EDE1, 0x47B13C7A,
722
+ 0xD2DF599C, 0xF2733F55, 0x14CE7918, 0xC737BF73, 0xF7CDEA53, 0xFDAA5B5F, 0x3D6F14DF, 0x44DB8678,
723
+ 0xAFF381CA, 0x68C43EB9, 0x24342C38, 0xA3405FC2, 0x1DC37216, 0xE2250CBC, 0x3C498B28, 0x0D9541FF,
724
+ 0xA8017139, 0x0CB3DE08, 0xB4E49CD8, 0x56C19064, 0xCB84617B, 0x32B670D5, 0x6C5C7448, 0xB85742D0
725
+ ));
726
+
727
+ foreach ($dt3 as $dt3i) {
728
+ $dt0[] = (($dt3i << 24) & 0xFF000000) | (($dt3i >> 8) & 0x00FFFFFF);
729
+ $dt1[] = (($dt3i << 16) & 0xFFFF0000) | (($dt3i >> 16) & 0x0000FFFF);
730
+ $dt2[] = (($dt3i << 8) & 0xFFFFFF00) | (($dt3i >> 24) & 0x000000FF);
731
+ };
732
+
733
+ $tables = array(
734
+ // The Precomputed inverse mixColumns tables dt0 - dt3
735
+ $dt0,
736
+ $dt1,
737
+ $dt2,
738
+ $dt3,
739
+ // The inverse SubByte S-Box
740
+ array(
741
+ 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB,
742
+ 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB,
743
+ 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
744
+ 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25,
745
+ 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92,
746
+ 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
747
+ 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06,
748
+ 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B,
749
+ 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
750
+ 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E,
751
+ 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B,
752
+ 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
753
+ 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F,
754
+ 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF,
755
+ 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
756
+ 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D
757
+ )
758
+ );
759
+ }
760
+ return $tables;
761
+ }
762
+
763
+ /**
764
+ * Setup the performance-optimized function for de/encrypt()
765
+ *
766
+ * @see \phpseclib\Crypt\Base::_setupInlineCrypt()
767
+ * @access private
768
+ */
769
+ function _setupInlineCrypt()
770
+ {
771
+ // Note: _setupInlineCrypt() will be called only if $this->changed === true
772
+ // So here we are'nt under the same heavy timing-stress as we are in _de/encryptBlock() or de/encrypt().
773
+ // However...the here generated function- $code, stored as php callback in $this->inline_crypt, must work as fast as even possible.
774
+
775
+ $lambda_functions =& self::_getLambdaFunctions();
776
+
777
+ // We create max. 10 hi-optimized code for memory reason. Means: For each $key one ultra fast inline-crypt function.
778
+ // (Currently, for Crypt_Rijndael/AES, one generated $lambda_function cost on php5.5@32bit ~80kb unfreeable mem and ~130kb on php5.5@64bit)
779
+ // After that, we'll still create very fast optimized code but not the hi-ultimative code, for each $mode one.
780
+ $gen_hi_opt_code = (bool)(count($lambda_functions) < 10);
781
+
782
+ // Generation of a uniqe hash for our generated code
783
+ $code_hash = "Crypt_Rijndael, {$this->mode}, {$this->Nr}, {$this->Nb}";
784
+ if ($gen_hi_opt_code) {
785
+ $code_hash = str_pad($code_hash, 32) . $this->_hashInlineCryptFunction($this->key);
786
+ }
787
+
788
+ if (!isset($lambda_functions[$code_hash])) {
789
+ switch (true) {
790
+ case $gen_hi_opt_code:
791
+ // The hi-optimized $lambda_functions will use the key-words hardcoded for better performance.
792
+ $w = $this->w;
793
+ $dw = $this->dw;
794
+ $init_encrypt = '';
795
+ $init_decrypt = '';
796
+ break;
797
+ default:
798
+ for ($i = 0, $cw = count($this->w); $i < $cw; ++$i) {
799
+ $w[] = '$w[' . $i . ']';
800
+ $dw[] = '$dw[' . $i . ']';
801
+ }
802
+ $init_encrypt = '$w = $self->w;';
803
+ $init_decrypt = '$dw = $self->dw;';
804
+ }
805
+
806
+ $Nr = $this->Nr;
807
+ $Nb = $this->Nb;
808
+ $c = $this->c;
809
+
810
+ // Generating encrypt code:
811
+ $init_encrypt.= '
812
+ static $tables;
813
+ if (empty($tables)) {
814
+ $tables = &$self->_getTables();
815
+ }
816
+ $t0 = $tables[0];
817
+ $t1 = $tables[1];
818
+ $t2 = $tables[2];
819
+ $t3 = $tables[3];
820
+ $sbox = $tables[4];
821
+ ';
822
+
823
+ $s = 'e';
824
+ $e = 's';
825
+ $wc = $Nb - 1;
826
+
827
+ // Preround: addRoundKey
828
+ $encrypt_block = '$in = unpack("N*", $in);'."\n";
829
+ for ($i = 0; $i < $Nb; ++$i) {
830
+ $encrypt_block .= '$s'.$i.' = $in['.($i + 1).'] ^ '.$w[++$wc].";\n";
831
+ }
832
+
833
+ // Mainrounds: shiftRows + subWord + mixColumns + addRoundKey
834
+ for ($round = 1; $round < $Nr; ++$round) {
835
+ list($s, $e) = array($e, $s);
836
+ for ($i = 0; $i < $Nb; ++$i) {
837
+ $encrypt_block.=
838
+ '$'.$e.$i.' =
839
+ $t0[($'.$s.$i .' >> 24) & 0xff] ^
840
+ $t1[($'.$s.(($i + $c[1]) % $Nb).' >> 16) & 0xff] ^
841
+ $t2[($'.$s.(($i + $c[2]) % $Nb).' >> 8) & 0xff] ^
842
+ $t3[ $'.$s.(($i + $c[3]) % $Nb).' & 0xff] ^
843
+ '.$w[++$wc].";\n";
844
+ }
845
+ }
846
+
847
+ // Finalround: subWord + shiftRows + addRoundKey
848
+ for ($i = 0; $i < $Nb; ++$i) {
849
+ $encrypt_block.=
850
+ '$'.$e.$i.' =
851
+ $sbox[ $'.$e.$i.' & 0xff] |
852
+ ($sbox[($'.$e.$i.' >> 8) & 0xff] << 8) |
853
+ ($sbox[($'.$e.$i.' >> 16) & 0xff] << 16) |
854
+ ($sbox[($'.$e.$i.' >> 24) & 0xff] << 24);'."\n";
855
+ }
856
+ $encrypt_block .= '$in = pack("N*"'."\n";
857
+ for ($i = 0; $i < $Nb; ++$i) {
858
+ $encrypt_block.= ',
859
+ ($'.$e.$i .' & '.((int)0xFF000000).') ^
860
+ ($'.$e.(($i + $c[1]) % $Nb).' & 0x00FF0000 ) ^
861
+ ($'.$e.(($i + $c[2]) % $Nb).' & 0x0000FF00 ) ^
862
+ ($'.$e.(($i + $c[3]) % $Nb).' & 0x000000FF ) ^
863
+ '.$w[$i]."\n";
864
+ }
865
+ $encrypt_block .= ');';
866
+
867
+ // Generating decrypt code:
868
+ $init_decrypt.= '
869
+ static $invtables;
870
+ if (empty($invtables)) {
871
+ $invtables = &$self->_getInvTables();
872
+ }
873
+ $dt0 = $invtables[0];
874
+ $dt1 = $invtables[1];
875
+ $dt2 = $invtables[2];
876
+ $dt3 = $invtables[3];
877
+ $isbox = $invtables[4];
878
+ ';
879
+
880
+ $s = 'e';
881
+ $e = 's';
882
+ $wc = $Nb - 1;
883
+
884
+ // Preround: addRoundKey
885
+ $decrypt_block = '$in = unpack("N*", $in);'."\n";
886
+ for ($i = 0; $i < $Nb; ++$i) {
887
+ $decrypt_block .= '$s'.$i.' = $in['.($i + 1).'] ^ '.$dw[++$wc].';'."\n";
888
+ }
889
+
890
+ // Mainrounds: shiftRows + subWord + mixColumns + addRoundKey
891
+ for ($round = 1; $round < $Nr; ++$round) {
892
+ list($s, $e) = array($e, $s);
893
+ for ($i = 0; $i < $Nb; ++$i) {
894
+ $decrypt_block.=
895
+ '$'.$e.$i.' =
896
+ $dt0[($'.$s.$i .' >> 24) & 0xff] ^
897
+ $dt1[($'.$s.(($Nb + $i - $c[1]) % $Nb).' >> 16) & 0xff] ^
898
+ $dt2[($'.$s.(($Nb + $i - $c[2]) % $Nb).' >> 8) & 0xff] ^
899
+ $dt3[ $'.$s.(($Nb + $i - $c[3]) % $Nb).' & 0xff] ^
900
+ '.$dw[++$wc].";\n";
901
+ }
902
+ }
903
+
904
+ // Finalround: subWord + shiftRows + addRoundKey
905
+ for ($i = 0; $i < $Nb; ++$i) {
906
+ $decrypt_block.=
907
+ '$'.$e.$i.' =
908
+ $isbox[ $'.$e.$i.' & 0xff] |
909
+ ($isbox[($'.$e.$i.' >> 8) & 0xff] << 8) |
910
+ ($isbox[($'.$e.$i.' >> 16) & 0xff] << 16) |
911
+ ($isbox[($'.$e.$i.' >> 24) & 0xff] << 24);'."\n";
912
+ }
913
+ $decrypt_block .= '$in = pack("N*"'."\n";
914
+ for ($i = 0; $i < $Nb; ++$i) {
915
+ $decrypt_block.= ',
916
+ ($'.$e.$i. ' & '.((int)0xFF000000).') ^
917
+ ($'.$e.(($Nb + $i - $c[1]) % $Nb).' & 0x00FF0000 ) ^
918
+ ($'.$e.(($Nb + $i - $c[2]) % $Nb).' & 0x0000FF00 ) ^
919
+ ($'.$e.(($Nb + $i - $c[3]) % $Nb).' & 0x000000FF ) ^
920
+ '.$dw[$i]."\n";
921
+ }
922
+ $decrypt_block .= ');';
923
+
924
+ $lambda_functions[$code_hash] = $this->_createInlineCryptFunction(
925
+ array(
926
+ 'init_crypt' => '',
927
+ 'init_encrypt' => $init_encrypt,
928
+ 'init_decrypt' => $init_decrypt,
929
+ 'encrypt_block' => $encrypt_block,
930
+ 'decrypt_block' => $decrypt_block
931
+ )
932
+ );
933
+ }
934
+ $this->inline_crypt = $lambda_functions[$code_hash];
935
+ }
936
+ }
vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger.php CHANGED
@@ -1,3779 +1,3779 @@
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 version 5
10
- *
11
- * {@internal (all DocBlock comments regarding implementation - such as the one that follows - refer to the
12
- * {@link self::MODE_INTERNAL self::MODE_INTERNAL} mode)
13
- *
14
- * 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 \phpseclib\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
- * $a = new \phpseclib\Math\BigInteger(2);
35
- * $b = new \phpseclib\Math\BigInteger(3);
36
- *
37
- * $c = $a->add($b);
38
- *
39
- * echo $c->toString(); // outputs 5
40
- * ?>
41
- * </code>
42
- *
43
- * @category Math
44
- * @package BigInteger
45
- * @author Jim Wigginton <terrafrost@php.net>
46
- * @copyright 2006 Jim Wigginton
47
- * @license http://www.opensource.org/licenses/mit-license.html MIT License
48
- */
49
-
50
- namespace phpseclib\Math;
51
-
52
- use phpseclib\Crypt\Random;
53
-
54
- /**
55
- * Pure-PHP arbitrary precision integer arithmetic library. Supports base-2, base-10, base-16, and base-256
56
- * numbers.
57
- *
58
- * @package BigInteger
59
- * @author Jim Wigginton <terrafrost@php.net>
60
- * @access public
61
- */
62
- class BigInteger
63
- {
64
- /**#@+
65
- * Reduction constants
66
- *
67
- * @access private
68
- * @see BigInteger::_reduce()
69
- */
70
- /**
71
- * @see BigInteger::_montgomery()
72
- * @see BigInteger::_prepMontgomery()
73
- */
74
- const MONTGOMERY = 0;
75
- /**
76
- * @see BigInteger::_barrett()
77
- */
78
- const BARRETT = 1;
79
- /**
80
- * @see BigInteger::_mod2()
81
- */
82
- const POWEROF2 = 2;
83
- /**
84
- * @see BigInteger::_remainder()
85
- */
86
- const CLASSIC = 3;
87
- /**
88
- * @see BigInteger::__clone()
89
- */
90
- const NONE = 4;
91
- /**#@-*/
92
-
93
- /**#@+
94
- * Array constants
95
- *
96
- * Rather than create a thousands and thousands of new BigInteger objects in repeated function calls to add() and
97
- * multiply() or whatever, we'll just work directly on arrays, taking them in as parameters and returning them.
98
- *
99
- * @access private
100
- */
101
- /**
102
- * $result[self::VALUE] contains the value.
103
- */
104
- const VALUE = 0;
105
- /**
106
- * $result[self::SIGN] contains the sign.
107
- */
108
- const SIGN = 1;
109
- /**#@-*/
110
-
111
- /**#@+
112
- * @access private
113
- * @see BigInteger::_montgomery()
114
- * @see BigInteger::_barrett()
115
- */
116
- /**
117
- * Cache constants
118
- *
119
- * $cache[self::VARIABLE] tells us whether or not the cached data is still valid.
120
- */
121
- const VARIABLE = 0;
122
- /**
123
- * $cache[self::DATA] contains the cached data.
124
- */
125
- const DATA = 1;
126
- /**#@-*/
127
-
128
- /**#@+
129
- * Mode constants.
130
- *
131
- * @access private
132
- * @see BigInteger::__construct()
133
- */
134
- /**
135
- * To use the pure-PHP implementation
136
- */
137
- const MODE_INTERNAL = 1;
138
- /**
139
- * To use the BCMath library
140
- *
141
- * (if enabled; otherwise, the internal implementation will be used)
142
- */
143
- const MODE_BCMATH = 2;
144
- /**
145
- * To use the GMP library
146
- *
147
- * (if present; otherwise, either the BCMath or the internal implementation will be used)
148
- */
149
- const MODE_GMP = 3;
150
- /**#@-*/
151
-
152
- /**
153
- * Karatsuba Cutoff
154
- *
155
- * At what point do we switch between Karatsuba multiplication and schoolbook long multiplication?
156
- *
157
- * @access private
158
- */
159
- const KARATSUBA_CUTOFF = 25;
160
-
161
- /**#@+
162
- * Static properties used by the pure-PHP implementation.
163
- *
164
- * @see __construct()
165
- */
166
- protected static $base;
167
- protected static $baseFull;
168
- protected static $maxDigit;
169
- protected static $msb;
170
-
171
- /**
172
- * $max10 in greatest $max10Len satisfying
173
- * $max10 = 10**$max10Len <= 2**$base.
174
- */
175
- protected static $max10;
176
-
177
- /**
178
- * $max10Len in greatest $max10Len satisfying
179
- * $max10 = 10**$max10Len <= 2**$base.
180
- */
181
- protected static $max10Len;
182
- protected static $maxDigit2;
183
- /**#@-*/
184
-
185
- /**
186
- * Holds the BigInteger's value.
187
- *
188
- * @var array
189
- * @access private
190
- */
191
- var $value;
192
-
193
- /**
194
- * Holds the BigInteger's magnitude.
195
- *
196
- * @var bool
197
- * @access private
198
- */
199
- var $is_negative = false;
200
-
201
- /**
202
- * Precision
203
- *
204
- * @see self::setPrecision()
205
- * @access private
206
- */
207
- var $precision = -1;
208
-
209
- /**
210
- * Precision Bitmask
211
- *
212
- * @see self::setPrecision()
213
- * @access private
214
- */
215
- var $bitmask = false;
216
-
217
- /**
218
- * Mode independent value used for serialization.
219
- *
220
- * If the bcmath or gmp extensions are installed $this->value will be a non-serializable resource, hence the need for
221
- * a variable that'll be serializable regardless of whether or not extensions are being used. Unlike $this->value,
222
- * however, $this->hex is only calculated when $this->__sleep() is called.
223
- *
224
- * @see self::__sleep()
225
- * @see self::__wakeup()
226
- * @var string
227
- * @access private
228
- */
229
- var $hex;
230
-
231
- /**
232
- * Converts base-2, base-10, base-16, and binary strings (base-256) to BigIntegers.
233
- *
234
- * If the second parameter - $base - is negative, then it will be assumed that the number's are encoded using
235
- * two's compliment. The sole exception to this is -10, which is treated the same as 10 is.
236
- *
237
- * Here's an example:
238
- * <code>
239
- * <?php
240
- * $a = new \phpseclib\Math\BigInteger('0x32', 16); // 50 in base-16
241
- *
242
- * echo $a->toString(); // outputs 50
243
- * ?>
244
- * </code>
245
- *
246
- * @param $x base-10 number or base-$base number if $base set.
247
- * @param int $base
248
- * @return \phpseclib\Math\BigInteger
249
- * @access public
250
- */
251
- function __construct($x = 0, $base = 10)
252
- {
253
- if (!defined('MATH_BIGINTEGER_MODE')) {
254
- switch (true) {
255
- case extension_loaded('gmp'):
256
- define('MATH_BIGINTEGER_MODE', self::MODE_GMP);
257
- break;
258
- case extension_loaded('bcmath'):
259
- define('MATH_BIGINTEGER_MODE', self::MODE_BCMATH);
260
- break;
261
- default:
262
- define('MATH_BIGINTEGER_MODE', self::MODE_INTERNAL);
263
- }
264
- }
265
-
266
- if (extension_loaded('openssl') && !defined('MATH_BIGINTEGER_OPENSSL_DISABLE') && !defined('MATH_BIGINTEGER_OPENSSL_ENABLED')) {
267
- // some versions of XAMPP have mismatched versions of OpenSSL which causes it not to work
268
- $versions = array();
269
-
270
- // avoid generating errors (even with suppression) when phpinfo() is disabled (common in production systems)
271
- if (strpos(ini_get('disable_functions'), 'phpinfo') === false) {
272
- ob_start();
273
- @phpinfo();
274
- $content = ob_get_contents();
275
- ob_end_clean();
276
-
277
- preg_match_all('#OpenSSL (Header|Library) Version(.*)#im', $content, $matches);
278
-
279
- if (!empty($matches[1])) {
280
- for ($i = 0; $i < count($matches[1]); $i++) {
281
- $fullVersion = trim(str_replace('=>', '', strip_tags($matches[2][$i])));
282
-
283
- // Remove letter part in OpenSSL version
284
- if (!preg_match('/(\d+\.\d+\.\d+)/i', $fullVersion, $m)) {
285
- $versions[$matches[1][$i]] = $fullVersion;
286
- } else {
287
- $versions[$matches[1][$i]] = $m[0];
288
- }
289
- }
290
- }
291
- }
292
-
293
- // it doesn't appear that OpenSSL versions were reported upon until PHP 5.3+
294
- switch (true) {
295
- case !isset($versions['Header']):
296
- case !isset($versions['Library']):
297
- case $versions['Header'] == $versions['Library']:
298
- case version_compare($versions['Header'], '1.0.0') >= 0 && version_compare($versions['Library'], '1.0.0') >= 0:
299
- define('MATH_BIGINTEGER_OPENSSL_ENABLED', true);
300
- break;
301
- default:
302
- define('MATH_BIGINTEGER_OPENSSL_DISABLE', true);
303
- }
304
- }
305
-
306
- if (!defined('PHP_INT_SIZE')) {
307
- define('PHP_INT_SIZE', 4);
308
- }
309
-
310
- if (empty(self::$base) && MATH_BIGINTEGER_MODE == self::MODE_INTERNAL) {
311
- switch (PHP_INT_SIZE) {
312
- case 8: // use 64-bit integers if int size is 8 bytes
313
- self::$base = 31;
314
- self::$baseFull = 0x80000000;
315
- self::$maxDigit = 0x7FFFFFFF;
316
- self::$msb = 0x40000000;
317
- self::$max10 = 1000000000;
318
- self::$max10Len = 9;
319
- self::$maxDigit2 = pow(2, 62);
320
- break;
321
- //case 4: // use 64-bit floats if int size is 4 bytes
322
- default:
323
- self::$base = 26;
324
- self::$baseFull = 0x4000000;
325
- self::$maxDigit = 0x3FFFFFF;
326
- self::$msb = 0x2000000;
327
- self::$max10 = 10000000;
328
- self::$max10Len = 7;
329
- self::$maxDigit2 = pow(2, 52); // pow() prevents truncation
330
- }
331
- }
332
-
333
- switch (MATH_BIGINTEGER_MODE) {
334
- case self::MODE_GMP:
335
- switch (true) {
336
- case is_resource($x) && get_resource_type($x) == 'GMP integer':
337
- // PHP 5.6 switched GMP from using resources to objects
338
- case $x instanceof \GMP:
339
- $this->value = $x;
340
- return;
341
- }
342
- $this->value = gmp_init(0);
343
- break;
344
- case self::MODE_BCMATH:
345
- $this->value = '0';
346
- break;
347
- default:
348
- $this->value = array();
349
- }
350
-
351
- // '0' counts as empty() but when the base is 256 '0' is equal to ord('0') or 48
352
- // '0' is the only value like this per http://php.net/empty
353
- if (empty($x) && (abs($base) != 256 || $x !== '0')) {
354
- return;
355
- }
356
-
357
- switch ($base) {
358
- case -256:
359
- if (ord($x[0]) & 0x80) {
360
- $x = ~$x;
361
- $this->is_negative = true;
362
- }
363
- case 256:
364
- switch (MATH_BIGINTEGER_MODE) {
365
- case self::MODE_GMP:
366
- $this->value = function_exists('gmp_import') ?
367
- gmp_import($x) :
368
- gmp_init('0x' . bin2hex($x));
369
- if ($this->is_negative) {
370
- $this->value = gmp_neg($this->value);
371
- }
372
- break;
373
- case self::MODE_BCMATH:
374
- // round $len to the nearest 4 (thanks, DavidMJ!)
375
- $len = (strlen($x) + 3) & 0xFFFFFFFC;
376
-
377
- $x = str_pad($x, $len, chr(0), STR_PAD_LEFT);
378
-
379
- for ($i = 0; $i < $len; $i+= 4) {
380
- $this->value = bcmul($this->value, '4294967296', 0); // 4294967296 == 2**32
381
- $this->value = bcadd($this->value, 0x1000000 * ord($x[$i]) + ((ord($x[$i + 1]) << 16) | (ord($x[$i + 2]) << 8) | ord($x[$i + 3])), 0);
382
- }
383
-
384
- if ($this->is_negative) {
385
- $this->value = '-' . $this->value;
386
- }
387
-
388
- break;
389
- // converts a base-2**8 (big endian / msb) number to base-2**26 (little endian / lsb)
390
- default:
391
- while (strlen($x)) {
392
- $this->value[] = $this->_bytes2int($this->_base256_rshift($x, self::$base));
393
- }
394
- }
395
-
396
- if ($this->is_negative) {
397
- if (MATH_BIGINTEGER_MODE != self::MODE_INTERNAL) {
398
- $this->is_negative = false;
399
- }
400
- $temp = $this->add(new static('-1'));
401
- $this->value = $temp->value;
402
- }
403
- break;
404
- case 16:
405
- case -16:
406
- if ($base > 0 && $x[0] == '-') {
407
- $this->is_negative = true;
408
- $x = substr($x, 1);
409
- }
410
-
411
- $x = preg_replace('#^(?:0x)?([A-Fa-f0-9]*).*#', '$1', $x);
412
-
413
- $is_negative = false;
414
- if ($base < 0 && hexdec($x[0]) >= 8) {
415
- $this->is_negative = $is_negative = true;
416
- $x = bin2hex(~pack('H*', $x));
417
- }
418
-
419
- switch (MATH_BIGINTEGER_MODE) {
420
- case self::MODE_GMP:
421
- $temp = $this->is_negative ? '-0x' . $x : '0x' . $x;
422
- $this->value = gmp_init($temp);
423
- $this->is_negative = false;
424
- break;
425
- case self::MODE_BCMATH:
426
- $x = (strlen($x) & 1) ? '0' . $x : $x;
427
- $temp = new static(pack('H*', $x), 256);
428
- $this->value = $this->is_negative ? '-' . $temp->value : $temp->value;
429
- $this->is_negative = false;
430
- break;
431
- default:
432
- $x = (strlen($x) & 1) ? '0' . $x : $x;
433
- $temp = new static(pack('H*', $x), 256);
434
- $this->value = $temp->value;
435
- }
436
-
437
- if ($is_negative) {
438
- $temp = $this->add(new static('-1'));
439
- $this->value = $temp->value;
440
- }
441
- break;
442
- case 10:
443
- case -10:
444
- // (?<!^)(?:-).*: find any -'s that aren't at the beginning and then any characters that follow that
445
- // (?<=^|-)0*: find any 0's that are preceded by the start of the string or by a - (ie. octals)
446
- // [^-0-9].*: find any non-numeric characters and then any characters that follow that
447
- $x = preg_replace('#(?<!^)(?:-).*|(?<=^|-)0*|[^-0-9].*#', '', $x);
448
- if (!strlen($x) || $x == '-') {
449
- $x = '0';
450
- }
451
-
452
- switch (MATH_BIGINTEGER_MODE) {
453
- case self::MODE_GMP:
454
- $this->value = gmp_init($x);
455
- break;
456
- case self::MODE_BCMATH:
457
- // explicitly casting $x to a string is necessary, here, since doing $x[0] on -1 yields different
458
- // results then doing it on '-1' does (modInverse does $x[0])
459
- $this->value = $x === '-' ? '0' : (string) $x;
460
- break;
461
- default:
462
- $temp = new static();
463
-
464
- $multiplier = new static();
465
- $multiplier->value = array(self::$max10);
466
-
467
- if ($x[0] == '-') {
468
- $this->is_negative = true;
469
- $x = substr($x, 1);
470
- }
471
-
472
- $x = str_pad($x, strlen($x) + ((self::$max10Len - 1) * strlen($x)) % self::$max10Len, 0, STR_PAD_LEFT);
473
- while (strlen($x)) {
474
- $temp = $temp->multiply($multiplier);
475
- $temp = $temp->add(new static($this->_int2bytes(substr($x, 0, self::$max10Len)), 256));
476
- $x = substr($x, self::$max10Len);
477
- }
478
-
479
- $this->value = $temp->value;
480
- }
481
- break;
482
- case 2: // base-2 support originally implemented by Lluis Pamies - thanks!
483
- case -2:
484
- if ($base > 0 && $x[0] == '-') {
485
- $this->is_negative = true;
486
- $x = substr($x, 1);
487
- }
488
-
489
- $x = preg_replace('#^([01]*).*#', '$1', $x);
490
- $x = str_pad($x, strlen($x) + (3 * strlen($x)) % 4, 0, STR_PAD_LEFT);
491
-
492
- $str = '0x';
493
- while (strlen($x)) {
494
- $part = substr($x, 0, 4);
495
- $str.= dechex(bindec($part));
496
- $x = substr($x, 4);
497
- }
498
-
499
- if ($this->is_negative) {
500
- $str = '-' . $str;
501
- }
502
-
503
- $temp = new static($str, 8 * $base); // ie. either -16 or +16
504
- $this->value = $temp->value;
505
- $this->is_negative = $temp->is_negative;
506
-
507
- break;
508
- default:
509
- // base not supported, so we'll let $this == 0
510
- }
511
- }
512
-
513
- /**
514
- * Converts a BigInteger to a byte string (eg. base-256).
515
- *
516
- * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're
517
- * saved as two's compliment.
518
- *
519
- * Here's an example:
520
- * <code>
521
- * <?php
522
- * $a = new \phpseclib\Math\BigInteger('65');
523
- *
524
- * echo $a->toBytes(); // outputs chr(65)
525
- * ?>
526
- * </code>
527
- *
528
- * @param bool $twos_compliment
529
- * @return string
530
- * @access public
531
- * @internal Converts a base-2**26 number to base-2**8
532
- */
533
- function toBytes($twos_compliment = false)
534
- {
535
- if ($twos_compliment) {
536
- $comparison = $this->compare(new static());
537
- if ($comparison == 0) {
538
- return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
539
- }
540
-
541
- $temp = $comparison < 0 ? $this->add(new static(1)) : $this->copy();
542
- $bytes = $temp->toBytes();
543
-
544
- if (!strlen($bytes)) { // eg. if the number we're trying to convert is -1
545
- $bytes = chr(0);
546
- }
547
-
548
- if (ord($bytes[0]) & 0x80) {
549
- $bytes = chr(0) . $bytes;
550
- }
551
-
552
- return $comparison < 0 ? ~$bytes : $bytes;
553
- }
554
-
555
- switch (MATH_BIGINTEGER_MODE) {
556
- case self::MODE_GMP:
557
- if (gmp_cmp($this->value, gmp_init(0)) == 0) {
558
- return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
559
- }
560
-
561
- if (function_exists('gmp_export')) {
562
- $temp = gmp_export($this->value);
563
- } else {
564
- $temp = gmp_strval(gmp_abs($this->value), 16);
565
- $temp = (strlen($temp) & 1) ? '0' . $temp : $temp;
566
- $temp = pack('H*', $temp);
567
- }
568
-
569
- return $this->precision > 0 ?
570
- substr(str_pad($temp, $this->precision >> 3, chr(0), STR_PAD_LEFT), -($this->precision >> 3)) :
571
- ltrim($temp, chr(0));
572
- case self::MODE_BCMATH:
573
- if ($this->value === '0') {
574
- return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
575
- }
576
-
577
- $value = '';
578
- $current = $this->value;
579
-
580
- if ($current[0] == '-') {
581
- $current = substr($current, 1);
582
- }
583
-
584
- while (bccomp($current, '0', 0) > 0) {
585
- $temp = bcmod($current, '16777216');
586
- $value = chr($temp >> 16) . chr($temp >> 8) . chr($temp) . $value;
587
- $current = bcdiv($current, '16777216', 0);
588
- }
589
-
590
- return $this->precision > 0 ?
591
- substr(str_pad($value, $this->precision >> 3, chr(0), STR_PAD_LEFT), -($this->precision >> 3)) :
592
- ltrim($value, chr(0));
593
- }
594
-
595
- if (!count($this->value)) {
596
- return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
597
- }
598
- $result = $this->_int2bytes($this->value[count($this->value) - 1]);
599
-
600
- $temp = $this->copy();
601
-
602
- for ($i = count($temp->value) - 2; $i >= 0; --$i) {
603
- $temp->_base256_lshift($result, self::$base);
604
- $result = $result | str_pad($temp->_int2bytes($temp->value[$i]), strlen($result), chr(0), STR_PAD_LEFT);
605
- }
606
-
607
- return $this->precision > 0 ?
608
- str_pad(substr($result, -(($this->precision + 7) >> 3)), ($this->precision + 7) >> 3, chr(0), STR_PAD_LEFT) :
609
- $result;
610
- }
611
-
612
- /**
613
- * Converts a BigInteger to a hex string (eg. base-16)).
614
- *
615
- * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're
616
- * saved as two's compliment.
617
- *
618
- * Here's an example:
619
- * <code>
620
- * <?php
621
- * $a = new \phpseclib\Math\BigInteger('65');
622
- *
623
- * echo $a->toHex(); // outputs '41'
624
- * ?>
625
- * </code>
626
- *
627
- * @param bool $twos_compliment
628
- * @return string
629
- * @access public
630
- * @internal Converts a base-2**26 number to base-2**8
631
- */
632
- function toHex($twos_compliment = false)
633
- {
634
- return bin2hex($this->toBytes($twos_compliment));
635
- }
636
-
637
- /**
638
- * Converts a BigInteger to a bit string (eg. base-2).
639
- *
640
- * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're
641
- * saved as two's compliment.
642
- *
643
- * Here's an example:
644
- * <code>
645
- * <?php
646
- * $a = new \phpseclib\Math\BigInteger('65');
647
- *
648
- * echo $a->toBits(); // outputs '1000001'
649
- * ?>
650
- * </code>
651
- *
652
- * @param bool $twos_compliment
653
- * @return string
654
- * @access public
655
- * @internal Converts a base-2**26 number to base-2**2
656
- */
657
- function toBits($twos_compliment = false)
658
- {
659
- $hex = $this->toHex($twos_compliment);
660
- $bits = '';
661
- for ($i = strlen($hex) - 8, $start = strlen($hex) & 7; $i >= $start; $i-=8) {
662
- $bits = str_pad(decbin(hexdec(substr($hex, $i, 8))), 32, '0', STR_PAD_LEFT) . $bits;
663
- }
664
- if ($start) { // hexdec('') == 0
665
- $bits = str_pad(decbin(hexdec(substr($hex, 0, $start))), 8, '0', STR_PAD_LEFT) . $bits;
666
- }
667
- $result = $this->precision > 0 ? substr($bits, -$this->precision) : ltrim($bits, '0');
668
-
669
- if ($twos_compliment && $this->compare(new static()) > 0 && $this->precision <= 0) {
670
- return '0' . $result;
671
- }
672
-
673
- return $result;
674
- }
675
-
676
- /**
677
- * Converts a BigInteger to a base-10 number.
678
- *
679
- * Here's an example:
680
- * <code>
681
- * <?php
682
- * $a = new \phpseclib\Math\BigInteger('50');
683
- *
684
- * echo $a->toString(); // outputs 50
685
- * ?>
686
- * </code>
687
- *
688
- * @return string
689
- * @access public
690
- * @internal Converts a base-2**26 number to base-10**7 (which is pretty much base-10)
691
- */
692
- function toString()
693
- {
694
- switch (MATH_BIGINTEGER_MODE) {
695
- case self::MODE_GMP:
696
- return gmp_strval($this->value);
697
- case self::MODE_BCMATH:
698
- if ($this->value === '0') {
699
- return '0';
700
- }
701
-
702
- return ltrim($this->value, '0');
703
- }
704
-
705
- if (!count($this->value)) {
706
- return '0';
707
- }
708
-
709
- $temp = $this->copy();
710
- $temp->is_negative = false;
711
-
712
- $divisor = new static();
713
- $divisor->value = array(self::$max10);
714
- $result = '';
715
- while (count($temp->value)) {
716
- list($temp, $mod) = $temp->divide($divisor);
717
- $result = str_pad(isset($mod->value[0]) ? $mod->value[0] : '', self::$max10Len, '0', STR_PAD_LEFT) . $result;
718
- }
719
- $result = ltrim($result, '0');
720
- if (empty($result)) {
721
- $result = '0';
722
- }
723
-
724
- if ($this->is_negative) {
725
- $result = '-' . $result;
726
- }
727
-
728
- return $result;
729
- }
730
-
731
- /**
732
- * Copy an object
733
- *
734
- * PHP5 passes objects by reference while PHP4 passes by value. As such, we need a function to guarantee
735
- * that all objects are passed by value, when appropriate. More information can be found here:
736
- *
737
- * {@link http://php.net/language.oop5.basic#51624}
738
- *
739
- * @access public
740
- * @see self::__clone()
741
- * @return \phpseclib\Math\BigInteger
742
- */
743
- function copy()
744
- {
745
- $temp = new static();
746
- $temp->value = $this->value;
747
- $temp->is_negative = $this->is_negative;
748
- $temp->precision = $this->precision;
749
- $temp->bitmask = $this->bitmask;
750
- return $temp;
751
- }
752
-
753
- /**
754
- * __toString() magic method
755
- *
756
- * Will be called, automatically, if you're supporting just PHP5. If you're supporting PHP4, you'll need to call
757
- * toString().
758
- *
759
- * @access public
760
- * @internal Implemented per a suggestion by Techie-Michael - thanks!
761
- */
762
- function __toString()
763
- {
764
- return $this->toString();
765
- }
766
-
767
- /**
768
- * __clone() magic method
769
- *
770
- * Although you can call BigInteger::__toString() directly in PHP5, you cannot call BigInteger::__clone() directly
771
- * 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
772
- * only syntax of $y = clone $x. As such, if you're trying to write an application that works on both PHP4 and
773
- * PHP5, call BigInteger::copy(), instead.
774
- *
775
- * @access public
776
- * @see self::copy()
777
- * @return \phpseclib\Math\BigInteger
778
- */
779
- function __clone()
780
- {
781
- return $this->copy();
782
- }
783
-
784
- /**
785
- * __sleep() magic method
786
- *
787
- * Will be called, automatically, when serialize() is called on a BigInteger object.
788
- *
789
- * @see self::__wakeup()
790
- * @access public
791
- */
792
- function __sleep()
793
- {
794
- $this->hex = $this->toHex(true);
795
- $vars = array('hex');
796
- if ($this->precision > 0) {
797
- $vars[] = 'precision';
798
- }
799
- return $vars;
800
- }
801
-
802
- /**
803
- * __wakeup() magic method
804
- *
805
- * Will be called, automatically, when unserialize() is called on a BigInteger object.
806
- *
807
- * @see self::__sleep()
808
- * @access public
809
- */
810
- function __wakeup()
811
- {
812
- $temp = new static($this->hex, -16);
813
- $this->value = $temp->value;
814
- $this->is_negative = $temp->is_negative;
815
- if ($this->precision > 0) {
816
- // recalculate $this->bitmask
817
- $this->setPrecision($this->precision);
818
- }
819
- }
820
-
821
- /**
822
- * __debugInfo() magic method
823
- *
824
- * Will be called, automatically, when print_r() or var_dump() are called
825
- *
826
- * @access public
827
- */
828
- function __debugInfo()
829
- {
830
- $opts = array();
831
- switch (MATH_BIGINTEGER_MODE) {
832
- case self::MODE_GMP:
833
- $engine = 'gmp';
834
- break;
835
- case self::MODE_BCMATH:
836
- $engine = 'bcmath';
837
- break;
838
- case self::MODE_INTERNAL:
839
- $engine = 'internal';
840
- $opts[] = PHP_INT_SIZE == 8 ? '64-bit' : '32-bit';
841
- }
842
- if (MATH_BIGINTEGER_MODE != self::MODE_GMP && defined('MATH_BIGINTEGER_OPENSSL_ENABLED')) {
843
- $opts[] = 'OpenSSL';
844
- }
845
- if (!empty($opts)) {
846
- $engine.= ' (' . implode($opts, ', ') . ')';
847
- }
848
- return array(
849
- 'value' => '0x' . $this->toHex(true),
850
- 'engine' => $engine
851
- );
852
- }
853
-
854
- /**
855
- * Adds two BigIntegers.
856
- *
857
- * Here's an example:
858
- * <code>
859
- * <?php
860
- * $a = new \phpseclib\Math\BigInteger('10');
861
- * $b = new \phpseclib\Math\BigInteger('20');
862
- *
863
- * $c = $a->add($b);
864
- *
865
- * echo $c->toString(); // outputs 30
866
- * ?>
867
- * </code>
868
- *
869
- * @param \phpseclib\Math\BigInteger $y
870
- * @return \phpseclib\Math\BigInteger
871
- * @access public
872
- * @internal Performs base-2**52 addition
873
- */
874
- function add($y)
875
- {
876
- switch (MATH_BIGINTEGER_MODE) {
877
- case self::MODE_GMP:
878
- $temp = new static();
879
- $temp->value = gmp_add($this->value, $y->value);
880
-
881
- return $this->_normalize($temp);
882
- case self::MODE_BCMATH:
883
- $temp = new static();
884
- $temp->value = bcadd($this->value, $y->value, 0);
885
-
886
- return $this->_normalize($temp);
887
- }
888
-
889
- $temp = $this->_add($this->value, $this->is_negative, $y->value, $y->is_negative);
890
-
891
- $result = new static();
892
- $result->value = $temp[self::VALUE];
893
- $result->is_negative = $temp[self::SIGN];
894
-
895
- return $this->_normalize($result);
896
- }
897
-
898
- /**
899
- * Performs addition.
900
- *
901
- * @param array $x_value
902
- * @param bool $x_negative
903
- * @param array $y_value
904
- * @param bool $y_negative
905
- * @return array
906
- * @access private
907
- */
908
- function _add($x_value, $x_negative, $y_value, $y_negative)
909
- {
910
- $x_size = count($x_value);
911
- $y_size = count($y_value);
912
-
913
- if ($x_size == 0) {
914
- return array(
915
- self::VALUE => $y_value,
916
- self::SIGN => $y_negative
917
- );
918
- } elseif ($y_size == 0) {
919
- return array(
920
- self::VALUE => $x_value,
921
- self::SIGN => $x_negative
922
- );
923
- }
924
-
925
- // subtract, if appropriate
926
- if ($x_negative != $y_negative) {
927
- if ($x_value == $y_value) {
928
- return array(
929
- self::VALUE => array(),
930
- self::SIGN => false
931
- );
932
- }
933
-
934
- $temp = $this->_subtract($x_value, false, $y_value, false);
935
- $temp[self::SIGN] = $this->_compare($x_value, false, $y_value, false) > 0 ?
936
- $x_negative : $y_negative;
937
-
938
- return $temp;
939
- }
940
-
941
- if ($x_size < $y_size) {
942
- $size = $x_size;
943
- $value = $y_value;
944
- } else {
945
- $size = $y_size;
946
- $value = $x_value;
947
- }
948
-
949
- $value[count($value)] = 0; // just in case the carry adds an extra digit
950
-
951
- $carry = 0;
952
- for ($i = 0, $j = 1; $j < $size; $i+=2, $j+=2) {
953
- $sum = $x_value[$j] * self::$baseFull + $x_value[$i] + $y_value[$j] * self::$baseFull + $y_value[$i] + $carry;
954
- $carry = $sum >= self::$maxDigit2; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1
955
- $sum = $carry ? $sum - self::$maxDigit2 : $sum;
956
-
957
- $temp = self::$base === 26 ? intval($sum / 0x4000000) : ($sum >> 31);
958
-
959
- $value[$i] = (int) ($sum - self::$baseFull * $temp); // eg. a faster alternative to fmod($sum, 0x4000000)
960
- $value[$j] = $temp;
961
- }
962
-
963
- if ($j == $size) { // ie. if $y_size is odd
964
- $sum = $x_value[$i] + $y_value[$i] + $carry;
965
- $carry = $sum >= self::$baseFull;
966
- $value[$i] = $carry ? $sum - self::$baseFull : $sum;
967
- ++$i; // ie. let $i = $j since we've just done $value[$i]
968
- }
969
-
970
- if ($carry) {
971
- for (; $value[$i] == self::$maxDigit; ++$i) {
972
- $value[$i] = 0;
973
- }
974
- ++$value[$i];
975
- }
976
-
977
- return array(
978
- self::VALUE => $this->_trim($value),
979
- self::SIGN => $x_negative
980
- );
981
- }
982
-
983
- /**
984
- * Subtracts two BigIntegers.
985
- *
986
- * Here's an example:
987
- * <code>
988
- * <?php
989
- * $a = new \phpseclib\Math\BigInteger('10');
990
- * $b = new \phpseclib\Math\BigInteger('20');
991
- *
992
- * $c = $a->subtract($b);
993
- *
994
- * echo $c->toString(); // outputs -10
995
- * ?>
996
- * </code>
997
- *
998
- * @param \phpseclib\Math\BigInteger $y
999
- * @return \phpseclib\Math\BigInteger
1000
- * @access public
1001
- * @internal Performs base-2**52 subtraction
1002
- */
1003
- function subtract($y)
1004
- {
1005
- switch (MATH_BIGINTEGER_MODE) {
1006
- case self::MODE_GMP:
1007
- $temp = new static();
1008
- $temp->value = gmp_sub($this->value, $y->value);
1009
-
1010
- return $this->_normalize($temp);
1011
- case self::MODE_BCMATH:
1012
- $temp = new static();
1013
- $temp->value = bcsub($this->value, $y->value, 0);
1014
-
1015
- return $this->_normalize($temp);
1016
- }
1017
-
1018
- $temp = $this->_subtract($this->value, $this->is_negative, $y->value, $y->is_negative);
1019
-
1020
- $result = new static();
1021
- $result->value = $temp[self::VALUE];
1022
- $result->is_negative = $temp[self::SIGN];
1023
-
1024
- return $this->_normalize($result);
1025
- }
1026
-
1027
- /**
1028
- * Performs subtraction.
1029
- *
1030
- * @param array $x_value
1031
- * @param bool $x_negative
1032
- * @param array $y_value
1033
- * @param bool $y_negative
1034
- * @return array
1035
- * @access private
1036
- */
1037
- function _subtract($x_value, $x_negative, $y_value, $y_negative)
1038
- {
1039
- $x_size = count($x_value);
1040
- $y_size = count($y_value);
1041
-
1042
- if ($x_size == 0) {
1043
- return array(
1044
- self::VALUE => $y_value,
1045
- self::SIGN => !$y_negative
1046
- );
1047
- } elseif ($y_size == 0) {
1048
- return array(
1049
- self::VALUE => $x_value,
1050
- self::SIGN => $x_negative
1051
- );
1052
- }
1053
-
1054
- // add, if appropriate (ie. -$x - +$y or +$x - -$y)
1055
- if ($x_negative != $y_negative) {
1056
- $temp = $this->_add($x_value, false, $y_value, false);
1057
- $temp[self::SIGN] = $x_negative;
1058
-
1059
- return $temp;
1060
- }
1061
-
1062
- $diff = $this->_compare($x_value, $x_negative, $y_value, $y_negative);
1063
-
1064
- if (!$diff) {
1065
- return array(
1066
- self::VALUE => array(),
1067
- self::SIGN => false
1068
- );
1069
- }
1070
-
1071
- // switch $x and $y around, if appropriate.
1072
- if ((!$x_negative && $diff < 0) || ($x_negative && $diff > 0)) {
1073
- $temp = $x_value;
1074
- $x_value = $y_value;
1075
- $y_value = $temp;
1076
-
1077
- $x_negative = !$x_negative;
1078
-
1079
- $x_size = count($x_value);
1080
- $y_size = count($y_value);
1081
- }
1082
-
1083
- // at this point, $x_value should be at least as big as - if not bigger than - $y_value
1084
-
1085
- $carry = 0;
1086
- for ($i = 0, $j = 1; $j < $y_size; $i+=2, $j+=2) {
1087
- $sum = $x_value[$j] * self::$baseFull + $x_value[$i] - $y_value[$j] * self::$baseFull - $y_value[$i] - $carry;
1088
- $carry = $sum < 0; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1
1089
- $sum = $carry ? $sum + self::$maxDigit2 : $sum;
1090
-
1091
- $temp = self::$base === 26 ? intval($sum / 0x4000000) : ($sum >> 31);
1092
-
1093
- $x_value[$i] = (int) ($sum - self::$baseFull * $temp);
1094
- $x_value[$j] = $temp;
1095
- }
1096
-
1097
- if ($j == $y_size) { // ie. if $y_size is odd
1098
- $sum = $x_value[$i] - $y_value[$i] - $carry;
1099
- $carry = $sum < 0;
1100
- $x_value[$i] = $carry ? $sum + self::$baseFull : $sum;
1101
- ++$i;
1102
- }
1103
-
1104
- if ($carry) {
1105
- for (; !$x_value[$i]; ++$i) {
1106
- $x_value[$i] = self::$maxDigit;
1107
- }
1108
- --$x_value[$i];
1109
- }
1110
-
1111
- return array(
1112
- self::VALUE => $this->_trim($x_value),
1113
- self::SIGN => $x_negative
1114
- );
1115
- }
1116
-
1117
- /**
1118
- * Multiplies two BigIntegers
1119
- *
1120
- * Here's an example:
1121
- * <code>
1122
- * <?php
1123
- * $a = new \phpseclib\Math\BigInteger('10');
1124
- * $b = new \phpseclib\Math\BigInteger('20');
1125
- *
1126
- * $c = $a->multiply($b);
1127
- *
1128
- * echo $c->toString(); // outputs 200
1129
- * ?>
1130
- * </code>
1131
- *
1132
- * @param \phpseclib\Math\BigInteger $x
1133
- * @return \phpseclib\Math\BigInteger
1134
- * @access public
1135
- */
1136
- function multiply($x)
1137
- {
1138
- switch (MATH_BIGINTEGER_MODE) {
1139
- case self::MODE_GMP:
1140
- $temp = new static();
1141
- $temp->value = gmp_mul($this->value, $x->value);
1142
-
1143
- return $this->_normalize($temp);
1144
- case self::MODE_BCMATH:
1145
- $temp = new static();
1146
- $temp->value = bcmul($this->value, $x->value, 0);
1147
-
1148
- return $this->_normalize($temp);
1149
- }
1150
-
1151
- $temp = $this->_multiply($this->value, $this->is_negative, $x->value, $x->is_negative);
1152
-
1153
- $product = new static();
1154
- $product->value = $temp[self::VALUE];
1155
- $product->is_negative = $temp[self::SIGN];
1156
-
1157
- return $this->_normalize($product);
1158
- }
1159
-
1160
- /**
1161
- * Performs multiplication.
1162
- *
1163
- * @param array $x_value
1164
- * @param bool $x_negative
1165
- * @param array $y_value
1166
- * @param bool $y_negative
1167
- * @return array
1168
- * @access private
1169
- */
1170
- function _multiply($x_value, $x_negative, $y_value, $y_negative)
1171
- {
1172
- //if ( $x_value == $y_value ) {
1173
- // return array(
1174
- // self::VALUE => $this->_square($x_value),
1175
- // self::SIGN => $x_sign != $y_value
1176
- // );
1177
- //}
1178
-
1179
- $x_length = count($x_value);
1180
- $y_length = count($y_value);
1181
-
1182
- if (!$x_length || !$y_length) { // a 0 is being multiplied
1183
- return array(
1184
- self::VALUE => array(),
1185
- self::SIGN => false
1186
- );
1187
- }
1188
-
1189
- return array(
1190
- self::VALUE => min($x_length, $y_length) < 2 * self::KARATSUBA_CUTOFF ?
1191
- $this->_trim($this->_regularMultiply($x_value, $y_value)) :
1192
- $this->_trim($this->_karatsuba($x_value, $y_value)),
1193
- self::SIGN => $x_negative != $y_negative
1194
- );
1195
- }
1196
-
1197
- /**
1198
- * Performs long multiplication on two BigIntegers
1199
- *
1200
- * Modeled after 'multiply' in MutableBigInteger.java.
1201
- *
1202
- * @param array $x_value
1203
- * @param array $y_value
1204
- * @return array
1205
- * @access private
1206
- */
1207
- function _regularMultiply($x_value, $y_value)
1208
- {
1209
- $x_length = count($x_value);
1210
- $y_length = count($y_value);
1211
-
1212
- if (!$x_length || !$y_length) { // a 0 is being multiplied
1213
- return array();
1214
- }
1215
-
1216
- if ($x_length < $y_length) {
1217
- $temp = $x_value;
1218
- $x_value = $y_value;
1219
- $y_value = $temp;
1220
-
1221
- $x_length = count($x_value);
1222
- $y_length = count($y_value);
1223
- }
1224
-
1225
- $product_value = $this->_array_repeat(0, $x_length + $y_length);
1226
-
1227
- // the following for loop could be removed if the for loop following it
1228
- // (the one with nested for loops) initially set $i to 0, but
1229
- // doing so would also make the result in one set of unnecessary adds,
1230
- // since on the outermost loops first pass, $product->value[$k] is going
1231
- // to always be 0
1232
-
1233
- $carry = 0;
1234
-
1235
- for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0
1236
- $temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0
1237
- $carry = self::$base === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
1238
- $product_value[$j] = (int) ($temp - self::$baseFull * $carry);
1239
- }
1240
-
1241
- $product_value[$j] = $carry;
1242
-
1243
- // the above for loop is what the previous comment was talking about. the
1244
- // following for loop is the "one with nested for loops"
1245
- for ($i = 1; $i < $y_length; ++$i) {
1246
- $carry = 0;
1247
-
1248
- for ($j = 0, $k = $i; $j < $x_length; ++$j, ++$k) {
1249
- $temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry;
1250
- $carry = self::$base === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
1251
- $product_value[$k] = (int) ($temp - self::$baseFull * $carry);
1252
- }
1253
-
1254
- $product_value[$k] = $carry;
1255
- }
1256
-
1257
- return $product_value;
1258
- }
1259
-
1260
- /**
1261
- * Performs Karatsuba multiplication on two BigIntegers
1262
- *
1263
- * See {@link http://en.wikipedia.org/wiki/Karatsuba_algorithm Karatsuba algorithm} and
1264
- * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=120 MPM 5.2.3}.
1265
- *
1266
- * @param array $x_value
1267
- * @param array $y_value
1268
- * @return array
1269
- * @access private
1270
- */
1271
- function _karatsuba($x_value, $y_value)
1272
- {
1273
- $m = min(count($x_value) >> 1, count($y_value) >> 1);
1274
-
1275
- if ($m < self::KARATSUBA_CUTOFF) {
1276
- return $this->_regularMultiply($x_value, $y_value);
1277
- }
1278
-
1279
- $x1 = array_slice($x_value, $m);
1280
- $x0 = array_slice($x_value, 0, $m);
1281
- $y1 = array_slice($y_value, $m);
1282
- $y0 = array_slice($y_value, 0, $m);
1283
-
1284
- $z2 = $this->_karatsuba($x1, $y1);
1285
- $z0 = $this->_karatsuba($x0, $y0);
1286
-
1287
- $z1 = $this->_add($x1, false, $x0, false);
1288
- $temp = $this->_add($y1, false, $y0, false);
1289
- $z1 = $this->_karatsuba($z1[self::VALUE], $temp[self::VALUE]);
1290
- $temp = $this->_add($z2, false, $z0, false);
1291
- $z1 = $this->_subtract($z1, false, $temp[self::VALUE], false);
1292
-
1293
- $z2 = array_merge(array_fill(0, 2 * $m, 0), $z2);
1294
- $z1[self::VALUE] = array_merge(array_fill(0, $m, 0), $z1[self::VALUE]);
1295
-
1296
- $xy = $this->_add($z2, false, $z1[self::VALUE], $z1[self::SIGN]);
1297
- $xy = $this->_add($xy[self::VALUE], $xy[self::SIGN], $z0, false);
1298
-
1299
- return $xy[self::VALUE];
1300
- }
1301
-
1302
- /**
1303
- * Performs squaring
1304
- *
1305
- * @param array $x
1306
- * @return array
1307
- * @access private
1308
- */
1309
- function _square($x = false)
1310
- {
1311
- return count($x) < 2 * self::KARATSUBA_CUTOFF ?
1312
- $this->_trim($this->_baseSquare($x)) :
1313
- $this->_trim($this->_karatsubaSquare($x));
1314
- }
1315
-
1316
- /**
1317
- * Performs traditional squaring on two BigIntegers
1318
- *
1319
- * Squaring can be done faster than multiplying a number by itself can be. See
1320
- * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=7 HAC 14.2.4} /
1321
- * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=141 MPM 5.3} for more information.
1322
- *
1323
- * @param array $value
1324
- * @return array
1325
- * @access private
1326
- */
1327
- function _baseSquare($value)
1328
- {
1329
- if (empty($value)) {
1330
- return array();
1331
- }
1332
- $square_value = $this->_array_repeat(0, 2 * count($value));
1333
-
1334
- for ($i = 0, $max_index = count($value) - 1; $i <= $max_index; ++$i) {
1335
- $i2 = $i << 1;
1336
-
1337
- $temp = $square_value[$i2] + $value[$i] * $value[$i];
1338
- $carry = self::$base === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
1339
- $square_value[$i2] = (int) ($temp - self::$baseFull * $carry);
1340
-
1341
- // note how we start from $i+1 instead of 0 as we do in multiplication.
1342
- for ($j = $i + 1, $k = $i2 + 1; $j <= $max_index; ++$j, ++$k) {
1343
- $temp = $square_value[$k] + 2 * $value[$j] * $value[$i] + $carry;
1344
- $carry = self::$base === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
1345
- $square_value[$k] = (int) ($temp - self::$baseFull * $carry);
1346
- }
1347
-
1348
- // the following line can yield values larger 2**15. at this point, PHP should switch
1349
- // over to floats.
1350
- $square_value[$i + $max_index + 1] = $carry;
1351
- }
1352
-
1353
- return $square_value;
1354
- }
1355
-
1356
- /**
1357
- * Performs Karatsuba "squaring" on two BigIntegers
1358
- *
1359
- * See {@link http://en.wikipedia.org/wiki/Karatsuba_algorithm Karatsuba algorithm} and
1360
- * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=151 MPM 5.3.4}.
1361
- *
1362
- * @param array $value
1363
- * @return array
1364
- * @access private
1365
- */
1366
- function _karatsubaSquare($value)
1367
- {
1368
- $m = count($value) >> 1;
1369
-
1370
- if ($m < self::KARATSUBA_CUTOFF) {
1371
- return $this->_baseSquare($value);
1372
- }
1373
-
1374
- $x1 = array_slice($value, $m);
1375
- $x0 = array_slice($value, 0, $m);
1376
-
1377
- $z2 = $this->_karatsubaSquare($x1);
1378
- $z0 = $this->_karatsubaSquare($x0);
1379
-
1380
- $z1 = $this->_add($x1, false, $x0, false);
1381
- $z1 = $this->_karatsubaSquare($z1[self::VALUE]);
1382
- $temp = $this->_add($z2, false, $z0, false);
1383
- $z1 = $this->_subtract($z1, false, $temp[self::VALUE], false);
1384
-
1385
- $z2 = array_merge(array_fill(0, 2 * $m, 0), $z2);
1386
- $z1[self::VALUE] = array_merge(array_fill(0, $m, 0), $z1[self::VALUE]);
1387
-
1388
- $xx = $this->_add($z2, false, $z1[self::VALUE], $z1[self::SIGN]);
1389
- $xx = $this->_add($xx[self::VALUE], $xx[self::SIGN], $z0, false);
1390
-
1391
- return $xx[self::VALUE];
1392
- }
1393
-
1394
- /**
1395
- * Divides two BigIntegers.
1396
- *
1397
- * Returns an array whose first element contains the quotient and whose second element contains the
1398
- * "common residue". If the remainder would be positive, the "common residue" and the remainder are the
1399
- * same. If the remainder would be negative, the "common residue" is equal to the sum of the remainder
1400
- * and the divisor (basically, the "common residue" is the first positive modulo).
1401
- *
1402
- * Here's an example:
1403
- * <code>
1404
- * <?php
1405
- * $a = new \phpseclib\Math\BigInteger('10');
1406
- * $b = new \phpseclib\Math\BigInteger('20');
1407
- *
1408
- * list($quotient, $remainder) = $a->divide($b);
1409
- *
1410
- * echo $quotient->toString(); // outputs 0
1411
- * echo "\r\n";
1412
- * echo $remainder->toString(); // outputs 10
1413
- * ?>
1414
- * </code>
1415
- *
1416
- * @param \phpseclib\Math\BigInteger $y
1417
- * @return array
1418
- * @access public
1419
- * @internal This function is based off of {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=9 HAC 14.20}.
1420
- */
1421
- function divide($y)
1422
- {
1423
- switch (MATH_BIGINTEGER_MODE) {
1424
- case self::MODE_GMP:
1425
- $quotient = new static();
1426
- $remainder = new static();
1427
-
1428
- list($quotient->value, $remainder->value) = gmp_div_qr($this->value, $y->value);
1429
-
1430
- if (gmp_sign($remainder->value) < 0) {
1431
- $remainder->value = gmp_add($remainder->value, gmp_abs($y->value));
1432
- }
1433
-
1434
- return array($this->_normalize($quotient), $this->_normalize($remainder));
1435
- case self::MODE_BCMATH:
1436
- $quotient = new static();
1437
- $remainder = new static();
1438
-
1439
- $quotient->value = bcdiv($this->value, $y->value, 0);
1440
- $remainder->value = bcmod($this->value, $y->value);
1441
-
1442
- if ($remainder->value[0] == '-') {
1443
- $remainder->value = bcadd($remainder->value, $y->value[0] == '-' ? substr($y->value, 1) : $y->value, 0);
1444
- }
1445
-
1446
- return array($this->_normalize($quotient), $this->_normalize($remainder));
1447
- }
1448
-
1449
- if (count($y->value) == 1) {
1450
- list($q, $r) = $this->_divide_digit($this->value, $y->value[0]);
1451
- $quotient = new static();
1452
- $remainder = new static();
1453
- $quotient->value = $q;
1454
- $remainder->value = array($r);
1455
- $quotient->is_negative = $this->is_negative != $y->is_negative;
1456
- return array($this->_normalize($quotient), $this->_normalize($remainder));
1457
- }
1458
-
1459
- static $zero;
1460
- if (!isset($zero)) {
1461
- $zero = new static();
1462
- }
1463
-
1464
- $x = $this->copy();
1465
- $y = $y->copy();
1466
-
1467
- $x_sign = $x->is_negative;
1468
- $y_sign = $y->is_negative;
1469
-
1470
- $x->is_negative = $y->is_negative = false;
1471
-
1472
- $diff = $x->compare($y);
1473
-
1474
- if (!$diff) {
1475
- $temp = new static();
1476
- $temp->value = array(1);
1477
- $temp->is_negative = $x_sign != $y_sign;
1478
- return array($this->_normalize($temp), $this->_normalize(new static()));
1479
- }
1480
-
1481
- if ($diff < 0) {
1482
- // if $x is negative, "add" $y.
1483
- if ($x_sign) {
1484
- $x = $y->subtract($x);
1485
- }
1486
- return array($this->_normalize(new static()), $this->_normalize($x));
1487
- }
1488
-
1489
- // normalize $x and $y as described in HAC 14.23 / 14.24
1490
- $msb = $y->value[count($y->value) - 1];
1491
- for ($shift = 0; !($msb & self::$msb); ++$shift) {
1492
- $msb <<= 1;
1493
- }
1494
- $x->_lshift($shift);
1495
- $y->_lshift($shift);
1496
- $y_value = &$y->value;
1497
-
1498
- $x_max = count($x->value) - 1;
1499
- $y_max = count($y->value) - 1;
1500
-
1501
- $quotient = new static();
1502
- $quotient_value = &$quotient->value;
1503
- $quotient_value = $this->_array_repeat(0, $x_max - $y_max + 1);
1504
-
1505
- static $temp, $lhs, $rhs;
1506
- if (!isset($temp)) {
1507
- $temp = new static();
1508
- $lhs = new static();
1509
- $rhs = new static();
1510
- }
1511
- $temp_value = &$temp->value;
1512
- $rhs_value = &$rhs->value;
1513
-
1514
- // $temp = $y << ($x_max - $y_max-1) in base 2**26
1515
- $temp_value = array_merge($this->_array_repeat(0, $x_max - $y_max), $y_value);
1516
-
1517
- while ($x->compare($temp) >= 0) {
1518
- // calculate the "common residue"
1519
- ++$quotient_value[$x_max - $y_max];
1520
- $x = $x->subtract($temp);
1521
- $x_max = count($x->value) - 1;
1522
- }
1523
-
1524
- for ($i = $x_max; $i >= $y_max + 1; --$i) {
1525
- $x_value = &$x->value;
1526
- $x_window = array(
1527
- isset($x_value[$i]) ? $x_value[$i] : 0,
1528
- isset($x_value[$i - 1]) ? $x_value[$i - 1] : 0,
1529
- isset($x_value[$i - 2]) ? $x_value[$i - 2] : 0
1530
- );
1531
- $y_window = array(
1532
- $y_value[$y_max],
1533
- ($y_max > 0) ? $y_value[$y_max - 1] : 0
1534
- );
1535
-
1536
- $q_index = $i - $y_max - 1;
1537
- if ($x_window[0] == $y_window[0]) {
1538
- $quotient_value[$q_index] = self::$maxDigit;
1539
- } else {
1540
- $quotient_value[$q_index] = $this->_safe_divide(
1541
- $x_window[0] * self::$baseFull + $x_window[1],
1542
- $y_window[0]
1543
- );
1544
- }
1545
-
1546
- $temp_value = array($y_window[1], $y_window[0]);
1547
-
1548
- $lhs->value = array($quotient_value[$q_index]);
1549
- $lhs = $lhs->multiply($temp);
1550
-
1551
- $rhs_value = array($x_window[2], $x_window[1], $x_window[0]);
1552
-
1553
- while ($lhs->compare($rhs) > 0) {
1554
- --$quotient_value[$q_index];
1555
-
1556
- $lhs->value = array($quotient_value[$q_index]);
1557
- $lhs = $lhs->multiply($temp);
1558
- }
1559
-
1560
- $adjust = $this->_array_repeat(0, $q_index);
1561
- $temp_value = array($quotient_value[$q_index]);
1562
- $temp = $temp->multiply($y);
1563
- $temp_value = &$temp->value;
1564
- if (count($temp_value)) {
1565
- $temp_value = array_merge($adjust, $temp_value);
1566
- }
1567
-
1568
- $x = $x->subtract($temp);
1569
-
1570
- if ($x->compare($zero) < 0) {
1571
- $temp_value = array_merge($adjust, $y_value);
1572
- $x = $x->add($temp);
1573
-
1574
- --$quotient_value[$q_index];
1575
- }
1576
-
1577
- $x_max = count($x_value) - 1;
1578
- }
1579
-
1580
- // unnormalize the remainder
1581
- $x->_rshift($shift);
1582
-
1583
- $quotient->is_negative = $x_sign != $y_sign;
1584
-
1585
- // calculate the "common residue", if appropriate
1586
- if ($x_sign) {
1587
- $y->_rshift($shift);
1588
- $x = $y->subtract($x);
1589
- }
1590
-
1591
- return array($this->_normalize($quotient), $this->_normalize($x));
1592
- }
1593
-
1594
- /**
1595
- * Divides a BigInteger by a regular integer
1596
- *
1597
- * abc / x = a00 / x + b0 / x + c / x
1598
- *
1599
- * @param array $dividend
1600
- * @param array $divisor
1601
- * @return array
1602
- * @access private
1603
- */
1604
- function _divide_digit($dividend, $divisor)
1605
- {
1606
- $carry = 0;
1607
- $result = array();
1608
-
1609
- for ($i = count($dividend) - 1; $i >= 0; --$i) {
1610
- $temp = self::$baseFull * $carry + $dividend[$i];
1611
- $result[$i] = $this->_safe_divide($temp, $divisor);
1612
- $carry = (int) ($temp - $divisor * $result[$i]);
1613
- }
1614
-
1615
- return array($result, $carry);
1616
- }
1617
-
1618
- /**
1619
- * Performs modular exponentiation.
1620
- *
1621
- * Here's an example:
1622
- * <code>
1623
- * <?php
1624
- * $a = new \phpseclib\Math\BigInteger('10');
1625
- * $b = new \phpseclib\Math\BigInteger('20');
1626
- * $c = new \phpseclib\Math\BigInteger('30');
1627
- *
1628
- * $c = $a->modPow($b, $c);
1629
- *
1630
- * echo $c->toString(); // outputs 10
1631
- * ?>
1632
- * </code>
1633
- *
1634
- * @param \phpseclib\Math\BigInteger $e
1635
- * @param \phpseclib\Math\BigInteger $n
1636
- * @return \phpseclib\Math\BigInteger
1637
- * @access public
1638
- * @internal The most naive approach to modular exponentiation has very unreasonable requirements, and
1639
- * and although the approach involving repeated squaring does vastly better, it, too, is impractical
1640
- * for our purposes. The reason being that division - by far the most complicated and time-consuming
1641
- * of the basic operations (eg. +,-,*,/) - occurs multiple times within it.
1642
- *
1643
- * Modular reductions resolve this issue. Although an individual modular reduction takes more time
1644
- * then an individual division, when performed in succession (with the same modulo), they're a lot faster.
1645
- *
1646
- * The two most commonly used modular reductions are Barrett and Montgomery reduction. Montgomery reduction,
1647
- * although faster, only works when the gcd of the modulo and of the base being used is 1. In RSA, when the
1648
- * base is a power of two, the modulo - a product of two primes - is always going to have a gcd of 1 (because
1649
- * the product of two odd numbers is odd), but what about when RSA isn't used?
1650
- *
1651
- * In contrast, Barrett reduction has no such constraint. As such, some bigint implementations perform a
1652
- * Barrett reduction after every operation in the modpow function. Others perform Barrett reductions when the
1653
- * modulo is even and Montgomery reductions when the modulo is odd. BigInteger.java's modPow method, however,
1654
- * uses a trick involving the Chinese Remainder Theorem to factor the even modulo into two numbers - one odd and
1655
- * the other, a power of two - and recombine them, later. This is the method that this modPow function uses.
1656
- * {@link http://islab.oregonstate.edu/papers/j34monex.pdf Montgomery Reduction with Even Modulus} elaborates.
1657
- */
1658
- function modPow($e, $n)
1659
- {
1660
- $n = $this->bitmask !== false && $this->bitmask->compare($n) < 0 ? $this->bitmask : $n->abs();
1661
-
1662
- if ($e->compare(new static()) < 0) {
1663
- $e = $e->abs();
1664
-
1665
- $temp = $this->modInverse($n);
1666
- if ($temp === false) {
1667
- return false;
1668
- }
1669
-
1670
- return $this->_normalize($temp->modPow($e, $n));
1671
- }
1672
-
1673
- if (MATH_BIGINTEGER_MODE == self::MODE_GMP) {
1674
- $temp = new static();
1675
- $temp->value = gmp_powm($this->value, $e->value, $n->value);
1676
-
1677
- return $this->_normalize($temp);
1678
- }
1679
-
1680
- if ($this->compare(new static()) < 0 || $this->compare($n) > 0) {
1681
- list(, $temp) = $this->divide($n);
1682
- return $temp->modPow($e, $n);
1683
- }
1684
-
1685
- if (defined('MATH_BIGINTEGER_OPENSSL_ENABLED')) {
1686
- $components = array(
1687
- 'modulus' => $n->toBytes(true),
1688
- 'publicExponent' => $e->toBytes(true)
1689
- );
1690
-
1691
- $components = array(
1692
- 'modulus' => pack('Ca*a*', 2, $this->_encodeASN1Length(strlen($components['modulus'])), $components['modulus']),
1693
- 'publicExponent' => pack('Ca*a*', 2, $this->_encodeASN1Length(strlen($components['publicExponent'])), $components['publicExponent'])
1694
- );
1695
-
1696
- $RSAPublicKey = pack(
1697
- 'Ca*a*a*',
1698
- 48,
1699
- $this->_encodeASN1Length(strlen($components['modulus']) + strlen($components['publicExponent'])),
1700
- $components['modulus'],
1701
- $components['publicExponent']
1702
- );
1703
-
1704
- $rsaOID = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA
1705
- $RSAPublicKey = chr(0) . $RSAPublicKey;
1706
- $RSAPublicKey = chr(3) . $this->_encodeASN1Length(strlen($RSAPublicKey)) . $RSAPublicKey;
1707
-
1708
- $encapsulated = pack(
1709
- 'Ca*a*',
1710
- 48,
1711
- $this->_encodeASN1Length(strlen($rsaOID . $RSAPublicKey)),
1712
- $rsaOID . $RSAPublicKey
1713
- );
1714
-
1715
- $RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" .
1716
- chunk_split(base64_encode($encapsulated)) .
1717
- '-----END PUBLIC KEY-----';
1718
-
1719
- $plaintext = str_pad($this->toBytes(), strlen($n->toBytes(true)) - 1, "\0", STR_PAD_LEFT);
1720
-
1721
- if (openssl_public_encrypt($plaintext, $result, $RSAPublicKey, OPENSSL_NO_PADDING)) {
1722
- return new static($result, 256);
1723
- }
1724
- }
1725
-
1726
- if (MATH_BIGINTEGER_MODE == self::MODE_BCMATH) {
1727
- $temp = new static();
1728
- $temp->value = bcpowmod($this->value, $e->value, $n->value, 0);
1729
-
1730
- return $this->_normalize($temp);
1731
- }
1732
-
1733
- if (empty($e->value)) {
1734
- $temp = new static();
1735
- $temp->value = array(1);
1736
- return $this->_normalize($temp);
1737
- }
1738
-
1739
- if ($e->value == array(1)) {
1740
- list(, $temp) = $this->divide($n);
1741
- return $this->_normalize($temp);
1742
- }
1743
-
1744
- if ($e->value == array(2)) {
1745
- $temp = new static();
1746
- $temp->value = $this->_square($this->value);
1747
- list(, $temp) = $temp->divide($n);
1748
- return $this->_normalize($temp);
1749
- }
1750
-
1751
- return $this->_normalize($this->_slidingWindow($e, $n, self::BARRETT));
1752
-
1753
- // the following code, although not callable, can be run independently of the above code
1754
- // although the above code performed better in my benchmarks the following could might
1755
- // perform better under different circumstances. in lieu of deleting it it's just been
1756
- // made uncallable
1757
-
1758
- // is the modulo odd?
1759
- if ($n->value[0] & 1) {
1760
- return $this->_normalize($this->_slidingWindow($e, $n, self::MONTGOMERY));
1761
- }
1762
- // if it's not, it's even
1763
-
1764
- // find the lowest set bit (eg. the max pow of 2 that divides $n)
1765
- for ($i = 0; $i < count($n->value); ++$i) {
1766
- if ($n->value[$i]) {
1767
- $temp = decbin($n->value[$i]);
1768
- $j = strlen($temp) - strrpos($temp, '1') - 1;
1769
- $j+= 26 * $i;
1770
- break;
1771
- }
1772
- }
1773
- // at this point, 2^$j * $n/(2^$j) == $n
1774
-
1775
- $mod1 = $n->copy();
1776
- $mod1->_rshift($j);
1777
- $mod2 = new static();
1778
- $mod2->value = array(1);
1779
- $mod2->_lshift($j);
1780
-
1781
- $part1 = ($mod1->value != array(1)) ? $this->_slidingWindow($e, $mod1, self::MONTGOMERY) : new static();
1782
- $part2 = $this->_slidingWindow($e, $mod2, self::POWEROF2);
1783
-
1784
- $y1 = $mod2->modInverse($mod1);
1785
- $y2 = $mod1->modInverse($mod2);
1786
-
1787
- $result = $part1->multiply($mod2);
1788
- $result = $result->multiply($y1);
1789
-
1790
- $temp = $part2->multiply($mod1);
1791
- $temp = $temp->multiply($y2);
1792
-
1793
- $result = $result->add($temp);
1794
- list(, $result) = $result->divide($n);
1795
-
1796
- return $this->_normalize($result);
1797
- }
1798
-
1799
- /**
1800
- * Performs modular exponentiation.
1801
- *
1802
- * Alias for modPow().
1803
- *
1804
- * @param \phpseclib\Math\BigInteger $e
1805
- * @param \phpseclib\Math\BigInteger $n
1806
- * @return \phpseclib\Math\BigInteger
1807
- * @access public
1808
- */
1809
- function powMod($e, $n)
1810
- {
1811
- return $this->modPow($e, $n);
1812
- }
1813
-
1814
- /**
1815
- * Sliding Window k-ary Modular Exponentiation
1816
- *
1817
- * Based on {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=27 HAC 14.85} /
1818
- * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=210 MPM 7.7}. In a departure from those algorithims,
1819
- * however, this function performs a modular reduction after every multiplication and squaring operation.
1820
- * As such, this function has the same preconditions that the reductions being used do.
1821
- *
1822
- * @param \phpseclib\Math\BigInteger $e
1823
- * @param \phpseclib\Math\BigInteger $n
1824
- * @param int $mode
1825
- * @return \phpseclib\Math\BigInteger
1826
- * @access private
1827
- */
1828
- function _slidingWindow($e, $n, $mode)
1829
- {
1830
- static $window_ranges = array(7, 25, 81, 241, 673, 1793); // from BigInteger.java's oddModPow function
1831
- //static $window_ranges = array(0, 7, 36, 140, 450, 1303, 3529); // from MPM 7.3.1
1832
-
1833
- $e_value = $e->value;
1834
- $e_length = count($e_value) - 1;
1835
- $e_bits = decbin($e_value[$e_length]);
1836
- for ($i = $e_length - 1; $i >= 0; --$i) {
1837
- $e_bits.= str_pad(decbin($e_value[$i]), self::$base, '0', STR_PAD_LEFT);
1838
- }
1839
-
1840
- $e_length = strlen($e_bits);
1841
-
1842
- // calculate the appropriate window size.
1843
- // $window_size == 3 if $window_ranges is between 25 and 81, for example.
1844
- for ($i = 0, $window_size = 1; $i < count($window_ranges) && $e_length > $window_ranges[$i]; ++$window_size, ++$i) {
1845
- }
1846
-
1847
- $n_value = $n->value;
1848
-
1849
- // precompute $this^0 through $this^$window_size
1850
- $powers = array();
1851
- $powers[1] = $this->_prepareReduce($this->value, $n_value, $mode);
1852
- $powers[2] = $this->_squareReduce($powers[1], $n_value, $mode);
1853
-
1854
- // we do every other number since substr($e_bits, $i, $j+1) (see below) is supposed to end
1855
- // in a 1. ie. it's supposed to be odd.
1856
- $temp = 1 << ($window_size - 1);
1857
- for ($i = 1; $i < $temp; ++$i) {
1858
- $i2 = $i << 1;
1859
- $powers[$i2 + 1] = $this->_multiplyReduce($powers[$i2 - 1], $powers[2], $n_value, $mode);
1860
- }
1861
-
1862
- $result = array(1);
1863
- $result = $this->_prepareReduce($result, $n_value, $mode);
1864
-
1865
- for ($i = 0; $i < $e_length;) {
1866
- if (!$e_bits[$i]) {
1867
- $result = $this->_squareReduce($result, $n_value, $mode);
1868
- ++$i;
1869
- } else {
1870
- for ($j = $window_size - 1; $j > 0; --$j) {
1871
- if (!empty($e_bits[$i + $j])) {
1872
- break;
1873
- }
1874
- }
1875
-
1876
- // eg. the length of substr($e_bits, $i, $j + 1)
1877
- for ($k = 0; $k <= $j; ++$k) {
1878
- $result = $this->_squareReduce($result, $n_value, $mode);
1879
- }
1880
-
1881
- $result = $this->_multiplyReduce($result, $powers[bindec(substr($e_bits, $i, $j + 1))], $n_value, $mode);
1882
-
1883
- $i += $j + 1;
1884
- }
1885
- }
1886
-
1887
- $temp = new static();
1888
- $temp->value = $this->_reduce($result, $n_value, $mode);
1889
-
1890
- return $temp;
1891
- }
1892
-
1893
- /**
1894
- * Modular reduction
1895
- *
1896
- * For most $modes this will return the remainder.
1897
- *
1898
- * @see self::_slidingWindow()
1899
- * @access private
1900
- * @param array $x
1901
- * @param array $n
1902
- * @param int $mode
1903
- * @return array
1904
- */
1905
- function _reduce($x, $n, $mode)
1906
- {
1907
- switch ($mode) {
1908
- case self::MONTGOMERY:
1909
- return $this->_montgomery($x, $n);
1910
- case self::BARRETT:
1911
- return $this->_barrett($x, $n);
1912
- case self::POWEROF2:
1913
- $lhs = new static();
1914
- $lhs->value = $x;
1915
- $rhs = new static();
1916
- $rhs->value = $n;
1917
- return $x->_mod2($n);
1918
- case self::CLASSIC:
1919
- $lhs = new static();
1920
- $lhs->value = $x;
1921
- $rhs = new static();
1922
- $rhs->value = $n;
1923
- list(, $temp) = $lhs->divide($rhs);
1924
- return $temp->value;
1925
- case self::NONE:
1926
- return $x;
1927
- default:
1928
- // an invalid $mode was provided
1929
- }
1930
- }
1931
-
1932
- /**
1933
- * Modular reduction preperation
1934
- *
1935
- * @see self::_slidingWindow()
1936
- * @access private
1937
- * @param array $x
1938
- * @param array $n
1939
- * @param int $mode
1940
- * @return array
1941
- */
1942
- function _prepareReduce($x, $n, $mode)
1943
- {
1944
- if ($mode == self::MONTGOMERY) {
1945
- return $this->_prepMontgomery($x, $n);
1946
- }
1947
- return $this->_reduce($x, $n, $mode);
1948
- }
1949
-
1950
- /**
1951
- * Modular multiply
1952
- *
1953
- * @see self::_slidingWindow()
1954
- * @access private
1955
- * @param array $x
1956
- * @param array $y
1957
- * @param array $n
1958
- * @param int $mode
1959
- * @return array
1960
- */
1961
- function _multiplyReduce($x, $y, $n, $mode)
1962
- {
1963
- if ($mode == self::MONTGOMERY) {
1964
- return $this->_montgomeryMultiply($x, $y, $n);
1965
- }
1966
- $temp = $this->_multiply($x, false, $y, false);
1967
- return $this->_reduce($temp[self::VALUE], $n, $mode);
1968
- }
1969
-
1970
- /**
1971
- * Modular square
1972
- *
1973
- * @see self::_slidingWindow()
1974
- * @access private
1975
- * @param array $x
1976
- * @param array $n
1977
- * @param int $mode
1978
- * @return array
1979
- */
1980
- function _squareReduce($x, $n, $mode)
1981
- {
1982
- if ($mode == self::MONTGOMERY) {
1983
- return $this->_montgomeryMultiply($x, $x, $n);
1984
- }
1985
- return $this->_reduce($this->_square($x), $n, $mode);
1986
- }
1987
-
1988
- /**
1989
- * Modulos for Powers of Two
1990
- *
1991
- * Calculates $x%$n, where $n = 2**$e, for some $e. Since this is basically the same as doing $x & ($n-1),
1992
- * we'll just use this function as a wrapper for doing that.
1993
- *
1994
- * @see self::_slidingWindow()
1995
- * @access private
1996
- * @param \phpseclib\Math\BigInteger
1997
- * @return \phpseclib\Math\BigInteger
1998
- */
1999
- function _mod2($n)
2000
- {
2001
- $temp = new static();
2002
- $temp->value = array(1);
2003
- return $this->bitwise_and($n->subtract($temp));
2004
- }
2005
-
2006
- /**
2007
- * Barrett Modular Reduction
2008
- *
2009
- * See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=14 HAC 14.3.3} /
2010
- * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=165 MPM 6.2.5} for more information. Modified slightly,
2011
- * so as not to require negative numbers (initially, this script didn't support negative numbers).
2012
- *
2013
- * Employs "folding", as described at
2014
- * {@link http://www.cosic.esat.kuleuven.be/publications/thesis-149.pdf#page=66 thesis-149.pdf#page=66}. To quote from
2015
- * it, "the idea [behind folding] is to find a value x' such that x (mod m) = x' (mod m), with x' being smaller than x."
2016
- *
2017
- * Unfortunately, the "Barrett Reduction with Folding" algorithm described in thesis-149.pdf is not, as written, all that
2018
- * usable on account of (1) its not using reasonable radix points as discussed in
2019
- * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=162 MPM 6.2.2} and (2) the fact that, even with reasonable
2020
- * radix points, it only works when there are an even number of digits in the denominator. The reason for (2) is that
2021
- * (x >> 1) + (x >> 1) != x / 2 + x / 2. If x is even, they're the same, but if x is odd, they're not. See the in-line
2022
- * comments for details.
2023
- *
2024
- * @see self::_slidingWindow()
2025
- * @access private
2026
- * @param array $n
2027
- * @param array $m
2028
- * @return array
2029
- */
2030
- function _barrett($n, $m)
2031
- {
2032
- static $cache = array(
2033
- self::VARIABLE => array(),
2034
- self::DATA => array()
2035
- );
2036
-
2037
- $m_length = count($m);
2038
-
2039
- // if ($this->_compare($n, $this->_square($m)) >= 0) {
2040
- if (count($n) > 2 * $m_length) {
2041
- $lhs = new static();
2042
- $rhs = new static();
2043
- $lhs->value = $n;
2044
- $rhs->value = $m;
2045
- list(, $temp) = $lhs->divide($rhs);
2046
- return $temp->value;
2047
- }
2048
-
2049
- // if (m.length >> 1) + 2 <= m.length then m is too small and n can't be reduced
2050
- if ($m_length < 5) {
2051
- return $this->_regularBarrett($n, $m);
2052
- }
2053
-
2054
- // n = 2 * m.length
2055
-
2056
- if (($key = array_search($m, $cache[self::VARIABLE])) === false) {
2057
- $key = count($cache[self::VARIABLE]);
2058
- $cache[self::VARIABLE][] = $m;
2059
-
2060
- $lhs = new static();
2061
- $lhs_value = &$lhs->value;
2062
- $lhs_value = $this->_array_repeat(0, $m_length + ($m_length >> 1));
2063
- $lhs_value[] = 1;
2064
- $rhs = new static();
2065
- $rhs->value = $m;
2066
-
2067
- list($u, $m1) = $lhs->divide($rhs);
2068
- $u = $u->value;
2069
- $m1 = $m1->value;
2070
-
2071
- $cache[self::DATA][] = array(
2072
- 'u' => $u, // m.length >> 1 (technically (m.length >> 1) + 1)
2073
- 'm1'=> $m1 // m.length
2074
- );
2075
- } else {
2076
- extract($cache[self::DATA][$key]);
2077
- }
2078
-
2079
- $cutoff = $m_length + ($m_length >> 1);
2080
- $lsd = array_slice($n, 0, $cutoff); // m.length + (m.length >> 1)
2081
- $msd = array_slice($n, $cutoff); // m.length >> 1
2082
- $lsd = $this->_trim($lsd);
2083
- $temp = $this->_multiply($msd, false, $m1, false);
2084
- $n = $this->_add($lsd, false, $temp[self::VALUE], false); // m.length + (m.length >> 1) + 1
2085
-
2086
- if ($m_length & 1) {
2087
- return $this->_regularBarrett($n[self::VALUE], $m);
2088
- }
2089
-
2090
- // (m.length + (m.length >> 1) + 1) - (m.length - 1) == (m.length >> 1) + 2
2091
- $temp = array_slice($n[self::VALUE], $m_length - 1);
2092
- // if even: ((m.length >> 1) + 2) + (m.length >> 1) == m.length + 2
2093
- // if odd: ((m.length >> 1) + 2) + (m.length >> 1) == (m.length - 1) + 2 == m.length + 1
2094
- $temp = $this->_multiply($temp, false, $u, false);
2095
- // if even: (m.length + 2) - ((m.length >> 1) + 1) = m.length - (m.length >> 1) + 1
2096
- // if odd: (m.length + 1) - ((m.length >> 1) + 1) = m.length - (m.length >> 1)
2097
- $temp = array_slice($temp[self::VALUE], ($m_length >> 1) + 1);
2098
- // if even: (m.length - (m.length >> 1) + 1) + m.length = 2 * m.length - (m.length >> 1) + 1
2099
- // if odd: (m.length - (m.length >> 1)) + m.length = 2 * m.length - (m.length >> 1)
2100
- $temp = $this->_multiply($temp, false, $m, false);
2101
-
2102
- // at this point, if m had an odd number of digits, we'd be subtracting a 2 * m.length - (m.length >> 1) digit
2103
- // number from a m.length + (m.length >> 1) + 1 digit number. ie. there'd be an extra digit and the while loop
2104
- // following this comment would loop a lot (hence our calling _regularBarrett() in that situation).
2105
-
2106
- $result = $this->_subtract($n[self::VALUE], false, $temp[self::VALUE], false);
2107
-
2108
- while ($this->_compare($result[self::VALUE], $result[self::SIGN], $m, false) >= 0) {
2109
- $result = $this->_subtract($result[self::VALUE], $result[self::SIGN], $m, false);
2110
- }
2111
-
2112
- return $result[self::VALUE];
2113
- }
2114
-
2115
- /**
2116
- * (Regular) Barrett Modular Reduction
2117
- *
2118
- * For numbers with more than four digits BigInteger::_barrett() is faster. The difference between that and this
2119
- * is that this function does not fold the denominator into a smaller form.
2120
- *
2121
- * @see self::_slidingWindow()
2122
- * @access private
2123
- * @param array $x
2124
- * @param array $n
2125
- * @return array
2126
- */
2127
- function _regularBarrett($x, $n)
2128
- {
2129
- static $cache = array(
2130
- self::VARIABLE => array(),
2131
- self::DATA => array()
2132
- );
2133
-
2134
- $n_length = count($n);
2135
-
2136
- if (count($x) > 2 * $n_length) {
2137
- $lhs = new static();
2138
- $rhs = new static();
2139
- $lhs->value = $x;
2140
- $rhs->value = $n;
2141
- list(, $temp) = $lhs->divide($rhs);
2142
- return $temp->value;
2143
- }
2144
-
2145
- if (($key = array_search($n, $cache[self::VARIABLE])) === false) {
2146
- $key = count($cache[self::VARIABLE]);
2147
- $cache[self::VARIABLE][] = $n;
2148
- $lhs = new static();
2149
- $lhs_value = &$lhs->value;
2150
- $lhs_value = $this->_array_repeat(0, 2 * $n_length);
2151
- $lhs_value[] = 1;
2152
- $rhs = new static();
2153
- $rhs->value = $n;
2154
- list($temp, ) = $lhs->divide($rhs); // m.length
2155
- $cache[self::DATA][] = $temp->value;
2156
- }
2157
-
2158
- // 2 * m.length - (m.length - 1) = m.length + 1
2159
- $temp = array_slice($x, $n_length - 1);
2160
- // (m.length + 1) + m.length = 2 * m.length + 1
2161
- $temp = $this->_multiply($temp, false, $cache[self::DATA][$key], false);
2162
- // (2 * m.length + 1) - (m.length - 1) = m.length + 2
2163
- $temp = array_slice($temp[self::VALUE], $n_length + 1);
2164
-
2165
- // m.length + 1
2166
- $result = array_slice($x, 0, $n_length + 1);
2167
- // m.length + 1
2168
- $temp = $this->_multiplyLower($temp, false, $n, false, $n_length + 1);
2169
- // $temp == array_slice($temp->_multiply($temp, false, $n, false)->value, 0, $n_length + 1)
2170
-
2171
- if ($this->_compare($result, false, $temp[self::VALUE], $temp[self::SIGN]) < 0) {
2172
- $corrector_value = $this->_array_repeat(0, $n_length + 1);
2173
- $corrector_value[count($corrector_value)] = 1;
2174
- $result = $this->_add($result, false, $corrector_value, false);
2175
- $result = $result[self::VALUE];
2176
- }
2177
-
2178
- // at this point, we're subtracting a number with m.length + 1 digits from another number with m.length + 1 digits
2179
- $result = $this->_subtract($result, false, $temp[self::VALUE], $temp[self::SIGN]);
2180
- while ($this->_compare($result[self::VALUE], $result[self::SIGN], $n, false) > 0) {
2181
- $result = $this->_subtract($result[self::VALUE], $result[self::SIGN], $n, false);
2182
- }
2183
-
2184
- return $result[self::VALUE];
2185
- }
2186
-
2187
- /**
2188
- * Performs long multiplication up to $stop digits
2189
- *
2190
- * If you're going to be doing array_slice($product->value, 0, $stop), some cycles can be saved.
2191
- *
2192
- * @see self::_regularBarrett()
2193
- * @param array $x_value
2194
- * @param bool $x_negative
2195
- * @param array $y_value
2196
- * @param bool $y_negative
2197
- * @param int $stop
2198
- * @return array
2199
- * @access private
2200
- */
2201
- function _multiplyLower($x_value, $x_negative, $y_value, $y_negative, $stop)
2202
- {
2203
- $x_length = count($x_value);
2204
- $y_length = count($y_value);
2205
-
2206
- if (!$x_length || !$y_length) { // a 0 is being multiplied
2207
- return array(
2208
- self::VALUE => array(),
2209
- self::SIGN => false
2210
- );
2211
- }
2212
-
2213
- if ($x_length < $y_length) {
2214
- $temp = $x_value;
2215
- $x_value = $y_value;
2216
- $y_value = $temp;
2217
-
2218
- $x_length = count($x_value);
2219
- $y_length = count($y_value);
2220
- }
2221
-
2222
- $product_value = $this->_array_repeat(0, $x_length + $y_length);
2223
-
2224
- // the following for loop could be removed if the for loop following it
2225
- // (the one with nested for loops) initially set $i to 0, but
2226
- // doing so would also make the result in one set of unnecessary adds,
2227
- // since on the outermost loops first pass, $product->value[$k] is going
2228
- // to always be 0
2229
-
2230
- $carry = 0;
2231
-
2232
- for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0, $k = $i
2233
- $temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0
2234
- $carry = self::$base === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
2235
- $product_value[$j] = (int) ($temp - self::$baseFull * $carry);
2236
- }
2237
-
2238
- if ($j < $stop) {
2239
- $product_value[$j] = $carry;
2240
- }
2241
-
2242
- // the above for loop is what the previous comment was talking about. the
2243
- // following for loop is the "one with nested for loops"
2244
-
2245
- for ($i = 1; $i < $y_length; ++$i) {
2246
- $carry = 0;
2247
-
2248
- for ($j = 0, $k = $i; $j < $x_length && $k < $stop; ++$j, ++$k) {
2249
- $temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry;
2250
- $carry = self::$base === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
2251
- $product_value[$k] = (int) ($temp - self::$baseFull * $carry);
2252
- }
2253
-
2254
- if ($k < $stop) {
2255
- $product_value[$k] = $carry;
2256
- }
2257
- }
2258
-
2259
- return array(
2260
- self::VALUE => $this->_trim($product_value),
2261
- self::SIGN => $x_negative != $y_negative
2262
- );
2263
- }
2264
-
2265
- /**
2266
- * Montgomery Modular Reduction
2267
- *
2268
- * ($x->_prepMontgomery($n))->_montgomery($n) yields $x % $n.
2269
- * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=170 MPM 6.3} provides insights on how this can be
2270
- * improved upon (basically, by using the comba method). gcd($n, 2) must be equal to one for this function
2271
- * to work correctly.
2272
- *
2273
- * @see self::_prepMontgomery()
2274
- * @see self::_slidingWindow()
2275
- * @access private
2276
- * @param array $x
2277
- * @param array $n
2278
- * @return array
2279
- */
2280
- function _montgomery($x, $n)
2281
- {
2282
- static $cache = array(
2283
- self::VARIABLE => array(),
2284
- self::DATA => array()
2285
- );
2286
-
2287
- if (($key = array_search($n, $cache[self::VARIABLE])) === false) {
2288
- $key = count($cache[self::VARIABLE]);
2289
- $cache[self::VARIABLE][] = $x;
2290
- $cache[self::DATA][] = $this->_modInverse67108864($n);
2291
- }
2292
-
2293
- $k = count($n);
2294
-
2295
- $result = array(self::VALUE => $x);
2296
-
2297
- for ($i = 0; $i < $k; ++$i) {
2298
- $temp = $result[self::VALUE][$i] * $cache[self::DATA][$key];
2299
- $temp = $temp - self::$baseFull * (self::$base === 26 ? intval($temp / 0x4000000) : ($temp >> 31));
2300
- $temp = $this->_regularMultiply(array($temp), $n);
2301
- $temp = array_merge($this->_array_repeat(0, $i), $temp);
2302
- $result = $this->_add($result[self::VALUE], false, $temp, false);
2303
- }
2304
-
2305
- $result[self::VALUE] = array_slice($result[self::VALUE], $k);
2306
-
2307
- if ($this->_compare($result, false, $n, false) >= 0) {
2308
- $result = $this->_subtract($result[self::VALUE], false, $n, false);
2309
- }
2310
-
2311
- return $result[self::VALUE];
2312
- }
2313
-
2314
- /**
2315
- * Montgomery Multiply
2316
- *
2317
- * Interleaves the montgomery reduction and long multiplication algorithms together as described in
2318
- * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=13 HAC 14.36}
2319
- *
2320
- * @see self::_prepMontgomery()
2321
- * @see self::_montgomery()
2322
- * @access private
2323
- * @param array $x
2324
- * @param array $y
2325
- * @param array $m
2326
- * @return array
2327
- */
2328
- function _montgomeryMultiply($x, $y, $m)
2329
- {
2330
- $temp = $this->_multiply($x, false, $y, false);
2331
- return $this->_montgomery($temp[self::VALUE], $m);
2332
-
2333
- // the following code, although not callable, can be run independently of the above code
2334
- // although the above code performed better in my benchmarks the following could might
2335
- // perform better under different circumstances. in lieu of deleting it it's just been
2336
- // made uncallable
2337
-
2338
- static $cache = array(
2339
- self::VARIABLE => array(),
2340
- self::DATA => array()
2341
- );
2342
-
2343
- if (($key = array_search($m, $cache[self::VARIABLE])) === false) {
2344
- $key = count($cache[self::VARIABLE]);
2345
- $cache[self::VARIABLE][] = $m;
2346
- $cache[self::DATA][] = $this->_modInverse67108864($m);
2347
- }
2348
-
2349
- $n = max(count($x), count($y), count($m));
2350
- $x = array_pad($x, $n, 0);
2351
- $y = array_pad($y, $n, 0);
2352
- $m = array_pad($m, $n, 0);
2353
- $a = array(self::VALUE => $this->_array_repeat(0, $n + 1));
2354
- for ($i = 0; $i < $n; ++$i) {
2355
- $temp = $a[self::VALUE][0] + $x[$i] * $y[0];
2356
- $temp = $temp - self::$baseFull * (self::$base === 26 ? intval($temp / 0x4000000) : ($temp >> 31));
2357
- $temp = $temp * $cache[self::DATA][$key];
2358
- $temp = $temp - self::$baseFull * (self::$base === 26 ? intval($temp / 0x4000000) : ($temp >> 31));
2359
- $temp = $this->_add($this->_regularMultiply(array($x[$i]), $y), false, $this->_regularMultiply(array($temp), $m), false);
2360
- $a = $this->_add($a[self::VALUE], false, $temp[self::VALUE], false);
2361
- $a[self::VALUE] = array_slice($a[self::VALUE], 1);
2362
- }
2363
- if ($this->_compare($a[self::VALUE], false, $m, false) >= 0) {
2364
- $a = $this->_subtract($a[self::VALUE], false, $m, false);
2365
- }
2366
- return $a[self::VALUE];
2367
- }
2368
-
2369
- /**
2370
- * Prepare a number for use in Montgomery Modular Reductions
2371
- *
2372
- * @see self::_montgomery()
2373
- * @see self::_slidingWindow()
2374
- * @access private
2375
- * @param array $x
2376
- * @param array $n
2377
- * @return array
2378
- */
2379
- function _prepMontgomery($x, $n)
2380
- {
2381
- $lhs = new static();
2382
- $lhs->value = array_merge($this->_array_repeat(0, count($n)), $x);
2383
- $rhs = new static();
2384
- $rhs->value = $n;
2385
-
2386
- list(, $temp) = $lhs->divide($rhs);
2387
- return $temp->value;
2388
- }
2389
-
2390
- /**
2391
- * Modular Inverse of a number mod 2**26 (eg. 67108864)
2392
- *
2393
- * Based off of the bnpInvDigit function implemented and justified in the following URL:
2394
- *
2395
- * {@link http://www-cs-students.stanford.edu/~tjw/jsbn/jsbn.js}
2396
- *
2397
- * The following URL provides more info:
2398
- *
2399
- * {@link http://groups.google.com/group/sci.crypt/msg/7a137205c1be7d85}
2400
- *
2401
- * As for why we do all the bitmasking... strange things can happen when converting from floats to ints. For
2402
- * instance, on some computers, var_dump((int) -4294967297) yields int(-1) and on others, it yields
2403
- * int(-2147483648). To avoid problems stemming from this, we use bitmasks to guarantee that ints aren't
2404
- * auto-converted to floats. The outermost bitmask is present because without it, there's no guarantee that
2405
- * the "residue" returned would be the so-called "common residue". We use fmod, in the last step, because the
2406
- * maximum possible $x is 26 bits and the maximum $result is 16 bits. Thus, we have to be able to handle up to
2407
- * 40 bits, which only 64-bit floating points will support.
2408
- *
2409
- * Thanks to Pedro Gimeno Fortea for input!
2410
- *
2411
- * @see self::_montgomery()
2412
- * @access private
2413
- * @param array $x
2414
- * @return int
2415
- */
2416
- function _modInverse67108864($x) // 2**26 == 67,108,864
2417
- {
2418
- $x = -$x[0];
2419
- $result = $x & 0x3; // x**-1 mod 2**2
2420
- $result = ($result * (2 - $x * $result)) & 0xF; // x**-1 mod 2**4
2421
- $result = ($result * (2 - ($x & 0xFF) * $result)) & 0xFF; // x**-1 mod 2**8
2422
- $result = ($result * ((2 - ($x & 0xFFFF) * $result) & 0xFFFF)) & 0xFFFF; // x**-1 mod 2**16
2423
- $result = fmod($result * (2 - fmod($x * $result, self::$baseFull)), self::$baseFull); // x**-1 mod 2**26
2424
- return $result & self::$maxDigit;
2425
- }
2426
-
2427
- /**
2428
- * Calculates modular inverses.
2429
- *
2430
- * Say you have (30 mod 17 * x mod 17) mod 17 == 1. x can be found using modular inverses.
2431
- *
2432
- * Here's an example:
2433
- * <code>
2434
- * <?php
2435
- * $a = new \phpseclib\Math\BigInteger(30);
2436
- * $b = new \phpseclib\Math\BigInteger(17);
2437
- *
2438
- * $c = $a->modInverse($b);
2439
- * echo $c->toString(); // outputs 4
2440
- *
2441
- * echo "\r\n";
2442
- *
2443
- * $d = $a->multiply($c);
2444
- * list(, $d) = $d->divide($b);
2445
- * echo $d; // outputs 1 (as per the definition of modular inverse)
2446
- * ?>
2447
- * </code>
2448
- *
2449
- * @param \phpseclib\Math\BigInteger $n
2450
- * @return \phpseclib\Math\BigInteger|false
2451
- * @access public
2452
- * @internal See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=21 HAC 14.64} for more information.
2453
- */
2454
- function modInverse($n)
2455
- {
2456
- switch (MATH_BIGINTEGER_MODE) {
2457
- case self::MODE_GMP:
2458
- $temp = new static();
2459
- $temp->value = gmp_invert($this->value, $n->value);
2460
-
2461
- return ($temp->value === false) ? false : $this->_normalize($temp);
2462
- }
2463
-
2464
- static $zero, $one;
2465
- if (!isset($zero)) {
2466
- $zero = new static();
2467
- $one = new static(1);
2468
- }
2469
-
2470
- // $x mod -$n == $x mod $n.
2471
- $n = $n->abs();
2472
-
2473
- if ($this->compare($zero) < 0) {
2474
- $temp = $this->abs();
2475
- $temp = $temp->modInverse($n);
2476
- return $this->_normalize($n->subtract($temp));
2477
- }
2478
-
2479
- extract($this->extendedGCD($n));
2480
-
2481
- if (!$gcd->equals($one)) {
2482
- return false;
2483
- }
2484
-
2485
- $x = $x->compare($zero) < 0 ? $x->add($n) : $x;
2486
-
2487
- return $this->compare($zero) < 0 ? $this->_normalize($n->subtract($x)) : $this->_normalize($x);
2488
- }
2489
-
2490
- /**
2491
- * Calculates the greatest common divisor and Bezout's identity.
2492
- *
2493
- * Say you have 693 and 609. The GCD is 21. Bezout's identity states that there exist integers x and y such that
2494
- * 693*x + 609*y == 21. In point of fact, there are actually an infinite number of x and y combinations and which
2495
- * combination is returned is dependent upon which mode is in use. See
2496
- * {@link http://en.wikipedia.org/wiki/B%C3%A9zout%27s_identity Bezout's identity - Wikipedia} for more information.
2497
- *
2498
- * Here's an example:
2499
- * <code>
2500
- * <?php
2501
- * $a = new \phpseclib\Math\BigInteger(693);
2502
- * $b = new \phpseclib\Math\BigInteger(609);
2503
- *
2504
- * extract($a->extendedGCD($b));
2505
- *
2506
- * echo $gcd->toString() . "\r\n"; // outputs 21
2507
- * echo $a->toString() * $x->toString() + $b->toString() * $y->toString(); // outputs 21
2508
- * ?>
2509
- * </code>
2510
- *
2511
- * @param \phpseclib\Math\BigInteger $n
2512
- * @return \phpseclib\Math\BigInteger
2513
- * @access public
2514
- * @internal Calculates the GCD using the binary xGCD algorithim described in
2515
- * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=19 HAC 14.61}. As the text above 14.61 notes,
2516
- * the more traditional algorithim requires "relatively costly multiple-precision divisions".
2517
- */
2518
- function extendedGCD($n)
2519
- {
2520
- switch (MATH_BIGINTEGER_MODE) {
2521
- case self::MODE_GMP:
2522
- extract(gmp_gcdext($this->value, $n->value));
2523
-
2524
- return array(
2525
- 'gcd' => $this->_normalize(new static($g)),
2526
- 'x' => $this->_normalize(new static($s)),
2527
- 'y' => $this->_normalize(new static($t))
2528
- );
2529
- case self::MODE_BCMATH:
2530
- // it might be faster to use the binary xGCD algorithim here, as well, but (1) that algorithim works
2531
- // best when the base is a power of 2 and (2) i don't think it'd make much difference, anyway. as is,
2532
- // the basic extended euclidean algorithim is what we're using.
2533
-
2534
- $u = $this->value;
2535
- $v = $n->value;
2536
-
2537
- $a = '1';
2538
- $b = '0';
2539
- $c = '0';
2540
- $d = '1';
2541
-
2542
- while (bccomp($v, '0', 0) != 0) {
2543
- $q = bcdiv($u, $v, 0);
2544
-
2545
- $temp = $u;
2546
- $u = $v;
2547
- $v = bcsub($temp, bcmul($v, $q, 0), 0);
2548
-
2549
- $temp = $a;
2550
- $a = $c;
2551
- $c = bcsub($temp, bcmul($a, $q, 0), 0);
2552
-
2553
- $temp = $b;
2554
- $b = $d;
2555
- $d = bcsub($temp, bcmul($b, $q, 0), 0);
2556
- }
2557
-
2558
- return array(
2559
- 'gcd' => $this->_normalize(new static($u)),
2560
- 'x' => $this->_normalize(new static($a)),
2561
- 'y' => $this->_normalize(new static($b))
2562
- );
2563
- }
2564
-
2565
- $y = $n->copy();
2566
- $x = $this->copy();
2567
- $g = new static();
2568
- $g->value = array(1);
2569
-
2570
- while (!(($x->value[0] & 1)|| ($y->value[0] & 1))) {
2571
- $x->_rshift(1);
2572
- $y->_rshift(1);
2573
- $g->_lshift(1);
2574
- }
2575
-
2576
- $u = $x->copy();
2577
- $v = $y->copy();
2578
-
2579
- $a = new static();
2580
- $b = new static();
2581
- $c = new static();
2582
- $d = new static();
2583
-
2584
- $a->value = $d->value = $g->value = array(1);
2585
- $b->value = $c->value = array();
2586
-
2587
- while (!empty($u->value)) {
2588
- while (!($u->value[0] & 1)) {
2589
- $u->_rshift(1);
2590
- if ((!empty($a->value) && ($a->value[0] & 1)) || (!empty($b->value) && ($b->value[0] & 1))) {
2591
- $a = $a->add($y);
2592
- $b = $b->subtract($x);
2593
- }
2594
- $a->_rshift(1);
2595
- $b->_rshift(1);
2596
- }
2597
-
2598
- while (!($v->value[0] & 1)) {
2599
- $v->_rshift(1);
2600
- if ((!empty($d->value) && ($d->value[0] & 1)) || (!empty($c->value) && ($c->value[0] & 1))) {
2601
- $c = $c->add($y);
2602
- $d = $d->subtract($x);
2603
- }
2604
- $c->_rshift(1);
2605
- $d->_rshift(1);
2606
- }
2607
-
2608
- if ($u->compare($v) >= 0) {
2609
- $u = $u->subtract($v);
2610
- $a = $a->subtract($c);
2611
- $b = $b->subtract($d);
2612
- } else {
2613
- $v = $v->subtract($u);
2614
- $c = $c->subtract($a);
2615
- $d = $d->subtract($b);
2616
- }
2617
- }
2618
-
2619
- return array(
2620
- 'gcd' => $this->_normalize($g->multiply($v)),
2621
- 'x' => $this->_normalize($c),
2622
- 'y' => $this->_normalize($d)
2623
- );
2624
- }
2625
-
2626
- /**
2627
- * Calculates the greatest common divisor
2628
- *
2629
- * Say you have 693 and 609. The GCD is 21.
2630
- *
2631
- * Here's an example:
2632
- * <code>
2633
- * <?php
2634
- * $a = new \phpseclib\Math\BigInteger(693);
2635
- * $b = new \phpseclib\Math\BigInteger(609);
2636
- *
2637
- * $gcd = a->extendedGCD($b);
2638
- *
2639
- * echo $gcd->toString() . "\r\n"; // outputs 21
2640
- * ?>
2641
- * </code>
2642
- *
2643
- * @param \phpseclib\Math\BigInteger $n
2644
- * @return \phpseclib\Math\BigInteger
2645
- * @access public
2646
- */
2647
- function gcd($n)
2648
- {
2649
- extract($this->extendedGCD($n));
2650
- return $gcd;
2651
- }
2652
-
2653
- /**
2654
- * Absolute value.
2655
- *
2656
- * @return \phpseclib\Math\BigInteger
2657
- * @access public
2658
- */
2659
- function abs()
2660
- {
2661
- $temp = new static();
2662
-
2663
- switch (MATH_BIGINTEGER_MODE) {
2664
- case self::MODE_GMP:
2665
- $temp->value = gmp_abs($this->value);
2666
- break;
2667
- case self::MODE_BCMATH:
2668
- $temp->value = (bccomp($this->value, '0', 0) < 0) ? substr($this->value, 1) : $this->value;
2669
- break;
2670
- default:
2671
- $temp->value = $this->value;
2672
- }
2673
-
2674
- return $temp;
2675
- }
2676
-
2677
- /**
2678
- * Compares two numbers.
2679
- *
2680
- * Although one might think !$x->compare($y) means $x != $y, it, in fact, means the opposite. The reason for this is
2681
- * demonstrated thusly:
2682
- *
2683
- * $x > $y: $x->compare($y) > 0
2684
- * $x < $y: $x->compare($y) < 0
2685
- * $x == $y: $x->compare($y) == 0
2686
- *
2687
- * Note how the same comparison operator is used. If you want to test for equality, use $x->equals($y).
2688
- *
2689
- * @param \phpseclib\Math\BigInteger $y
2690
- * @return int < 0 if $this is less than $y; > 0 if $this is greater than $y, and 0 if they are equal.
2691
- * @access public
2692
- * @see self::equals()
2693
- * @internal Could return $this->subtract($x), but that's not as fast as what we do do.
2694
- */
2695
- function compare($y)
2696
- {
2697
- switch (MATH_BIGINTEGER_MODE) {
2698
- case self::MODE_GMP:
2699
- $r = gmp_cmp($this->value, $y->value);
2700
- if ($r < -1) {
2701
- $r = -1;
2702
- }
2703
- if ($r > 1) {
2704
- $r = 1;
2705
- }
2706
- return $r;
2707
- case self::MODE_BCMATH:
2708
- return bccomp($this->value, $y->value, 0);
2709
- }
2710
-
2711
- return $this->_compare($this->value, $this->is_negative, $y->value, $y->is_negative);
2712
- }
2713
-
2714
- /**
2715
- * Compares two numbers.
2716
- *
2717
- * @param array $x_value
2718
- * @param bool $x_negative
2719
- * @param array $y_value
2720
- * @param bool $y_negative
2721
- * @return int
2722
- * @see self::compare()
2723
- * @access private
2724
- */
2725
- function _compare($x_value, $x_negative, $y_value, $y_negative)
2726
- {
2727
- if ($x_negative != $y_negative) {
2728
- return (!$x_negative && $y_negative) ? 1 : -1;
2729
- }
2730
-
2731
- $result = $x_negative ? -1 : 1;
2732
-
2733
- if (count($x_value) != count($y_value)) {
2734
- return (count($x_value) > count($y_value)) ? $result : -$result;
2735
- }
2736
- $size = max(count($x_value), count($y_value));
2737
-
2738
- $x_value = array_pad($x_value, $size, 0);
2739
- $y_value = array_pad($y_value, $size, 0);
2740
-
2741
- for ($i = count($x_value) - 1; $i >= 0; --$i) {
2742
- if ($x_value[$i] != $y_value[$i]) {
2743
- return ($x_value[$i] > $y_value[$i]) ? $result : -$result;
2744
- }
2745
- }
2746
-
2747
- return 0;
2748
- }
2749
-
2750
- /**
2751
- * Tests the equality of two numbers.
2752
- *
2753
- * If you need to see if one number is greater than or less than another number, use BigInteger::compare()
2754
- *
2755
- * @param \phpseclib\Math\BigInteger $x
2756
- * @return bool
2757
- * @access public
2758
- * @see self::compare()
2759
- */
2760
- function equals($x)
2761
- {
2762
- switch (MATH_BIGINTEGER_MODE) {
2763
- case self::MODE_GMP:
2764
- return gmp_cmp($this->value, $x->value) == 0;
2765
- default:
2766
- return $this->value === $x->value && $this->is_negative == $x->is_negative;
2767
- }
2768
- }
2769
-
2770
- /**
2771
- * Set Precision
2772
- *
2773
- * Some bitwise operations give different results depending on the precision being used. Examples include left
2774
- * shift, not, and rotates.
2775
- *
2776
- * @param int $bits
2777
- * @access public
2778
- */
2779
- function setPrecision($bits)
2780
- {
2781
- $this->precision = $bits;
2782
- if (MATH_BIGINTEGER_MODE != self::MODE_BCMATH) {
2783
- $this->bitmask = new static(chr((1 << ($bits & 0x7)) - 1) . str_repeat(chr(0xFF), $bits >> 3), 256);
2784
- } else {
2785
- $this->bitmask = new static(bcpow('2', $bits, 0));
2786
- }
2787
-
2788
- $temp = $this->_normalize($this);
2789
- $this->value = $temp->value;
2790
- }
2791
-
2792
- /**
2793
- * Logical And
2794
- *
2795
- * @param \phpseclib\Math\BigInteger $x
2796
- * @access public
2797
- * @internal Implemented per a request by Lluis Pamies i Juarez <lluis _a_ pamies.cat>
2798
- * @return \phpseclib\Math\BigInteger
2799
- */
2800
- function bitwise_and($x)
2801
- {
2802
- switch (MATH_BIGINTEGER_MODE) {
2803
- case self::MODE_GMP:
2804
- $temp = new static();
2805
- $temp->value = gmp_and($this->value, $x->value);
2806
-
2807
- return $this->_normalize($temp);
2808
- case self::MODE_BCMATH:
2809
- $left = $this->toBytes();
2810
- $right = $x->toBytes();
2811
-
2812
- $length = max(strlen($left), strlen($right));
2813
-
2814
- $left = str_pad($left, $length, chr(0), STR_PAD_LEFT);
2815
- $right = str_pad($right, $length, chr(0), STR_PAD_LEFT);
2816
-
2817
- return $this->_normalize(new static($left & $right, 256));
2818
- }
2819
-
2820
- $result = $this->copy();
2821
-
2822
- $length = min(count($x->value), count($this->value));
2823
-
2824
- $result->value = array_slice($result->value, 0, $length);
2825
-
2826
- for ($i = 0; $i < $length; ++$i) {
2827
- $result->value[$i]&= $x->value[$i];
2828
- }
2829
-
2830
- return $this->_normalize($result);
2831
- }
2832
-
2833
- /**
2834
- * Logical Or
2835
- *
2836
- * @param \phpseclib\Math\BigInteger $x
2837
- * @access public
2838
- * @internal Implemented per a request by Lluis Pamies i Juarez <lluis _a_ pamies.cat>
2839
- * @return \phpseclib\Math\BigInteger
2840
- */
2841
- function bitwise_or($x)
2842
- {
2843
- switch (MATH_BIGINTEGER_MODE) {
2844
- case self::MODE_GMP:
2845
- $temp = new static();
2846
- $temp->value = gmp_or($this->value, $x->value);
2847
-
2848
- return $this->_normalize($temp);
2849
- case self::MODE_BCMATH:
2850
- $left = $this->toBytes();
2851
- $right = $x->toBytes();
2852
-
2853
- $length = max(strlen($left), strlen($right));
2854
-
2855
- $left = str_pad($left, $length, chr(0), STR_PAD_LEFT);
2856
- $right = str_pad($right, $length, chr(0), STR_PAD_LEFT);
2857
-
2858
- return $this->_normalize(new static($left | $right, 256));
2859
- }
2860
-
2861
- $length = max(count($this->value), count($x->value));
2862
- $result = $this->copy();
2863
- $result->value = array_pad($result->value, $length, 0);
2864
- $x->value = array_pad($x->value, $length, 0);
2865
-
2866
- for ($i = 0; $i < $length; ++$i) {
2867
- $result->value[$i]|= $x->value[$i];
2868
- }
2869
-
2870
- return $this->_normalize($result);
2871
- }
2872
-
2873
- /**
2874
- * Logical Exclusive-Or
2875
- *
2876
- * @param \phpseclib\Math\BigInteger $x
2877
- * @access public
2878
- * @internal Implemented per a request by Lluis Pamies i Juarez <lluis _a_ pamies.cat>
2879
- * @return \phpseclib\Math\BigInteger
2880
- */
2881
- function bitwise_xor($x)
2882
- {
2883
- switch (MATH_BIGINTEGER_MODE) {
2884
- case self::MODE_GMP:
2885
- $temp = new static();
2886
- $temp->value = gmp_xor(gmp_abs($this->value), gmp_abs($x->value));
2887
- return $this->_normalize($temp);
2888
- case self::MODE_BCMATH:
2889
- $left = $this->toBytes();
2890
- $right = $x->toBytes();
2891
-
2892
- $length = max(strlen($left), strlen($right));
2893
-
2894
- $left = str_pad($left, $length, chr(0), STR_PAD_LEFT);
2895
- $right = str_pad($right, $length, chr(0), STR_PAD_LEFT);
2896
-
2897
- return $this->_normalize(new static($left ^ $right, 256));
2898
- }
2899
-
2900
- $length = max(count($this->value), count($x->value));
2901
- $result = $this->copy();
2902
- $result->is_negative = false;
2903
- $result->value = array_pad($result->value, $length, 0);
2904
- $x->value = array_pad($x->value, $length, 0);
2905
-
2906
- for ($i = 0; $i < $length; ++$i) {
2907
- $result->value[$i]^= $x->value[$i];
2908
- }
2909
-
2910
- return $this->_normalize($result);
2911
- }
2912
-
2913
- /**
2914
- * Logical Not
2915
- *
2916
- * @access public
2917
- * @internal Implemented per a request by Lluis Pamies i Juarez <lluis _a_ pamies.cat>
2918
- * @return \phpseclib\Math\BigInteger
2919
- */
2920
- function bitwise_not()
2921
- {
2922
- // calculuate "not" without regard to $this->precision
2923
- // (will always result in a smaller number. ie. ~1 isn't 1111 1110 - it's 0)
2924
- $temp = $this->toBytes();
2925
- if ($temp == '') {
2926
- return $this->_normalize(new static());
2927
- }
2928
- $pre_msb = decbin(ord($temp[0]));
2929
- $temp = ~$temp;
2930
- $msb = decbin(ord($temp[0]));
2931
- if (strlen($msb) == 8) {
2932
- $msb = substr($msb, strpos($msb, '0'));
2933
- }
2934
- $temp[0] = chr(bindec($msb));
2935
-
2936
- // see if we need to add extra leading 1's
2937
- $current_bits = strlen($pre_msb) + 8 * strlen($temp) - 8;
2938
- $new_bits = $this->precision - $current_bits;
2939
- if ($new_bits <= 0) {
2940
- return $this->_normalize(new static($temp, 256));
2941
- }
2942
-
2943
- // generate as many leading 1's as we need to.
2944
- $leading_ones = chr((1 << ($new_bits & 0x7)) - 1) . str_repeat(chr(0xFF), $new_bits >> 3);
2945
- $this->_base256_lshift($leading_ones, $current_bits);
2946
-
2947
- $temp = str_pad($temp, strlen($leading_ones), chr(0), STR_PAD_LEFT);
2948
-
2949
- return $this->_normalize(new static($leading_ones | $temp, 256));
2950
- }
2951
-
2952
- /**
2953
- * Logical Right Shift
2954
- *
2955
- * Shifts BigInteger's by $shift bits, effectively dividing by 2**$shift.
2956
- *
2957
- * @param int $shift
2958
- * @return \phpseclib\Math\BigInteger
2959
- * @access public
2960
- * @internal The only version that yields any speed increases is the internal version.
2961
- */
2962
- function bitwise_rightShift($shift)
2963
- {
2964
- $temp = new static();
2965
-
2966
- switch (MATH_BIGINTEGER_MODE) {
2967
- case self::MODE_GMP:
2968
- static $two;
2969
-
2970
- if (!isset($two)) {
2971
- $two = gmp_init('2');
2972
- }
2973
-
2974
- $temp->value = gmp_div_q($this->value, gmp_pow($two, $shift));
2975
-
2976
- break;
2977
- case self::MODE_BCMATH:
2978
- $temp->value = bcdiv($this->value, bcpow('2', $shift, 0), 0);
2979
-
2980
- break;
2981
- default: // could just replace _lshift with this, but then all _lshift() calls would need to be rewritten
2982
- // and I don't want to do that...
2983
- $temp->value = $this->value;
2984
- $temp->_rshift($shift);
2985
- }
2986
-
2987
- return $this->_normalize($temp);
2988
- }
2989
-
2990
- /**
2991
- * Logical Left Shift
2992
- *
2993
- * Shifts BigInteger's by $shift bits, effectively multiplying by 2**$shift.
2994
- *
2995
- * @param int $shift
2996
- * @return \phpseclib\Math\BigInteger
2997
- * @access public
2998
- * @internal The only version that yields any speed increases is the internal version.
2999
- */
3000
- function bitwise_leftShift($shift)
3001
- {
3002
- $temp = new static();
3003
-
3004
- switch (MATH_BIGINTEGER_MODE) {
3005
- case self::MODE_GMP:
3006
- static $two;
3007
-
3008
- if (!isset($two)) {
3009
- $two = gmp_init('2');
3010
- }
3011
-
3012
- $temp->value = gmp_mul($this->value, gmp_pow($two, $shift));
3013
-
3014
- break;
3015
- case self::MODE_BCMATH:
3016
- $temp->value = bcmul($this->value, bcpow('2', $shift, 0), 0);
3017
-
3018
- break;
3019
- default: // could just replace _rshift with this, but then all _lshift() calls would need to be rewritten
3020
- // and I don't want to do that...
3021
- $temp->value = $this->value;
3022
- $temp->_lshift($shift);
3023
- }
3024
-
3025
- return $this->_normalize($temp);
3026
- }
3027
-
3028
- /**
3029
- * Logical Left Rotate
3030
- *
3031
- * Instead of the top x bits being dropped they're appended to the shifted bit string.
3032
- *
3033
- * @param int $shift
3034
- * @return \phpseclib\Math\BigInteger
3035
- * @access public
3036
- */
3037
- function bitwise_leftRotate($shift)
3038
- {
3039
- $bits = $this->toBytes();
3040
-
3041
- if ($this->precision > 0) {
3042
- $precision = $this->precision;
3043
- if (MATH_BIGINTEGER_MODE == self::MODE_BCMATH) {
3044
- $mask = $this->bitmask->subtract(new static(1));
3045
- $mask = $mask->toBytes();
3046
- } else {
3047
- $mask = $this->bitmask->toBytes();
3048
- }
3049
- } else {
3050
- $temp = ord($bits[0]);
3051
- for ($i = 0; $temp >> $i; ++$i) {
3052
- }
3053
- $precision = 8 * strlen($bits) - 8 + $i;
3054
- $mask = chr((1 << ($precision & 0x7)) - 1) . str_repeat(chr(0xFF), $precision >> 3);
3055
- }
3056
-
3057
- if ($shift < 0) {
3058
- $shift+= $precision;
3059
- }
3060
- $shift%= $precision;
3061
-
3062
- if (!$shift) {
3063
- return $this->copy();
3064
- }
3065
-
3066
- $left = $this->bitwise_leftShift($shift);
3067
- $left = $left->bitwise_and(new static($mask, 256));
3068
- $right = $this->bitwise_rightShift($precision - $shift);
3069
- $result = MATH_BIGINTEGER_MODE != self::MODE_BCMATH ? $left->bitwise_or($right) : $left->add($right);
3070
- return $this->_normalize($result);
3071
- }
3072
-
3073
- /**
3074
- * Logical Right Rotate
3075
- *
3076
- * Instead of the bottom x bits being dropped they're prepended to the shifted bit string.
3077
- *
3078
- * @param int $shift
3079
- * @return \phpseclib\Math\BigInteger
3080
- * @access public
3081
- */
3082
- function bitwise_rightRotate($shift)
3083
- {
3084
- return $this->bitwise_leftRotate(-$shift);
3085
- }
3086
-
3087
- /**
3088
- * Generates a random BigInteger
3089
- *
3090
- * Byte length is equal to $length. Uses \phpseclib\Crypt\Random if it's loaded and mt_rand if it's not.
3091
- *
3092
- * @param int $length
3093
- * @return \phpseclib\Math\BigInteger
3094
- * @access private
3095
- */
3096
- function _random_number_helper($size)
3097
- {
3098
- if (class_exists('\phpseclib\Crypt\Random')) {
3099
- $random = Random::string($size);
3100
- } else {
3101
- $random = '';
3102
-
3103
- if ($size & 1) {
3104
- $random.= chr(mt_rand(0, 255));
3105
- }
3106
-
3107
- $blocks = $size >> 1;
3108
- for ($i = 0; $i < $blocks; ++$i) {
3109
- // mt_rand(-2147483648, 0x7FFFFFFF) always produces -2147483648 on some systems
3110
- $random.= pack('n', mt_rand(0, 0xFFFF));
3111
- }
3112
- }
3113
-
3114
- return new static($random, 256);
3115
- }
3116
-
3117
- /**
3118
- * Generate a random number
3119
- *
3120
- * Returns a random number between $min and $max where $min and $max
3121
- * can be defined using one of the two methods:
3122
- *
3123
- * $min->random($max)
3124
- * $max->random($min)
3125
- *
3126
- * @param \phpseclib\Math\BigInteger $arg1
3127
- * @param \phpseclib\Math\BigInteger $arg2
3128
- * @return \phpseclib\Math\BigInteger
3129
- * @access public
3130
- * @internal The API for creating random numbers used to be $a->random($min, $max), where $a was a BigInteger object.
3131
- * That method is still supported for BC purposes.
3132
- */
3133
- function random($arg1, $arg2 = false)
3134
- {
3135
- if ($arg1 === false) {
3136
- return false;
3137
- }
3138
-
3139
- if ($arg2 === false) {
3140
- $max = $arg1;
3141
- $min = $this;
3142
- } else {
3143
- $min = $arg1;
3144
- $max = $arg2;
3145
- }
3146
-
3147
- $compare = $max->compare($min);
3148
-
3149
- if (!$compare) {
3150
- return $this->_normalize($min);
3151
- } elseif ($compare < 0) {
3152
- // if $min is bigger then $max, swap $min and $max
3153
- $temp = $max;
3154
- $max = $min;
3155
- $min = $temp;
3156
- }
3157
-
3158
- static $one;
3159
- if (!isset($one)) {
3160
- $one = new static(1);
3161
- }
3162
-
3163
- $max = $max->subtract($min->subtract($one));
3164
- $size = strlen(ltrim($max->toBytes(), chr(0)));
3165
-
3166
- /*
3167
- doing $random % $max doesn't work because some numbers will be more likely to occur than others.
3168
- eg. if $max is 140 and $random's max is 255 then that'd mean both $random = 5 and $random = 145
3169
- would produce 5 whereas the only value of random that could produce 139 would be 139. ie.
3170
- not all numbers would be equally likely. some would be more likely than others.
3171
-
3172
- creating a whole new random number until you find one that is within the range doesn't work
3173
- because, for sufficiently small ranges, the likelihood that you'd get a number within that range
3174
- would be pretty small. eg. with $random's max being 255 and if your $max being 1 the probability
3175
- would be pretty high that $random would be greater than $max.
3176
-
3177
- phpseclib works around this using the technique described here:
3178
-
3179
- http://crypto.stackexchange.com/questions/5708/creating-a-small-number-from-a-cryptographically-secure-random-string
3180
- */
3181
- $random_max = new static(chr(1) . str_repeat("\0", $size), 256);
3182
- $random = $this->_random_number_helper($size);
3183
-
3184
- list($max_multiple) = $random_max->divide($max);
3185
- $max_multiple = $max_multiple->multiply($max);
3186
-
3187
- while ($random->compare($max_multiple) >= 0) {
3188
- $random = $random->subtract($max_multiple);
3189
- $random_max = $random_max->subtract($max_multiple);
3190
- $random = $random->bitwise_leftShift(8);
3191
- $random = $random->add($this->_random_number_helper(1));
3192
- $random_max = $random_max->bitwise_leftShift(8);
3193
- list($max_multiple) = $random_max->divide($max);
3194
- $max_multiple = $max_multiple->multiply($max);
3195
- }
3196
- list(, $random) = $random->divide($max);
3197
-
3198
- return $this->_normalize($random->add($min));
3199
- }
3200
-
3201
- /**
3202
- * Generate a random prime number.
3203
- *
3204
- * If there's not a prime within the given range, false will be returned.
3205
- * If more than $timeout seconds have elapsed, give up and return false.
3206
- *
3207
- * @param \phpseclib\Math\BigInteger $arg1
3208
- * @param \phpseclib\Math\BigInteger $arg2
3209
- * @param int $timeout
3210
- * @return Math_BigInteger|false
3211
- * @access public
3212
- * @internal See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap4.pdf#page=15 HAC 4.44}.
3213
- */
3214
- function randomPrime($arg1, $arg2 = false, $timeout = false)
3215
- {
3216
- if ($arg1 === false) {
3217
- return false;
3218
- }
3219
-
3220
- if ($arg2 === false) {
3221
- $max = $arg1;
3222
- $min = $this;
3223
- } else {
3224
- $min = $arg1;
3225
- $max = $arg2;
3226
- }
3227
-
3228
- $compare = $max->compare($min);
3229
-
3230
- if (!$compare) {
3231
- return $min->isPrime() ? $min : false;
3232
- } elseif ($compare < 0) {
3233
- // if $min is bigger then $max, swap $min and $max
3234
- $temp = $max;
3235
- $max = $min;
3236
- $min = $temp;
3237
- }
3238
-
3239
- static $one, $two;
3240
- if (!isset($one)) {
3241
- $one = new static(1);
3242
- $two = new static(2);
3243
- }
3244
-
3245
- $start = time();
3246
-
3247
- $x = $this->random($min, $max);
3248
-
3249
- // gmp_nextprime() requires PHP 5 >= 5.2.0 per <http://php.net/gmp-nextprime>.
3250
- if (MATH_BIGINTEGER_MODE == self::MODE_GMP && extension_loaded('gmp')) {
3251
- $p = new static();
3252
- $p->value = gmp_nextprime($x->value);
3253
-
3254
- if ($p->compare($max) <= 0) {
3255
- return $p;
3256
- }
3257
-
3258
- if (!$min->equals($x)) {
3259
- $x = $x->subtract($one);
3260
- }
3261
-
3262
- return $x->randomPrime($min, $x);
3263
- }
3264
-
3265
- if ($x->equals($two)) {
3266
- return $x;
3267
- }
3268
-
3269
- $x->_make_odd();
3270
- if ($x->compare($max) > 0) {
3271
- // if $x > $max then $max is even and if $min == $max then no prime number exists between the specified range
3272
- if ($min->equals($max)) {
3273
- return false;
3274
- }
3275
- $x = $min->copy();
3276
- $x->_make_odd();
3277
- }
3278
-
3279
- $initial_x = $x->copy();
3280
-
3281
- while (true) {
3282
- if ($timeout !== false && time() - $start > $timeout) {
3283
- return false;
3284
- }
3285
-
3286
- if ($x->isPrime()) {
3287
- return $x;
3288
- }
3289
-
3290
- $x = $x->add($two);
3291
-
3292
- if ($x->compare($max) > 0) {
3293
- $x = $min->copy();
3294
- if ($x->equals($two)) {
3295
- return $x;
3296
- }
3297
- $x->_make_odd();
3298
- }
3299
-
3300
- if ($x->equals($initial_x)) {
3301
- return false;
3302
- }
3303
- }
3304
- }
3305
-
3306
- /**
3307
- * Make the current number odd
3308
- *
3309
- * If the current number is odd it'll be unchanged. If it's even, one will be added to it.
3310
- *
3311
- * @see self::randomPrime()
3312
- * @access private
3313
- */
3314
- function _make_odd()
3315
- {
3316
- switch (MATH_BIGINTEGER_MODE) {
3317
- case self::MODE_GMP:
3318
- gmp_setbit($this->value, 0);
3319
- break;
3320
- case self::MODE_BCMATH:
3321
- if ($this->value[strlen($this->value) - 1] % 2 == 0) {
3322
- $this->value = bcadd($this->value, '1');
3323
- }
3324
- break;
3325
- default:
3326
- $this->value[0] |= 1;
3327
- }
3328
- }
3329
-
3330
- /**
3331
- * Checks a numer to see if it's prime
3332
- *
3333
- * Assuming the $t parameter is not set, this function has an error rate of 2**-80. The main motivation for the
3334
- * $t parameter is distributability. BigInteger::randomPrime() can be distributed across multiple pageloads
3335
- * on a website instead of just one.
3336
- *
3337
- * @param \phpseclib\Math\BigInteger $t
3338
- * @return bool
3339
- * @access public
3340
- * @internal Uses the
3341
- * {@link http://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test Miller-Rabin primality test}. See
3342
- * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap4.pdf#page=8 HAC 4.24}.
3343
- */
3344
- function isPrime($t = false)
3345
- {
3346
- $length = strlen($this->toBytes());
3347
-
3348
- if (!$t) {
3349
- // see HAC 4.49 "Note (controlling the error probability)"
3350
- // @codingStandardsIgnoreStart
3351
- if ($length >= 163) { $t = 2; } // floor(1300 / 8)
3352
- else if ($length >= 106) { $t = 3; } // floor( 850 / 8)
3353
- else if ($length >= 81 ) { $t = 4; } // floor( 650 / 8)
3354
- else if ($length >= 68 ) { $t = 5; } // floor( 550 / 8)
3355
- else if ($length >= 56 ) { $t = 6; } // floor( 450 / 8)
3356
- else if ($length >= 50 ) { $t = 7; } // floor( 400 / 8)
3357
- else if ($length >= 43 ) { $t = 8; } // floor( 350 / 8)
3358
- else if ($length >= 37 ) { $t = 9; } // floor( 300 / 8)
3359
- else if ($length >= 31 ) { $t = 12; } // floor( 250 / 8)
3360
- else if ($length >= 25 ) { $t = 15; } // floor( 200 / 8)
3361
- else if ($length >= 18 ) { $t = 18; } // floor( 150 / 8)
3362
- else { $t = 27; }
3363
- // @codingStandardsIgnoreEnd
3364
- }
3365
-
3366
- // ie. gmp_testbit($this, 0)
3367
- // ie. isEven() or !isOdd()
3368
- switch (MATH_BIGINTEGER_MODE) {
3369
- case self::MODE_GMP:
3370
- return gmp_prob_prime($this->value, $t) != 0;
3371
- case self::MODE_BCMATH:
3372
- if ($this->value === '2') {
3373
- return true;
3374
- }
3375
- if ($this->value[strlen($this->value) - 1] % 2 == 0) {
3376
- return false;
3377
- }
3378
- break;
3379
- default:
3380
- if ($this->value == array(2)) {
3381
- return true;
3382
- }
3383
- if (~$this->value[0] & 1) {
3384
- return false;
3385
- }
3386
- }
3387
-
3388
- static $primes, $zero, $one, $two;
3389
-
3390
- if (!isset($primes)) {
3391
- $primes = array(
3392
- 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59,
3393
- 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137,
3394
- 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227,
3395
- 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313,
3396
- 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419,
3397
- 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509,
3398
- 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617,
3399
- 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727,
3400
- 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829,
3401
- 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947,
3402
- 953, 967, 971, 977, 983, 991, 997
3403
- );
3404
-
3405
- if (MATH_BIGINTEGER_MODE != self::MODE_INTERNAL) {
3406
- for ($i = 0; $i < count($primes); ++$i) {
3407
- $primes[$i] = new static($primes[$i]);
3408
- }
3409
- }
3410
-
3411
- $zero = new static();
3412
- $one = new static(1);
3413
- $two = new static(2);
3414
- }
3415
-
3416
- if ($this->equals($one)) {
3417
- return false;
3418
- }
3419
-
3420
- // see HAC 4.4.1 "Random search for probable primes"
3421
- if (MATH_BIGINTEGER_MODE != self::MODE_INTERNAL) {
3422
- foreach ($primes as $prime) {
3423
- list(, $r) = $this->divide($prime);
3424
- if ($r->equals($zero)) {
3425
- return $this->equals($prime);
3426
- }
3427
- }
3428
- } else {
3429
- $value = $this->value;
3430
- foreach ($primes as $prime) {
3431
- list(, $r) = $this->_divide_digit($value, $prime);
3432
- if (!$r) {
3433
- return count($value) == 1 && $value[0] == $prime;
3434
- }
3435
- }
3436
- }
3437
-
3438
- $n = $this->copy();
3439
- $n_1 = $n->subtract($one);
3440
- $n_2 = $n->subtract($two);
3441
-
3442
- $r = $n_1->copy();
3443
- $r_value = $r->value;
3444
- // ie. $s = gmp_scan1($n, 0) and $r = gmp_div_q($n, gmp_pow(gmp_init('2'), $s));
3445
- if (MATH_BIGINTEGER_MODE == self::MODE_BCMATH) {
3446
- $s = 0;
3447
- // if $n was 1, $r would be 0 and this would be an infinite loop, hence our $this->equals($one) check earlier
3448
- while ($r->value[strlen($r->value) - 1] % 2 == 0) {
3449
- $r->value = bcdiv($r->value, '2', 0);
3450
- ++$s;
3451
- }
3452
- } else {
3453
- for ($i = 0, $r_length = count($r_value); $i < $r_length; ++$i) {
3454
- $temp = ~$r_value[$i] & 0xFFFFFF;
3455
- for ($j = 1; ($temp >> $j) & 1; ++$j) {
3456
- }
3457
- if ($j != 25) {
3458
- break;
3459
- }
3460
- }
3461
- $s = 26 * $i + $j;
3462
- $r->_rshift($s);
3463
- }
3464
-
3465
- for ($i = 0; $i < $t; ++$i) {
3466
- $a = $this->random($two, $n_2);
3467
- $y = $a->modPow($r, $n);
3468
-
3469
- if (!$y->equals($one) && !$y->equals($n_1)) {
3470
- for ($j = 1; $j < $s && !$y->equals($n_1); ++$j) {
3471
- $y = $y->modPow($two, $n);
3472
- if ($y->equals($one)) {
3473
- return false;
3474
- }
3475
- }
3476
-
3477
- if (!$y->equals($n_1)) {
3478
- return false;
3479
- }
3480
- }
3481
- }
3482
- return true;
3483
- }
3484
-
3485
- /**
3486
- * Logical Left Shift
3487
- *
3488
- * Shifts BigInteger's by $shift bits.
3489
- *
3490
- * @param int $shift
3491
- * @access private
3492
- */
3493
- function _lshift($shift)
3494
- {
3495
- if ($shift == 0) {
3496
- return;
3497
- }
3498
-
3499
- $num_digits = (int) ($shift / self::$base);
3500
- $shift %= self::$base;
3501
- $shift = 1 << $shift;
3502
-
3503
- $carry = 0;
3504
-
3505
- for ($i = 0; $i < count($this->value); ++$i) {
3506
- $temp = $this->value[$i] * $shift + $carry;
3507
- $carry = self::$base === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
3508
- $this->value[$i] = (int) ($temp - $carry * self::$baseFull);
3509
- }
3510
-
3511
- if ($carry) {
3512
- $this->value[count($this->value)] = $carry;
3513
- }
3514
-
3515
- while ($num_digits--) {
3516
- array_unshift($this->value, 0);
3517
- }
3518
- }
3519
-
3520
- /**
3521
- * Logical Right Shift
3522
- *
3523
- * Shifts BigInteger's by $shift bits.
3524
- *
3525
- * @param int $shift
3526
- * @access private
3527
- */
3528
- function _rshift($shift)
3529
- {
3530
- if ($shift == 0) {
3531
- return;
3532
- }
3533
-
3534
- $num_digits = (int) ($shift / self::$base);
3535
- $shift %= self::$base;
3536
- $carry_shift = self::$base - $shift;
3537
- $carry_mask = (1 << $shift) - 1;
3538
-
3539
- if ($num_digits) {
3540
- $this->value = array_slice($this->value, $num_digits);
3541
- }
3542
-
3543
- $carry = 0;
3544
-
3545
- for ($i = count($this->value) - 1; $i >= 0; --$i) {
3546
- $temp = $this->value[$i] >> $shift | $carry;
3547
- $carry = ($this->value[$i] & $carry_mask) << $carry_shift;
3548
- $this->value[$i] = $temp;
3549
- }
3550
-
3551
- $this->value = $this->_trim($this->value);
3552
- }
3553
-
3554
- /**
3555
- * Normalize
3556
- *
3557
- * Removes leading zeros and truncates (if necessary) to maintain the appropriate precision
3558
- *
3559
- * @param \phpseclib\Math\BigInteger
3560
- * @return \phpseclib\Math\BigInteger
3561
- * @see self::_trim()
3562
- * @access private
3563
- */
3564
- function _normalize($result)
3565
- {
3566
- $result->precision = $this->precision;
3567
- $result->bitmask = $this->bitmask;
3568
-
3569
- switch (MATH_BIGINTEGER_MODE) {
3570
- case self::MODE_GMP:
3571
- if ($this->bitmask !== false) {
3572
- $result->value = gmp_and($result->value, $result->bitmask->value);
3573
- }
3574
-
3575
- return $result;
3576
- case self::MODE_BCMATH:
3577
- if (!empty($result->bitmask->value)) {
3578
- $result->value = bcmod($result->value, $result->bitmask->value);
3579
- }
3580
-
3581
- return $result;
3582
- }
3583
-
3584
- $value = &$result->value;
3585
-
3586
- if (!count($value)) {
3587
- $result->is_negative = false;
3588
- return $result;
3589
- }
3590
-
3591
- $value = $this->_trim($value);
3592
-
3593
- if (!empty($result->bitmask->value)) {
3594
- $length = min(count($value), count($this->bitmask->value));
3595
- $value = array_slice($value, 0, $length);
3596
-
3597
- for ($i = 0; $i < $length; ++$i) {
3598
- $value[$i] = $value[$i] & $this->bitmask->value[$i];
3599
- }
3600
- }
3601
-
3602
- return $result;
3603
- }
3604
-
3605
- /**
3606
- * Trim
3607
- *
3608
- * Removes leading zeros
3609
- *
3610
- * @param array $value
3611
- * @return \phpseclib\Math\BigInteger
3612
- * @access private
3613
- */
3614
- function _trim($value)
3615
- {
3616
- for ($i = count($value) - 1; $i >= 0; --$i) {
3617
- if ($value[$i]) {
3618
- break;
3619
- }
3620
- unset($value[$i]);
3621
- }
3622
-
3623
- return $value;
3624
- }
3625
-
3626
- /**
3627
- * Array Repeat
3628
- *
3629
- * @param $input Array
3630
- * @param $multiplier mixed
3631
- * @return array
3632
- * @access private
3633
- */
3634
- function _array_repeat($input, $multiplier)
3635
- {
3636
- return ($multiplier) ? array_fill(0, $multiplier, $input) : array();
3637
- }
3638
-
3639
- /**
3640
- * Logical Left Shift
3641
- *
3642
- * Shifts binary strings $shift bits, essentially multiplying by 2**$shift.
3643
- *
3644
- * @param $x String
3645
- * @param $shift Integer
3646
- * @return string
3647
- * @access private
3648
- */
3649
- function _base256_lshift(&$x, $shift)
3650
- {
3651
- if ($shift == 0) {
3652
- return;
3653
- }
3654
-
3655
- $num_bytes = $shift >> 3; // eg. floor($shift/8)
3656
- $shift &= 7; // eg. $shift % 8
3657
-
3658
- $carry = 0;
3659
- for ($i = strlen($x) - 1; $i >= 0; --$i) {
3660
- $temp = ord($x[$i]) << $shift | $carry;
3661
- $x[$i] = chr($temp);
3662
- $carry = $temp >> 8;
3663
- }
3664
- $carry = ($carry != 0) ? chr($carry) : '';
3665
- $x = $carry . $x . str_repeat(chr(0), $num_bytes);
3666
- }
3667
-
3668
- /**
3669
- * Logical Right Shift
3670
- *
3671
- * Shifts binary strings $shift bits, essentially dividing by 2**$shift and returning the remainder.
3672
- *
3673
- * @param $x String
3674
- * @param $shift Integer
3675
- * @return string
3676
- * @access private
3677
- */
3678
- function _base256_rshift(&$x, $shift)
3679
- {
3680
- if ($shift == 0) {
3681
- $x = ltrim($x, chr(0));
3682
- return '';
3683
- }
3684
-
3685
- $num_bytes = $shift >> 3; // eg. floor($shift/8)
3686
- $shift &= 7; // eg. $shift % 8
3687
-
3688
- $remainder = '';
3689
- if ($num_bytes) {
3690
- $start = $num_bytes > strlen($x) ? -strlen($x) : -$num_bytes;
3691
- $remainder = substr($x, $start);
3692
- $x = substr($x, 0, -$num_bytes);
3693
- }
3694
-
3695
- $carry = 0;
3696
- $carry_shift = 8 - $shift;
3697
- for ($i = 0; $i < strlen($x); ++$i) {
3698
- $temp = (ord($x[$i]) >> $shift) | $carry;
3699
- $carry = (ord($x[$i]) << $carry_shift) & 0xFF;
3700
- $x[$i] = chr($temp);
3701
- }
3702
- $x = ltrim($x, chr(0));
3703
-
3704
- $remainder = chr($carry >> $carry_shift) . $remainder;
3705
-
3706
- return ltrim($remainder, chr(0));
3707
- }
3708
-
3709
- // one quirk about how the following functions are implemented is that PHP defines N to be an unsigned long
3710
- // at 32-bits, while java's longs are 64-bits.
3711
-
3712
- /**
3713
- * Converts 32-bit integers to bytes.
3714
- *
3715
- * @param int $x
3716
- * @return string
3717
- * @access private
3718
- */
3719
- function _int2bytes($x)
3720
- {
3721
- return ltrim(pack('N', $x), chr(0));
3722
- }
3723
-
3724
- /**
3725
- * Converts bytes to 32-bit integers
3726
- *
3727
- * @param string $x
3728
- * @return int
3729
- * @access private
3730
- */
3731
- function _bytes2int($x)
3732
- {
3733
- $temp = unpack('Nint', str_pad($x, 4, chr(0), STR_PAD_LEFT));
3734
- return $temp['int'];
3735
- }
3736
-
3737
- /**
3738
- * DER-encode an integer
3739
- *
3740
- * The ability to DER-encode integers is needed to create RSA public keys for use with OpenSSL
3741
- *
3742
- * @see self::modPow()
3743
- * @access private
3744
- * @param int $length
3745
- * @return string
3746
- */
3747
- function _encodeASN1Length($length)
3748
- {
3749
- if ($length <= 0x7F) {
3750
- return chr($length);
3751
- }
3752
-
3753
- $temp = ltrim(pack('N', $length), chr(0));
3754
- return pack('Ca*', 0x80 | strlen($temp), $temp);
3755
- }
3756
-
3757
- /**
3758
- * Single digit division
3759
- *
3760
- * Even if int64 is being used the division operator will return a float64 value
3761
- * if the dividend is not evenly divisible by the divisor. Since a float64 doesn't
3762
- * have the precision of int64 this is a problem so, when int64 is being used,
3763
- * we'll guarantee that the dividend is divisible by first subtracting the remainder.
3764
- *
3765
- * @access private
3766
- * @param int $x
3767
- * @param int $y
3768
- * @return int
3769
- */
3770
- function _safe_divide($x, $y)
3771
- {
3772
- if (self::$base === 26) {
3773
- return (int) ($x / $y);
3774
- }
3775
-
3776
- // self::$base === 31
3777
- return ($x - ($x % $y)) / $y;
3778
- }
3779
- }
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 version 5
10
+ *
11
+ * {@internal (all DocBlock comments regarding implementation - such as the one that follows - refer to the
12
+ * {@link self::MODE_INTERNAL self::MODE_INTERNAL} mode)
13
+ *
14
+ * 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 \phpseclib\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
+ * $a = new \phpseclib\Math\BigInteger(2);
35
+ * $b = new \phpseclib\Math\BigInteger(3);
36
+ *
37
+ * $c = $a->add($b);
38
+ *
39
+ * echo $c->toString(); // outputs 5
40
+ * ?>
41
+ * </code>
42
+ *
43
+ * @category Math
44
+ * @package BigInteger
45
+ * @author Jim Wigginton <terrafrost@php.net>
46
+ * @copyright 2006 Jim Wigginton
47
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
48
+ */
49
+
50
+ namespace phpseclib\Math;
51
+
52
+ use phpseclib\Crypt\Random;
53
+
54
+ /**
55
+ * Pure-PHP arbitrary precision integer arithmetic library. Supports base-2, base-10, base-16, and base-256
56
+ * numbers.
57
+ *
58
+ * @package BigInteger
59
+ * @author Jim Wigginton <terrafrost@php.net>
60
+ * @access public
61
+ */
62
+ class BigInteger
63
+ {
64
+ /**#@+
65
+ * Reduction constants
66
+ *
67
+ * @access private
68
+ * @see BigInteger::_reduce()
69
+ */
70
+ /**
71
+ * @see BigInteger::_montgomery()
72
+ * @see BigInteger::_prepMontgomery()
73
+ */
74
+ const MONTGOMERY = 0;
75
+ /**
76
+ * @see BigInteger::_barrett()
77
+ */
78
+ const BARRETT = 1;
79
+ /**
80
+ * @see BigInteger::_mod2()
81
+ */
82
+ const POWEROF2 = 2;
83
+ /**
84
+ * @see BigInteger::_remainder()
85
+ */
86
+ const CLASSIC = 3;
87
+ /**
88
+ * @see BigInteger::__clone()
89
+ */
90
+ const NONE = 4;
91
+ /**#@-*/
92
+
93
+ /**#@+
94
+ * Array constants
95
+ *
96
+ * Rather than create a thousands and thousands of new BigInteger objects in repeated function calls to add() and
97
+ * multiply() or whatever, we'll just work directly on arrays, taking them in as parameters and returning them.
98
+ *
99
+ * @access private
100
+ */
101
+ /**
102
+ * $result[self::VALUE] contains the value.
103
+ */
104
+ const VALUE = 0;
105
+ /**
106
+ * $result[self::SIGN] contains the sign.
107
+ */
108
+ const SIGN = 1;
109
+ /**#@-*/
110
+
111
+ /**#@+
112
+ * @access private
113
+ * @see BigInteger::_montgomery()
114
+ * @see BigInteger::_barrett()
115
+ */
116
+ /**
117
+ * Cache constants
118
+ *
119
+ * $cache[self::VARIABLE] tells us whether or not the cached data is still valid.
120
+ */
121
+ const VARIABLE = 0;
122
+ /**
123
+ * $cache[self::DATA] contains the cached data.
124
+ */
125
+ const DATA = 1;
126
+ /**#@-*/
127
+
128
+ /**#@+
129
+ * Mode constants.
130
+ *
131
+ * @access private
132
+ * @see BigInteger::__construct()
133
+ */
134
+ /**
135
+ * To use the pure-PHP implementation
136
+ */
137
+ const MODE_INTERNAL = 1;
138
+ /**
139
+ * To use the BCMath library
140
+ *
141
+ * (if enabled; otherwise, the internal implementation will be used)
142
+ */
143
+ const MODE_BCMATH = 2;
144
+ /**
145
+ * To use the GMP library
146
+ *
147
+ * (if present; otherwise, either the BCMath or the internal implementation will be used)
148
+ */
149
+ const MODE_GMP = 3;
150
+ /**#@-*/
151
+
152
+ /**
153
+ * Karatsuba Cutoff
154
+ *
155
+ * At what point do we switch between Karatsuba multiplication and schoolbook long multiplication?
156
+ *
157
+ * @access private
158
+ */
159
+ const KARATSUBA_CUTOFF = 25;
160
+
161
+ /**#@+
162
+ * Static properties used by the pure-PHP implementation.
163
+ *
164
+ * @see __construct()
165
+ */
166
+ protected static $base;
167
+ protected static $baseFull;
168
+ protected static $maxDigit;
169
+ protected static $msb;
170
+
171
+ /**
172
+ * $max10 in greatest $max10Len satisfying
173
+ * $max10 = 10**$max10Len <= 2**$base.
174
+ */
175
+ protected static $max10;
176
+
177
+ /**
178
+ * $max10Len in greatest $max10Len satisfying
179
+ * $max10 = 10**$max10Len <= 2**$base.
180
+ */
181
+ protected static $max10Len;
182
+ protected static $maxDigit2;
183
+ /**#@-*/
184
+
185
+ /**
186
+ * Holds the BigInteger's value.
187
+ *
188
+ * @var array
189
+ * @access private
190
+ */
191
+ var $value;
192
+
193
+ /**
194
+ * Holds the BigInteger's magnitude.
195
+ *
196
+ * @var bool
197
+ * @access private
198
+ */
199
+ var $is_negative = false;
200
+
201
+ /**
202
+ * Precision
203
+ *
204
+ * @see self::setPrecision()
205
+ * @access private
206
+ */
207
+ var $precision = -1;
208
+
209
+ /**
210
+ * Precision Bitmask
211
+ *
212
+ * @see self::setPrecision()
213
+ * @access private
214
+ */
215
+ var $bitmask = false;
216
+
217
+ /**
218
+ * Mode independent value used for serialization.
219
+ *
220
+ * If the bcmath or gmp extensions are installed $this->value will be a non-serializable resource, hence the need for
221
+ * a variable that'll be serializable regardless of whether or not extensions are being used. Unlike $this->value,
222
+ * however, $this->hex is only calculated when $this->__sleep() is called.
223
+ *
224
+ * @see self::__sleep()
225
+ * @see self::__wakeup()
226
+ * @var string
227
+ * @access private
228
+ */
229
+ var $hex;
230
+
231
+ /**
232
+ * Converts base-2, base-10, base-16, and binary strings (base-256) to BigIntegers.
233
+ *
234
+ * If the second parameter - $base - is negative, then it will be assumed that the number's are encoded using
235
+ * two's compliment. The sole exception to this is -10, which is treated the same as 10 is.
236
+ *
237
+ * Here's an example:
238
+ * <code>
239
+ * <?php
240
+ * $a = new \phpseclib\Math\BigInteger('0x32', 16); // 50 in base-16
241
+ *
242
+ * echo $a->toString(); // outputs 50
243
+ * ?>
244
+ * </code>
245
+ *
246
+ * @param $x base-10 number or base-$base number if $base set.
247
+ * @param int $base
248
+ * @return \phpseclib\Math\BigInteger
249
+ * @access public
250
+ */
251
+ function __construct($x = 0, $base = 10)
252
+ {
253
+ if (!defined('MATH_BIGINTEGER_MODE')) {
254
+ switch (true) {
255
+ case extension_loaded('gmp'):
256
+ define('MATH_BIGINTEGER_MODE', self::MODE_GMP);
257
+ break;
258
+ case extension_loaded('bcmath'):
259
+ define('MATH_BIGINTEGER_MODE', self::MODE_BCMATH);
260
+ break;
261
+ default:
262
+ define('MATH_BIGINTEGER_MODE', self::MODE_INTERNAL);
263
+ }
264
+ }
265
+
266
+ if (extension_loaded('openssl') && !defined('MATH_BIGINTEGER_OPENSSL_DISABLE') && !defined('MATH_BIGINTEGER_OPENSSL_ENABLED')) {
267
+ // some versions of XAMPP have mismatched versions of OpenSSL which causes it not to work
268
+ $versions = array();
269
+
270
+ // avoid generating errors (even with suppression) when phpinfo() is disabled (common in production systems)
271
+ if (strpos(ini_get('disable_functions'), 'phpinfo') === false) {
272
+ ob_start();
273
+ @phpinfo();
274
+ $content = ob_get_contents();
275
+ ob_end_clean();
276
+
277
+ preg_match_all('#OpenSSL (Header|Library) Version(.*)#im', $content, $matches);
278
+
279
+ if (!empty($matches[1])) {
280
+ for ($i = 0; $i < count($matches[1]); $i++) {
281
+ $fullVersion = trim(str_replace('=>', '', strip_tags($matches[2][$i])));
282
+
283
+ // Remove letter part in OpenSSL version
284
+ if (!preg_match('/(\d+\.\d+\.\d+)/i', $fullVersion, $m)) {
285
+ $versions[$matches[1][$i]] = $fullVersion;
286
+ } else {
287
+ $versions[$matches[1][$i]] = $m[0];
288
+ }
289
+ }
290
+ }
291
+ }
292
+
293
+ // it doesn't appear that OpenSSL versions were reported upon until PHP 5.3+
294
+ switch (true) {
295
+ case !isset($versions['Header']):
296
+ case !isset($versions['Library']):
297
+ case $versions['Header'] == $versions['Library']:
298
+ case version_compare($versions['Header'], '1.0.0') >= 0 && version_compare($versions['Library'], '1.0.0') >= 0:
299
+ define('MATH_BIGINTEGER_OPENSSL_ENABLED', true);
300
+ break;
301
+ default:
302
+ define('MATH_BIGINTEGER_OPENSSL_DISABLE', true);
303
+ }
304
+ }
305
+
306
+ if (!defined('PHP_INT_SIZE')) {
307
+ define('PHP_INT_SIZE', 4);
308
+ }
309
+
310
+ if (empty(self::$base) && MATH_BIGINTEGER_MODE == self::MODE_INTERNAL) {
311
+ switch (PHP_INT_SIZE) {
312
+ case 8: // use 64-bit integers if int size is 8 bytes
313
+ self::$base = 31;
314
+ self::$baseFull = 0x80000000;
315
+ self::$maxDigit = 0x7FFFFFFF;
316
+ self::$msb = 0x40000000;
317
+ self::$max10 = 1000000000;
318
+ self::$max10Len = 9;
319
+ self::$maxDigit2 = pow(2, 62);
320
+ break;
321
+ //case 4: // use 64-bit floats if int size is 4 bytes
322
+ default:
323
+ self::$base = 26;
324
+ self::$baseFull = 0x4000000;
325
+ self::$maxDigit = 0x3FFFFFF;
326
+ self::$msb = 0x2000000;
327
+ self::$max10 = 10000000;
328
+ self::$max10Len = 7;
329
+ self::$maxDigit2 = pow(2, 52); // pow() prevents truncation
330
+ }
331
+ }
332
+
333
+ switch (MATH_BIGINTEGER_MODE) {
334
+ case self::MODE_GMP:
335
+ switch (true) {
336
+ case is_resource($x) && get_resource_type($x) == 'GMP integer':
337
+ // PHP 5.6 switched GMP from using resources to objects
338
+ case $x instanceof \GMP:
339
+ $this->value = $x;
340
+ return;
341
+ }
342
+ $this->value = gmp_init(0);
343
+ break;
344
+ case self::MODE_BCMATH:
345
+ $this->value = '0';
346
+ break;
347
+ default:
348
+ $this->value = array();
349
+ }
350
+
351
+ // '0' counts as empty() but when the base is 256 '0' is equal to ord('0') or 48
352
+ // '0' is the only value like this per http://php.net/empty
353
+ if (empty($x) && (abs($base) != 256 || $x !== '0')) {
354
+ return;
355
+ }
356
+
357
+ switch ($base) {
358
+ case -256:
359
+ if (ord($x[0]) & 0x80) {
360
+ $x = ~$x;
361
+ $this->is_negative = true;
362
+ }
363
+ case 256:
364
+ switch (MATH_BIGINTEGER_MODE) {
365
+ case self::MODE_GMP:
366
+ $this->value = function_exists('gmp_import') ?
367
+ gmp_import($x) :
368
+ gmp_init('0x' . bin2hex($x));
369
+ if ($this->is_negative) {
370
+ $this->value = gmp_neg($this->value);
371
+ }
372
+ break;
373
+ case self::MODE_BCMATH:
374
+ // round $len to the nearest 4 (thanks, DavidMJ!)
375
+ $len = (strlen($x) + 3) & 0xFFFFFFFC;
376
+
377
+ $x = str_pad($x, $len, chr(0), STR_PAD_LEFT);
378
+
379
+ for ($i = 0; $i < $len; $i+= 4) {
380
+ $this->value = bcmul($this->value, '4294967296', 0); // 4294967296 == 2**32
381
+ $this->value = bcadd($this->value, 0x1000000 * ord($x[$i]) + ((ord($x[$i + 1]) << 16) | (ord($x[$i + 2]) << 8) | ord($x[$i + 3])), 0);
382
+ }
383
+
384
+ if ($this->is_negative) {
385
+ $this->value = '-' . $this->value;
386
+ }
387
+
388
+ break;
389
+ // converts a base-2**8 (big endian / msb) number to base-2**26 (little endian / lsb)
390
+ default:
391
+ while (strlen($x)) {
392
+ $this->value[] = $this->_bytes2int($this->_base256_rshift($x, self::$base));
393
+ }
394
+ }
395
+
396
+ if ($this->is_negative) {
397
+ if (MATH_BIGINTEGER_MODE != self::MODE_INTERNAL) {
398
+ $this->is_negative = false;
399
+ }
400
+ $temp = $this->add(new static('-1'));
401
+ $this->value = $temp->value;
402
+ }
403
+ break;
404
+ case 16:
405
+ case -16:
406
+ if ($base > 0 && $x[0] == '-') {
407
+ $this->is_negative = true;
408
+ $x = substr($x, 1);
409
+ }
410
+
411
+ $x = preg_replace('#^(?:0x)?([A-Fa-f0-9]*).*#', '$1', $x);
412
+
413
+ $is_negative = false;
414
+ if ($base < 0 && hexdec($x[0]) >= 8) {
415
+ $this->is_negative = $is_negative = true;
416
+ $x = bin2hex(~pack('H*', $x));
417
+ }
418
+
419
+ switch (MATH_BIGINTEGER_MODE) {
420
+ case self::MODE_GMP:
421
+ $temp = $this->is_negative ? '-0x' . $x : '0x' . $x;
422
+ $this->value = gmp_init($temp);
423
+ $this->is_negative = false;
424
+ break;
425
+ case self::MODE_BCMATH:
426
+ $x = (strlen($x) & 1) ? '0' . $x : $x;
427
+ $temp = new static(pack('H*', $x), 256);
428
+ $this->value = $this->is_negative ? '-' . $temp->value : $temp->value;
429
+ $this->is_negative = false;
430
+ break;
431
+ default:
432
+ $x = (strlen($x) & 1) ? '0' . $x : $x;
433
+ $temp = new static(pack('H*', $x), 256);
434
+ $this->value = $temp->value;
435
+ }
436
+
437
+ if ($is_negative) {
438
+ $temp = $this->add(new static('-1'));
439
+ $this->value = $temp->value;
440
+ }
441
+ break;
442
+ case 10:
443
+ case -10:
444
+ // (?<!^)(?:-).*: find any -'s that aren't at the beginning and then any characters that follow that
445
+ // (?<=^|-)0*: find any 0's that are preceded by the start of the string or by a - (ie. octals)
446
+ // [^-0-9].*: find any non-numeric characters and then any characters that follow that
447
+ $x = preg_replace('#(?<!^)(?:-).*|(?<=^|-)0*|[^-0-9].*#', '', $x);
448
+ if (!strlen($x) || $x == '-') {
449
+ $x = '0';
450
+ }
451
+
452
+ switch (MATH_BIGINTEGER_MODE) {
453
+ case self::MODE_GMP:
454
+ $this->value = gmp_init($x);
455
+ break;
456
+ case self::MODE_BCMATH:
457
+ // explicitly casting $x to a string is necessary, here, since doing $x[0] on -1 yields different
458
+ // results then doing it on '-1' does (modInverse does $x[0])
459
+ $this->value = $x === '-' ? '0' : (string) $x;
460
+ break;
461
+ default:
462
+ $temp = new static();
463
+
464
+ $multiplier = new static();
465
+ $multiplier->value = array(self::$max10);
466
+
467
+ if ($x[0] == '-') {
468
+ $this->is_negative = true;
469
+ $x = substr($x, 1);
470
+ }
471
+
472
+ $x = str_pad($x, strlen($x) + ((self::$max10Len - 1) * strlen($x)) % self::$max10Len, 0, STR_PAD_LEFT);
473
+ while (strlen($x)) {
474
+ $temp = $temp->multiply($multiplier);
475
+ $temp = $temp->add(new static($this->_int2bytes(substr($x, 0, self::$max10Len)), 256));
476
+ $x = substr($x, self::$max10Len);
477
+ }
478
+
479
+ $this->value = $temp->value;
480
+ }
481
+ break;
482
+ case 2: // base-2 support originally implemented by Lluis Pamies - thanks!
483
+ case -2:
484
+ if ($base > 0 && $x[0] == '-') {
485
+ $this->is_negative = true;
486
+ $x = substr($x, 1);
487
+ }
488
+
489
+ $x = preg_replace('#^([01]*).*#', '$1', $x);
490
+ $x = str_pad($x, strlen($x) + (3 * strlen($x)) % 4, 0, STR_PAD_LEFT);
491
+
492
+ $str = '0x';
493
+ while (strlen($x)) {
494
+ $part = substr($x, 0, 4);
495
+ $str.= dechex(bindec($part));
496
+ $x = substr($x, 4);
497
+ }
498
+
499
+ if ($this->is_negative) {
500
+ $str = '-' . $str;
501
+ }
502
+
503
+ $temp = new static($str, 8 * $base); // ie. either -16 or +16
504
+ $this->value = $temp->value;
505
+ $this->is_negative = $temp->is_negative;
506
+
507
+ break;
508
+ default:
509
+ // base not supported, so we'll let $this == 0
510
+ }
511
+ }
512
+
513
+ /**
514
+ * Converts a BigInteger to a byte string (eg. base-256).
515
+ *
516
+ * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're
517
+ * saved as two's compliment.
518
+ *
519
+ * Here's an example:
520
+ * <code>
521
+ * <?php
522
+ * $a = new \phpseclib\Math\BigInteger('65');
523
+ *
524
+ * echo $a->toBytes(); // outputs chr(65)
525
+ * ?>
526
+ * </code>
527
+ *
528
+ * @param bool $twos_compliment
529
+ * @return string
530
+ * @access public
531
+ * @internal Converts a base-2**26 number to base-2**8
532
+ */
533
+ function toBytes($twos_compliment = false)
534
+ {
535
+ if ($twos_compliment) {
536
+ $comparison = $this->compare(new static());
537
+ if ($comparison == 0) {
538
+ return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
539
+ }
540
+
541
+ $temp = $comparison < 0 ? $this->add(new static(1)) : $this->copy();
542
+ $bytes = $temp->toBytes();
543
+
544
+ if (!strlen($bytes)) { // eg. if the number we're trying to convert is -1
545
+ $bytes = chr(0);
546
+ }
547
+
548
+ if (ord($bytes[0]) & 0x80) {
549
+ $bytes = chr(0) . $bytes;
550
+ }
551
+
552
+ return $comparison < 0 ? ~$bytes : $bytes;
553
+ }
554
+
555
+ switch (MATH_BIGINTEGER_MODE) {
556
+ case self::MODE_GMP:
557
+ if (gmp_cmp($this->value, gmp_init(0)) == 0) {
558
+ return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
559
+ }
560
+
561
+ if (function_exists('gmp_export')) {
562
+ $temp = gmp_export($this->value);
563
+ } else {
564
+ $temp = gmp_strval(gmp_abs($this->value), 16);
565
+ $temp = (strlen($temp) & 1) ? '0' . $temp : $temp;
566
+ $temp = pack('H*', $temp);
567
+ }
568
+
569
+ return $this->precision > 0 ?
570
+ substr(str_pad($temp, $this->precision >> 3, chr(0), STR_PAD_LEFT), -($this->precision >> 3)) :
571
+ ltrim($temp, chr(0));
572
+ case self::MODE_BCMATH:
573
+ if ($this->value === '0') {
574
+ return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
575
+ }
576
+
577
+ $value = '';
578
+ $current = $this->value;
579
+
580
+ if ($current[0] == '-') {
581
+ $current = substr($current, 1);
582
+ }
583
+
584
+ while (bccomp($current, '0', 0) > 0) {
585
+ $temp = bcmod($current, '16777216');
586
+ $value = chr($temp >> 16) . chr($temp >> 8) . chr($temp) . $value;
587
+ $current = bcdiv($current, '16777216', 0);
588
+ }
589
+
590
+ return $this->precision > 0 ?
591
+ substr(str_pad($value, $this->precision >> 3, chr(0), STR_PAD_LEFT), -($this->precision >> 3)) :
592
+ ltrim($value, chr(0));
593
+ }
594
+
595
+ if (!count($this->value)) {
596
+ return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
597
+ }
598
+ $result = $this->_int2bytes($this->value[count($this->value) - 1]);
599
+
600
+ $temp = $this->copy();
601
+
602
+ for ($i = count($temp->value) - 2; $i >= 0; --$i) {
603
+ $temp->_base256_lshift($result, self::$base);
604
+ $result = $result | str_pad($temp->_int2bytes($temp->value[$i]), strlen($result), chr(0), STR_PAD_LEFT);
605
+ }
606
+
607
+ return $this->precision > 0 ?
608
+ str_pad(substr($result, -(($this->precision + 7) >> 3)), ($this->precision + 7) >> 3, chr(0), STR_PAD_LEFT) :
609
+ $result;
610
+ }
611
+
612
+ /**
613
+ * Converts a BigInteger to a hex string (eg. base-16)).
614
+ *
615
+ * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're
616
+ * saved as two's compliment.
617
+ *
618
+ * Here's an example:
619
+ * <code>
620
+ * <?php
621
+ * $a = new \phpseclib\Math\BigInteger('65');
622
+ *
623
+ * echo $a->toHex(); // outputs '41'
624
+ * ?>
625
+ * </code>
626
+ *
627
+ * @param bool $twos_compliment
628
+ * @return string
629
+ * @access public
630
+ * @internal Converts a base-2**26 number to base-2**8
631
+ */
632
+ function toHex($twos_compliment = false)
633
+ {
634
+ return bin2hex($this->toBytes($twos_compliment));
635
+ }
636
+
637
+ /**
638
+ * Converts a BigInteger to a bit string (eg. base-2).
639
+ *
640
+ * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're
641
+ * saved as two's compliment.
642
+ *
643
+ * Here's an example:
644
+ * <code>
645
+ * <?php
646
+ * $a = new \phpseclib\Math\BigInteger('65');
647
+ *
648
+ * echo $a->toBits(); // outputs '1000001'
649
+ * ?>
650
+ * </code>
651
+ *
652
+ * @param bool $twos_compliment
653
+ * @return string
654
+ * @access public
655
+ * @internal Converts a base-2**26 number to base-2**2
656
+ */
657
+ function toBits($twos_compliment = false)
658
+ {
659
+ $hex = $this->toHex($twos_compliment);
660
+ $bits = '';
661
+ for ($i = strlen($hex) - 8, $start = strlen($hex) & 7; $i >= $start; $i-=8) {
662
+ $bits = str_pad(decbin(hexdec(substr($hex, $i, 8))), 32, '0', STR_PAD_LEFT) . $bits;
663
+ }
664
+ if ($start) { // hexdec('') == 0
665
+ $bits = str_pad(decbin(hexdec(substr($hex, 0, $start))), 8, '0', STR_PAD_LEFT) . $bits;
666
+ }
667
+ $result = $this->precision > 0 ? substr($bits, -$this->precision) : ltrim($bits, '0');
668
+
669
+ if ($twos_compliment && $this->compare(new static()) > 0 && $this->precision <= 0) {
670
+ return '0' . $result;
671
+ }
672
+
673
+ return $result;
674
+ }
675
+
676
+ /**
677
+ * Converts a BigInteger to a base-10 number.
678
+ *
679
+ * Here's an example:
680
+ * <code>
681
+ * <?php
682
+ * $a = new \phpseclib\Math\BigInteger('50');
683
+ *
684
+ * echo $a->toString(); // outputs 50
685
+ * ?>
686
+ * </code>
687
+ *
688
+ * @return string
689
+ * @access public
690
+ * @internal Converts a base-2**26 number to base-10**7 (which is pretty much base-10)
691
+ */
692
+ function toString()
693
+ {
694
+ switch (MATH_BIGINTEGER_MODE) {
695
+ case self::MODE_GMP:
696
+ return gmp_strval($this->value);
697
+ case self::MODE_BCMATH:
698
+ if ($this->value === '0') {
699
+ return '0';
700
+ }
701
+
702
+ return ltrim($this->value, '0');
703
+ }
704
+
705
+ if (!count($this->value)) {
706
+ return '0';
707
+ }
708
+
709
+ $temp = $this->copy();
710
+ $temp->is_negative = false;
711
+
712
+ $divisor = new static();
713
+ $divisor->value = array(self::$max10);
714
+ $result = '';
715
+ while (count($temp->value)) {
716
+ list($temp, $mod) = $temp->divide($divisor);
717
+ $result = str_pad(isset($mod->value[0]) ? $mod->value[0] : '', self::$max10Len, '0', STR_PAD_LEFT) . $result;
718
+ }
719
+ $result = ltrim($result, '0');
720
+ if (empty($result)) {
721
+ $result = '0';
722
+ }
723
+
724
+ if ($this->is_negative) {
725
+ $result = '-' . $result;
726
+ }
727
+
728
+ return $result;
729
+ }
730
+
731
+ /**
732
+ * Copy an object
733
+ *
734
+ * PHP5 passes objects by reference while PHP4 passes by value. As such, we need a function to guarantee
735
+ * that all objects are passed by value, when appropriate. More information can be found here:
736
+ *
737
+ * {@link http://php.net/language.oop5.basic#51624}
738
+ *
739
+ * @access public
740
+ * @see self::__clone()
741
+ * @return \phpseclib\Math\BigInteger
742
+ */
743
+ function copy()
744
+ {
745
+ $temp = new static();
746
+ $temp->value = $this->value;
747
+ $temp->is_negative = $this->is_negative;
748
+ $temp->precision = $this->precision;
749
+ $temp->bitmask = $this->bitmask;
750
+ return $temp;
751
+ }
752
+
753
+ /**
754
+ * __toString() magic method
755
+ *
756
+ * Will be called, automatically, if you're supporting just PHP5. If you're supporting PHP4, you'll need to call
757
+ * toString().
758
+ *
759
+ * @access public
760
+ * @internal Implemented per a suggestion by Techie-Michael - thanks!
761
+ */
762
+ function __toString()
763
+ {
764
+ return $this->toString();
765
+ }
766
+
767
+ /**
768
+ * __clone() magic method
769
+ *
770
+ * Although you can call BigInteger::__toString() directly in PHP5, you cannot call BigInteger::__clone() directly
771
+ * 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
772
+ * only syntax of $y = clone $x. As such, if you're trying to write an application that works on both PHP4 and
773
+ * PHP5, call BigInteger::copy(), instead.
774
+ *
775
+ * @access public
776
+ * @see self::copy()
777
+ * @return \phpseclib\Math\BigInteger
778
+ */
779
+ function __clone()
780
+ {
781
+ return $this->copy();
782
+ }
783
+
784
+ /**
785
+ * __sleep() magic method
786
+ *
787
+ * Will be called, automatically, when serialize() is called on a BigInteger object.
788
+ *
789
+ * @see self::__wakeup()
790
+ * @access public
791
+ */
792
+ function __sleep()
793
+ {
794
+ $this->hex = $this->toHex(true);
795
+ $vars = array('hex');
796
+ if ($this->precision > 0) {
797
+ $vars[] = 'precision';
798
+ }
799
+ return $vars;
800
+ }
801
+
802
+ /**
803
+ * __wakeup() magic method
804
+ *
805
+ * Will be called, automatically, when unserialize() is called on a BigInteger object.
806
+ *
807
+ * @see self::__sleep()
808
+ * @access public
809
+ */
810
+ function __wakeup()
811
+ {
812
+ $temp = new static($this->hex, -16);
813
+ $this->value = $temp->value;
814
+ $this->is_negative = $temp->is_negative;
815
+ if ($this->precision > 0) {
816
+ // recalculate $this->bitmask
817
+ $this->setPrecision($this->precision);
818
+ }
819
+ }
820
+
821
+ /**
822
+ * __debugInfo() magic method
823
+ *
824
+ * Will be called, automatically, when print_r() or var_dump() are called
825
+ *
826
+ * @access public
827
+ */
828
+ function __debugInfo()
829
+ {
830
+ $opts = array();
831
+ switch (MATH_BIGINTEGER_MODE) {
832
+ case self::MODE_GMP:
833
+ $engine = 'gmp';
834
+ break;
835
+ case self::MODE_BCMATH:
836
+ $engine = 'bcmath';
837
+ break;
838
+ case self::MODE_INTERNAL:
839
+ $engine = 'internal';
840
+ $opts[] = PHP_INT_SIZE == 8 ? '64-bit' : '32-bit';
841
+ }
842
+ if (MATH_BIGINTEGER_MODE != self::MODE_GMP && defined('MATH_BIGINTEGER_OPENSSL_ENABLED')) {
843
+ $opts[] = 'OpenSSL';
844
+ }
845
+ if (!empty($opts)) {
846
+ $engine.= ' (' . implode($opts, ', ') . ')';
847
+ }
848
+ return array(
849
+ 'value' => '0x' . $this->toHex(true),
850
+ 'engine' => $engine
851
+ );
852
+ }
853
+
854
+ /**
855
+ * Adds two BigIntegers.
856
+ *
857
+ * Here's an example:
858
+ * <code>
859
+ * <?php
860
+ * $a = new \phpseclib\Math\BigInteger('10');
861
+ * $b = new \phpseclib\Math\BigInteger('20');
862
+ *
863
+ * $c = $a->add($b);
864
+ *
865
+ * echo $c->toString(); // outputs 30
866
+ * ?>
867
+ * </code>
868
+ *
869
+ * @param \phpseclib\Math\BigInteger $y
870
+ * @return \phpseclib\Math\BigInteger
871
+ * @access public
872
+ * @internal Performs base-2**52 addition
873
+ */
874
+ function add($y)
875
+ {
876
+ switch (MATH_BIGINTEGER_MODE) {
877
+ case self::MODE_GMP:
878
+ $temp = new static();
879
+ $temp->value = gmp_add($this->value, $y->value);
880
+
881
+ return $this->_normalize($temp);
882
+ case self::MODE_BCMATH:
883
+ $temp = new static();
884
+ $temp->value = bcadd($this->value, $y->value, 0);
885
+
886
+ return $this->_normalize($temp);
887
+ }
888
+
889
+ $temp = $this->_add($this->value, $this->is_negative, $y->value, $y->is_negative);
890
+
891
+ $result = new static();
892
+ $result->value = $temp[self::VALUE];
893
+ $result->is_negative = $temp[self::SIGN];
894
+
895
+ return $this->_normalize($result);
896
+ }
897
+
898
+ /**
899
+ * Performs addition.
900
+ *
901
+ * @param array $x_value
902
+ * @param bool $x_negative
903
+ * @param array $y_value
904
+ * @param bool $y_negative
905
+ * @return array
906
+ * @access private
907
+ */
908
+ function _add($x_value, $x_negative, $y_value, $y_negative)
909
+ {
910
+ $x_size = count($x_value);
911
+ $y_size = count($y_value);
912
+
913
+ if ($x_size == 0) {
914
+ return array(
915
+ self::VALUE => $y_value,
916
+ self::SIGN => $y_negative
917
+ );
918
+ } elseif ($y_size == 0) {
919
+ return array(
920
+ self::VALUE => $x_value,
921
+ self::SIGN => $x_negative
922
+ );
923
+ }
924
+
925
+ // subtract, if appropriate
926
+ if ($x_negative != $y_negative) {
927
+ if ($x_value == $y_value) {
928
+ return array(
929
+ self::VALUE => array(),
930
+ self::SIGN => false
931
+ );
932
+ }
933
+
934
+ $temp = $this->_subtract($x_value, false, $y_value, false);
935
+ $temp[self::SIGN] = $this->_compare($x_value, false, $y_value, false) > 0 ?
936
+ $x_negative : $y_negative;
937
+
938
+ return $temp;
939
+ }
940
+
941
+ if ($x_size < $y_size) {
942
+ $size = $x_size;
943
+ $value = $y_value;
944
+ } else {
945
+ $size = $y_size;
946
+ $value = $x_value;
947
+ }
948
+
949
+ $value[count($value)] = 0; // just in case the carry adds an extra digit
950
+
951
+ $carry = 0;
952
+ for ($i = 0, $j = 1; $j < $size; $i+=2, $j+=2) {
953
+ $sum = $x_value[$j] * self::$baseFull + $x_value[$i] + $y_value[$j] * self::$baseFull + $y_value[$i] + $carry;
954
+ $carry = $sum >= self::$maxDigit2; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1
955
+ $sum = $carry ? $sum - self::$maxDigit2 : $sum;
956
+
957
+ $temp = self::$base === 26 ? intval($sum / 0x4000000) : ($sum >> 31);
958
+
959
+ $value[$i] = (int) ($sum - self::$baseFull * $temp); // eg. a faster alternative to fmod($sum, 0x4000000)
960
+ $value[$j] = $temp;
961
+ }
962
+
963
+ if ($j == $size) { // ie. if $y_size is odd
964
+ $sum = $x_value[$i] + $y_value[$i] + $carry;
965
+ $carry = $sum >= self::$baseFull;
966
+ $value[$i] = $carry ? $sum - self::$baseFull : $sum;
967
+ ++$i; // ie. let $i = $j since we've just done $value[$i]
968
+ }
969
+
970
+ if ($carry) {
971
+ for (; $value[$i] == self::$maxDigit; ++$i) {
972
+ $value[$i] = 0;
973
+ }
974
+ ++$value[$i];
975
+ }
976
+
977
+ return array(
978
+ self::VALUE => $this->_trim($value),
979
+ self::SIGN => $x_negative
980
+ );
981
+ }
982
+
983
+ /**
984
+ * Subtracts two BigIntegers.
985
+ *
986
+ * Here's an example:
987
+ * <code>
988
+ * <?php
989
+ * $a = new \phpseclib\Math\BigInteger('10');
990
+ * $b = new \phpseclib\Math\BigInteger('20');
991
+ *
992
+ * $c = $a->subtract($b);
993
+ *
994
+ * echo $c->toString(); // outputs -10
995
+ * ?>
996
+ * </code>
997
+ *
998
+ * @param \phpseclib\Math\BigInteger $y
999
+ * @return \phpseclib\Math\BigInteger
1000
+ * @access public
1001
+ * @internal Performs base-2**52 subtraction
1002
+ */
1003
+ function subtract($y)
1004
+ {
1005
+ switch (MATH_BIGINTEGER_MODE) {
1006
+ case self::MODE_GMP:
1007
+ $temp = new static();
1008
+ $temp->value = gmp_sub($this->value, $y->value);
1009
+
1010
+ return $this->_normalize($temp);
1011
+ case self::MODE_BCMATH:
1012
+ $temp = new static();
1013
+ $temp->value = bcsub($this->value, $y->value, 0);
1014
+
1015
+ return $this->_normalize($temp);
1016
+ }
1017
+
1018
+ $temp = $this->_subtract($this->value, $this->is_negative, $y->value, $y->is_negative);
1019
+
1020
+ $result = new static();
1021
+ $result->value = $temp[self::VALUE];
1022
+ $result->is_negative = $temp[self::SIGN];
1023
+
1024
+ return $this->_normalize($result);
1025
+ }
1026
+
1027
+ /**
1028
+ * Performs subtraction.
1029
+ *
1030
+ * @param array $x_value
1031
+ * @param bool $x_negative
1032
+ * @param array $y_value
1033
+ * @param bool $y_negative
1034
+ * @return array
1035
+ * @access private
1036
+ */
1037
+ function _subtract($x_value, $x_negative, $y_value, $y_negative)
1038
+ {
1039
+ $x_size = count($x_value);
1040
+ $y_size = count($y_value);
1041
+
1042
+ if ($x_size == 0) {
1043
+ return array(
1044
+ self::VALUE => $y_value,
1045
+ self::SIGN => !$y_negative
1046
+ );
1047
+ } elseif ($y_size == 0) {
1048
+ return array(
1049
+ self::VALUE => $x_value,
1050
+ self::SIGN => $x_negative
1051
+ );
1052
+ }
1053
+
1054
+ // add, if appropriate (ie. -$x - +$y or +$x - -$y)
1055
+ if ($x_negative != $y_negative) {
1056
+ $temp = $this->_add($x_value, false, $y_value, false);
1057
+ $temp[self::SIGN] = $x_negative;
1058
+
1059
+ return $temp;
1060
+ }
1061
+
1062
+ $diff = $this->_compare($x_value, $x_negative, $y_value, $y_negative);
1063
+
1064
+ if (!$diff) {
1065
+ return array(
1066
+ self::VALUE => array(),
1067
+ self::SIGN => false
1068
+ );
1069
+ }
1070
+
1071
+ // switch $x and $y around, if appropriate.
1072
+ if ((!$x_negative && $diff < 0) || ($x_negative && $diff > 0)) {
1073
+ $temp = $x_value;
1074
+ $x_value = $y_value;
1075
+ $y_value = $temp;
1076
+
1077
+ $x_negative = !$x_negative;
1078
+
1079
+ $x_size = count($x_value);
1080
+ $y_size = count($y_value);
1081
+ }
1082
+
1083
+ // at this point, $x_value should be at least as big as - if not bigger than - $y_value
1084
+
1085
+ $carry = 0;
1086
+ for ($i = 0, $j = 1; $j < $y_size; $i+=2, $j+=2) {
1087
+ $sum = $x_value[$j] * self::$baseFull + $x_value[$i] - $y_value[$j] * self::$baseFull - $y_value[$i] - $carry;
1088
+ $carry = $sum < 0; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1
1089
+ $sum = $carry ? $sum + self::$maxDigit2 : $sum;
1090
+
1091
+ $temp = self::$base === 26 ? intval($sum / 0x4000000) : ($sum >> 31);
1092
+
1093
+ $x_value[$i] = (int) ($sum - self::$baseFull * $temp);
1094
+ $x_value[$j] = $temp;
1095
+ }
1096
+
1097
+ if ($j == $y_size) { // ie. if $y_size is odd
1098
+ $sum = $x_value[$i] - $y_value[$i] - $carry;
1099
+ $carry = $sum < 0;
1100
+ $x_value[$i] = $carry ? $sum + self::$baseFull : $sum;
1101
+ ++$i;
1102
+ }
1103
+
1104
+ if ($carry) {
1105
+ for (; !$x_value[$i]; ++$i) {
1106
+ $x_value[$i] = self::$maxDigit;
1107
+ }
1108
+ --$x_value[$i];
1109
+ }
1110
+
1111
+ return array(
1112
+ self::VALUE => $this->_trim($x_value),
1113
+ self::SIGN => $x_negative
1114
+ );
1115
+ }
1116
+
1117
+ /**
1118
+ * Multiplies two BigIntegers
1119
+ *
1120
+ * Here's an example:
1121
+ * <code>
1122
+ * <?php
1123
+ * $a = new \phpseclib\Math\BigInteger('10');
1124
+ * $b = new \phpseclib\Math\BigInteger('20');
1125
+ *
1126
+ * $c = $a->multiply($b);
1127
+ *
1128
+ * echo $c->toString(); // outputs 200
1129
+ * ?>
1130
+ * </code>
1131
+ *
1132
+ * @param \phpseclib\Math\BigInteger $x
1133
+ * @return \phpseclib\Math\BigInteger
1134
+ * @access public
1135
+ */
1136
+ function multiply($x)
1137
+ {
1138
+ switch (MATH_BIGINTEGER_MODE) {
1139
+ case self::MODE_GMP:
1140
+ $temp = new static();
1141
+ $temp->value = gmp_mul($this->value, $x->value);
1142
+
1143
+ return $this->_normalize($temp);
1144
+ case self::MODE_BCMATH:
1145
+ $temp = new static();
1146
+ $temp->value = bcmul($this->value, $x->value, 0);
1147
+
1148
+ return $this->_normalize($temp);
1149
+ }
1150
+
1151
+ $temp = $this->_multiply($this->value, $this->is_negative, $x->value, $x->is_negative);
1152
+
1153
+ $product = new static();
1154
+ $product->value = $temp[self::VALUE];
1155
+ $product->is_negative = $temp[self::SIGN];
1156
+
1157
+ return $this->_normalize($product);
1158
+ }
1159
+
1160
+ /**
1161
+ * Performs multiplication.
1162
+ *
1163
+ * @param array $x_value
1164
+ * @param bool $x_negative
1165
+ * @param array $y_value
1166
+ * @param bool $y_negative
1167
+ * @return array
1168
+ * @access private
1169
+ */
1170
+ function _multiply($x_value, $x_negative, $y_value, $y_negative)
1171
+ {
1172
+ //if ( $x_value == $y_value ) {
1173
+ // return array(
1174
+ // self::VALUE => $this->_square($x_value),
1175
+ // self::SIGN => $x_sign != $y_value
1176
+ // );
1177
+ //}
1178
+
1179
+ $x_length = count($x_value);
1180
+ $y_length = count($y_value);
1181
+
1182
+ if (!$x_length || !$y_length) { // a 0 is being multiplied
1183
+ return array(
1184
+ self::VALUE => array(),
1185
+ self::SIGN => false
1186
+ );
1187
+ }
1188
+
1189
+ return array(
1190
+ self::VALUE => min($x_length, $y_length) < 2 * self::KARATSUBA_CUTOFF ?
1191
+ $this->_trim($this->_regularMultiply($x_value, $y_value)) :
1192
+ $this->_trim($this->_karatsuba($x_value, $y_value)),
1193
+ self::SIGN => $x_negative != $y_negative
1194
+ );
1195
+ }
1196
+
1197
+ /**
1198
+ * Performs long multiplication on two BigIntegers
1199
+ *
1200
+ * Modeled after 'multiply' in MutableBigInteger.java.
1201
+ *
1202
+ * @param array $x_value
1203
+ * @param array $y_value
1204
+ * @return array
1205
+ * @access private
1206
+ */
1207
+ function _regularMultiply($x_value, $y_value)
1208
+ {
1209
+ $x_length = count($x_value);
1210
+ $y_length = count($y_value);
1211
+
1212
+ if (!$x_length || !$y_length) { // a 0 is being multiplied
1213
+ return array();
1214
+ }
1215
+
1216
+ if ($x_length < $y_length) {
1217
+ $temp = $x_value;
1218
+ $x_value = $y_value;
1219
+ $y_value = $temp;
1220
+
1221
+ $x_length = count($x_value);
1222
+ $y_length = count($y_value);
1223
+ }
1224
+
1225
+ $product_value = $this->_array_repeat(0, $x_length + $y_length);
1226
+
1227
+ // the following for loop could be removed if the for loop following it
1228
+ // (the one with nested for loops) initially set $i to 0, but
1229
+ // doing so would also make the result in one set of unnecessary adds,
1230
+ // since on the outermost loops first pass, $product->value[$k] is going
1231
+ // to always be 0
1232
+
1233
+ $carry = 0;
1234
+
1235
+ for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0
1236
+ $temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0
1237
+ $carry = self::$base === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
1238
+ $product_value[$j] = (int) ($temp - self::$baseFull * $carry);
1239
+ }
1240
+
1241
+ $product_value[$j] = $carry;
1242
+
1243
+ // the above for loop is what the previous comment was talking about. the
1244
+ // following for loop is the "one with nested for loops"
1245
+ for ($i = 1; $i < $y_length; ++$i) {
1246
+ $carry = 0;
1247
+
1248
+ for ($j = 0, $k = $i; $j < $x_length; ++$j, ++$k) {
1249
+ $temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry;
1250
+ $carry = self::$base === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
1251
+ $product_value[$k] = (int) ($temp - self::$baseFull * $carry);
1252
+ }
1253
+
1254
+ $product_value[$k] = $carry;
1255
+ }
1256
+
1257
+ return $product_value;
1258
+ }
1259
+
1260
+ /**
1261
+ * Performs Karatsuba multiplication on two BigIntegers
1262
+ *
1263
+ * See {@link http://en.wikipedia.org/wiki/Karatsuba_algorithm Karatsuba algorithm} and
1264
+ * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=120 MPM 5.2.3}.
1265
+ *
1266
+ * @param array $x_value
1267
+ * @param array $y_value
1268
+ * @return array
1269
+ * @access private
1270
+ */
1271
+ function _karatsuba($x_value, $y_value)
1272
+ {
1273
+ $m = min(count($x_value) >> 1, count($y_value) >> 1);
1274
+
1275
+ if ($m < self::KARATSUBA_CUTOFF) {
1276
+ return $this->_regularMultiply($x_value, $y_value);
1277
+ }
1278
+
1279
+ $x1 = array_slice($x_value, $m);
1280
+ $x0 = array_slice($x_value, 0, $m);
1281
+ $y1 = array_slice($y_value, $m);
1282
+ $y0 = array_slice($y_value, 0, $m);
1283
+
1284
+ $z2 = $this->_karatsuba($x1, $y1);
1285
+ $z0 = $this->_karatsuba($x0, $y0);
1286
+
1287
+ $z1 = $this->_add($x1, false, $x0, false);
1288
+ $temp = $this->_add($y1, false, $y0, false);
1289
+ $z1 = $this->_karatsuba($z1[self::VALUE], $temp[self::VALUE]);
1290
+ $temp = $this->_add($z2, false, $z0, false);
1291
+ $z1 = $this->_subtract($z1, false, $temp[self::VALUE], false);
1292
+
1293
+ $z2 = array_merge(array_fill(0, 2 * $m, 0), $z2);
1294
+ $z1[self::VALUE] = array_merge(array_fill(0, $m, 0), $z1[self::VALUE]);
1295
+
1296
+ $xy = $this->_add($z2, false, $z1[self::VALUE], $z1[self::SIGN]);
1297
+ $xy = $this->_add($xy[self::VALUE], $xy[self::SIGN], $z0, false);
1298
+
1299
+ return $xy[self::VALUE];
1300
+ }
1301
+
1302
+ /**
1303
+ * Performs squaring
1304
+ *
1305
+ * @param array $x
1306
+ * @return array
1307
+ * @access private
1308
+ */
1309
+ function _square($x = false)
1310
+ {
1311
+ return count($x) < 2 * self::KARATSUBA_CUTOFF ?
1312
+ $this->_trim($this->_baseSquare($x)) :
1313
+ $this->_trim($this->_karatsubaSquare($x));
1314
+ }
1315
+
1316
+ /**
1317
+ * Performs traditional squaring on two BigIntegers
1318
+ *
1319
+ * Squaring can be done faster than multiplying a number by itself can be. See
1320
+ * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=7 HAC 14.2.4} /
1321
+ * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=141 MPM 5.3} for more information.
1322
+ *
1323
+ * @param array $value
1324
+ * @return array
1325
+ * @access private
1326
+ */
1327
+ function _baseSquare($value)
1328
+ {
1329
+ if (empty($value)) {
1330
+ return array();
1331
+ }
1332
+ $square_value = $this->_array_repeat(0, 2 * count($value));
1333
+
1334
+ for ($i = 0, $max_index = count($value) - 1; $i <= $max_index; ++$i) {
1335
+ $i2 = $i << 1;
1336
+
1337
+ $temp = $square_value[$i2] + $value[$i] * $value[$i];
1338
+ $carry = self::$base === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
1339
+ $square_value[$i2] = (int) ($temp - self::$baseFull * $carry);
1340
+
1341
+ // note how we start from $i+1 instead of 0 as we do in multiplication.
1342
+ for ($j = $i + 1, $k = $i2 + 1; $j <= $max_index; ++$j, ++$k) {
1343
+ $temp = $square_value[$k] + 2 * $value[$j] * $value[$i] + $carry;
1344
+ $carry = self::$base === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
1345
+ $square_value[$k] = (int) ($temp - self::$baseFull * $carry);
1346
+ }
1347
+
1348
+ // the following line can yield values larger 2**15. at this point, PHP should switch
1349
+ // over to floats.
1350
+ $square_value[$i + $max_index + 1] = $carry;
1351
+ }
1352
+
1353
+ return $square_value;
1354
+ }
1355
+
1356
+ /**
1357
+ * Performs Karatsuba "squaring" on two BigIntegers
1358
+ *
1359
+ * See {@link http://en.wikipedia.org/wiki/Karatsuba_algorithm Karatsuba algorithm} and
1360
+ * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=151 MPM 5.3.4}.
1361
+ *
1362
+ * @param array $value
1363
+ * @return array
1364
+ * @access private
1365
+ */
1366
+ function _karatsubaSquare($value)
1367
+ {
1368
+ $m = count($value) >> 1;
1369
+
1370
+ if ($m < self::KARATSUBA_CUTOFF) {
1371
+ return $this->_baseSquare($value);
1372
+ }
1373
+
1374
+ $x1 = array_slice($value, $m);
1375
+ $x0 = array_slice($value, 0, $m);
1376
+
1377
+ $z2 = $this->_karatsubaSquare($x1);
1378
+ $z0 = $this->_karatsubaSquare($x0);
1379
+
1380
+ $z1 = $this->_add($x1, false, $x0, false);
1381
+ $z1 = $this->_karatsubaSquare($z1[self::VALUE]);
1382
+ $temp = $this->_add($z2, false, $z0, false);
1383
+ $z1 = $this->_subtract($z1, false, $temp[self::VALUE], false);
1384
+
1385
+ $z2 = array_merge(array_fill(0, 2 * $m, 0), $z2);
1386
+ $z1[self::VALUE] = array_merge(array_fill(0, $m, 0), $z1[self::VALUE]);
1387
+
1388
+ $xx = $this->_add($z2, false, $z1[self::VALUE], $z1[self::SIGN]);
1389
+ $xx = $this->_add($xx[self::VALUE], $xx[self::SIGN], $z0, false);
1390
+
1391
+ return $xx[self::VALUE];
1392
+ }
1393
+
1394
+ /**
1395
+ * Divides two BigIntegers.
1396
+ *
1397
+ * Returns an array whose first element contains the quotient and whose second element contains the
1398
+ * "common residue". If the remainder would be positive, the "common residue" and the remainder are the
1399
+ * same. If the remainder would be negative, the "common residue" is equal to the sum of the remainder
1400
+ * and the divisor (basically, the "common residue" is the first positive modulo).
1401
+ *
1402
+ * Here's an example:
1403
+ * <code>
1404
+ * <?php
1405
+ * $a = new \phpseclib\Math\BigInteger('10');
1406
+ * $b = new \phpseclib\Math\BigInteger('20');
1407
+ *
1408
+ * list($quotient, $remainder) = $a->divide($b);
1409
+ *
1410
+ * echo $quotient->toString(); // outputs 0
1411
+ * echo "\r\n";
1412
+ * echo $remainder->toString(); // outputs 10
1413
+ * ?>
1414
+ * </code>
1415
+ *
1416
+ * @param \phpseclib\Math\BigInteger $y
1417
+ * @return array
1418
+ * @access public
1419
+ * @internal This function is based off of {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=9 HAC 14.20}.
1420
+ */
1421
+ function divide($y)
1422
+ {
1423
+ switch (MATH_BIGINTEGER_MODE) {
1424
+ case self::MODE_GMP:
1425
+ $quotient = new static();
1426
+ $remainder = new static();
1427
+
1428
+ list($quotient->value, $remainder->value) = gmp_div_qr($this->value, $y->value);
1429
+
1430
+ if (gmp_sign($remainder->value) < 0) {
1431
+ $remainder->value = gmp_add($remainder->value, gmp_abs($y->value));
1432
+ }
1433
+
1434
+ return array($this->_normalize($quotient), $this->_normalize($remainder));
1435
+ case self::MODE_BCMATH:
1436
+ $quotient = new static();
1437
+ $remainder = new static();
1438
+
1439
+ $quotient->value = bcdiv($this->value, $y->value, 0);
1440
+ $remainder->value = bcmod($this->value, $y->value);
1441
+
1442
+ if ($remainder->value[0] == '-') {
1443
+ $remainder->value = bcadd($remainder->value, $y->value[0] == '-' ? substr($y->value, 1) : $y->value, 0);
1444
+ }
1445
+
1446
+ return array($this->_normalize($quotient), $this->_normalize($remainder));
1447
+ }
1448
+
1449
+ if (count($y->value) == 1) {
1450
+ list($q, $r) = $this->_divide_digit($this->value, $y->value[0]);
1451
+ $quotient = new static();
1452
+ $remainder = new static();
1453
+ $quotient->value = $q;
1454
+ $remainder->value = array($r);
1455
+ $quotient->is_negative = $this->is_negative != $y->is_negative;
1456
+ return array($this->_normalize($quotient), $this->_normalize($remainder));
1457
+ }
1458
+
1459
+ static $zero;
1460
+ if (!isset($zero)) {
1461
+ $zero = new static();
1462
+ }
1463
+
1464
+ $x = $this->copy();
1465
+ $y = $y->copy();
1466
+
1467
+ $x_sign = $x->is_negative;
1468
+ $y_sign = $y->is_negative;
1469
+
1470
+ $x->is_negative = $y->is_negative = false;
1471
+
1472
+ $diff = $x->compare($y);
1473
+
1474
+ if (!$diff) {
1475
+ $temp = new static();
1476
+ $temp->value = array(1);
1477
+ $temp->is_negative = $x_sign != $y_sign;
1478
+ return array($this->_normalize($temp), $this->_normalize(new static()));
1479
+ }
1480
+
1481
+ if ($diff < 0) {
1482
+ // if $x is negative, "add" $y.
1483
+ if ($x_sign) {
1484
+ $x = $y->subtract($x);
1485
+ }
1486
+ return array($this->_normalize(new static()), $this->_normalize($x));
1487
+ }
1488
+
1489
+ // normalize $x and $y as described in HAC 14.23 / 14.24
1490
+ $msb = $y->value[count($y->value) - 1];
1491
+ for ($shift = 0; !($msb & self::$msb); ++$shift) {
1492
+ $msb <<= 1;
1493
+ }
1494
+ $x->_lshift($shift);
1495
+ $y->_lshift($shift);
1496
+ $y_value = &$y->value;
1497
+
1498
+ $x_max = count($x->value) - 1;
1499
+ $y_max = count($y->value) - 1;
1500
+
1501
+ $quotient = new static();
1502
+ $quotient_value = &$quotient->value;
1503
+ $quotient_value = $this->_array_repeat(0, $x_max - $y_max + 1);
1504
+
1505
+ static $temp, $lhs, $rhs;
1506
+ if (!isset($temp)) {
1507
+ $temp = new static();
1508
+ $lhs = new static();
1509
+ $rhs = new static();
1510
+ }
1511
+ $temp_value = &$temp->value;
1512
+ $rhs_value = &$rhs->value;
1513
+
1514
+ // $temp = $y << ($x_max - $y_max-1) in base 2**26
1515
+ $temp_value = array_merge($this->_array_repeat(0, $x_max - $y_max), $y_value);
1516
+
1517
+ while ($x->compare($temp) >= 0) {
1518
+ // calculate the "common residue"
1519
+ ++$quotient_value[$x_max - $y_max];
1520
+ $x = $x->subtract($temp);
1521
+ $x_max = count($x->value) - 1;
1522
+ }
1523
+
1524
+ for ($i = $x_max; $i >= $y_max + 1; --$i) {
1525
+ $x_value = &$x->value;
1526
+ $x_window = array(
1527
+ isset($x_value[$i]) ? $x_value[$i] : 0,
1528
+ isset($x_value[$i - 1]) ? $x_value[$i - 1] : 0,
1529
+ isset($x_value[$i - 2]) ? $x_value[$i - 2] : 0
1530
+ );
1531
+ $y_window = array(
1532
+ $y_value[$y_max],
1533
+ ($y_max > 0) ? $y_value[$y_max - 1] : 0
1534
+ );
1535
+
1536
+ $q_index = $i - $y_max - 1;
1537
+ if ($x_window[0] == $y_window[0]) {
1538
+ $quotient_value[$q_index] = self::$maxDigit;
1539
+ } else {
1540
+ $quotient_value[$q_index] = $this->_safe_divide(
1541
+ $x_window[0] * self::$baseFull + $x_window[1],
1542
+ $y_window[0]
1543
+ );
1544
+ }
1545
+
1546
+ $temp_value = array($y_window[1], $y_window[0]);
1547
+
1548
+ $lhs->value = array($quotient_value[$q_index]);
1549
+ $lhs = $lhs->multiply($temp);
1550
+
1551
+ $rhs_value = array($x_window[2], $x_window[1], $x_window[0]);
1552
+
1553
+ while ($lhs->compare($rhs) > 0) {
1554
+ --$quotient_value[$q_index];
1555
+
1556
+ $lhs->value = array($quotient_value[$q_index]);
1557
+ $lhs = $lhs->multiply($temp);
1558
+ }
1559
+
1560
+ $adjust = $this->_array_repeat(0, $q_index);
1561
+ $temp_value = array($quotient_value[$q_index]);
1562
+ $temp = $temp->multiply($y);
1563
+ $temp_value = &$temp->value;
1564
+ if (count($temp_value)) {
1565
+ $temp_value = array_merge($adjust, $temp_value);
1566
+ }
1567
+
1568
+ $x = $x->subtract($temp);
1569
+
1570
+ if ($x->compare($zero) < 0) {
1571
+ $temp_value = array_merge($adjust, $y_value);
1572
+ $x = $x->add($temp);
1573
+
1574
+ --$quotient_value[$q_index];
1575
+ }
1576
+
1577
+ $x_max = count($x_value) - 1;
1578
+ }
1579
+
1580
+ // unnormalize the remainder
1581
+ $x->_rshift($shift);
1582
+
1583
+ $quotient->is_negative = $x_sign != $y_sign;
1584
+
1585
+ // calculate the "common residue", if appropriate
1586
+ if ($x_sign) {
1587
+ $y->_rshift($shift);
1588
+ $x = $y->subtract($x);
1589
+ }
1590
+
1591
+ return array($this->_normalize($quotient), $this->_normalize($x));
1592
+ }
1593
+
1594
+ /**
1595
+ * Divides a BigInteger by a regular integer
1596
+ *
1597
+ * abc / x = a00 / x + b0 / x + c / x
1598
+ *
1599
+ * @param array $dividend
1600
+ * @param array $divisor
1601
+ * @return array
1602
+ * @access private
1603
+ */
1604
+ function _divide_digit($dividend, $divisor)
1605
+ {
1606
+ $carry = 0;
1607
+ $result = array();
1608
+
1609
+ for ($i = count($dividend) - 1; $i >= 0; --$i) {
1610
+ $temp = self::$baseFull * $carry + $dividend[$i];
1611
+ $result[$i] = $this->_safe_divide($temp, $divisor);
1612
+ $carry = (int) ($temp - $divisor * $result[$i]);
1613
+ }
1614
+
1615
+ return array($result, $carry);
1616
+ }
1617
+
1618
+ /**
1619
+ * Performs modular exponentiation.
1620
+ *
1621
+ * Here's an example:
1622
+ * <code>
1623
+ * <?php
1624
+ * $a = new \phpseclib\Math\BigInteger('10');
1625
+ * $b = new \phpseclib\Math\BigInteger('20');
1626
+ * $c = new \phpseclib\Math\BigInteger('30');
1627
+ *
1628
+ * $c = $a->modPow($b, $c);
1629
+ *
1630
+ * echo $c->toString(); // outputs 10
1631
+ * ?>
1632
+ * </code>
1633
+ *
1634
+ * @param \phpseclib\Math\BigInteger $e
1635
+ * @param \phpseclib\Math\BigInteger $n
1636
+ * @return \phpseclib\Math\BigInteger
1637
+ * @access public
1638
+ * @internal The most naive approach to modular exponentiation has very unreasonable requirements, and
1639
+ * and although the approach involving repeated squaring does vastly better, it, too, is impractical
1640
+ * for our purposes. The reason being that division - by far the most complicated and time-consuming
1641
+ * of the basic operations (eg. +,-,*,/) - occurs multiple times within it.
1642
+ *
1643
+ * Modular reductions resolve this issue. Although an individual modular reduction takes more time
1644
+ * then an individual division, when performed in succession (with the same modulo), they're a lot faster.
1645
+ *
1646
+ * The two most commonly used modular reductions are Barrett and Montgomery reduction. Montgomery reduction,
1647
+ * although faster, only works when the gcd of the modulo and of the base being used is 1. In RSA, when the
1648
+ * base is a power of two, the modulo - a product of two primes - is always going to have a gcd of 1 (because
1649
+ * the product of two odd numbers is odd), but what about when RSA isn't used?
1650
+ *
1651
+ * In contrast, Barrett reduction has no such constraint. As such, some bigint implementations perform a
1652
+ * Barrett reduction after every operation in the modpow function. Others perform Barrett reductions when the
1653
+ * modulo is even and Montgomery reductions when the modulo is odd. BigInteger.java's modPow method, however,
1654
+ * uses a trick involving the Chinese Remainder Theorem to factor the even modulo into two numbers - one odd and
1655
+ * the other, a power of two - and recombine them, later. This is the method that this modPow function uses.
1656
+ * {@link http://islab.oregonstate.edu/papers/j34monex.pdf Montgomery Reduction with Even Modulus} elaborates.
1657
+ */
1658
+ function modPow($e, $n)
1659
+ {
1660
+ $n = $this->bitmask !== false && $this->bitmask->compare($n) < 0 ? $this->bitmask : $n->abs();
1661
+
1662
+ if ($e->compare(new static()) < 0) {
1663
+ $e = $e->abs();
1664
+
1665
+ $temp = $this->modInverse($n);
1666
+ if ($temp === false) {
1667
+ return false;
1668
+ }
1669
+
1670
+ return $this->_normalize($temp->modPow($e, $n));
1671
+ }
1672
+
1673
+ if (MATH_BIGINTEGER_MODE == self::MODE_GMP) {
1674
+ $temp = new static();
1675
+ $temp->value = gmp_powm($this->value, $e->value, $n->value);
1676
+
1677
+ return $this->_normalize($temp);
1678
+ }
1679
+
1680
+ if ($this->compare(new static()) < 0 || $this->compare($n) > 0) {
1681
+ list(, $temp) = $this->divide($n);
1682
+ return $temp->modPow($e, $n);
1683
+ }
1684
+
1685
+ if (defined('MATH_BIGINTEGER_OPENSSL_ENABLED')) {
1686
+ $components = array(
1687
+ 'modulus' => $n->toBytes(true),
1688
+ 'publicExponent' => $e->toBytes(true)
1689
+ );
1690
+
1691
+ $components = array(
1692
+ 'modulus' => pack('Ca*a*', 2, $this->_encodeASN1Length(strlen($components['modulus'])), $components['modulus']),
1693
+ 'publicExponent' => pack('Ca*a*', 2, $this->_encodeASN1Length(strlen($components['publicExponent'])), $components['publicExponent'])
1694
+ );
1695
+
1696
+ $RSAPublicKey = pack(
1697
+ 'Ca*a*a*',
1698
+ 48,
1699
+ $this->_encodeASN1Length(strlen($components['modulus']) + strlen($components['publicExponent'])),
1700
+ $components['modulus'],
1701
+ $components['publicExponent']
1702
+ );
1703
+
1704
+ $rsaOID = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA
1705
+ $RSAPublicKey = chr(0) . $RSAPublicKey;
1706
+ $RSAPublicKey = chr(3) . $this->_encodeASN1Length(strlen($RSAPublicKey)) . $RSAPublicKey;
1707
+
1708
+ $encapsulated = pack(
1709
+ 'Ca*a*',
1710
+ 48,
1711
+ $this->_encodeASN1Length(strlen($rsaOID . $RSAPublicKey)),
1712
+ $rsaOID . $RSAPublicKey
1713
+ );
1714
+
1715
+ $RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" .
1716
+ chunk_split(base64_encode($encapsulated)) .
1717
+ '-----END PUBLIC KEY-----';
1718
+
1719
+ $plaintext = str_pad($this->toBytes(), strlen($n->toBytes(true)) - 1, "\0", STR_PAD_LEFT);
1720
+
1721
+ if (openssl_public_encrypt($plaintext, $result, $RSAPublicKey, OPENSSL_NO_PADDING)) {
1722
+ return new static($result, 256);
1723
+ }
1724
+ }
1725
+
1726
+ if (MATH_BIGINTEGER_MODE == self::MODE_BCMATH) {
1727
+ $temp = new static();
1728
+ $temp->value = bcpowmod($this->value, $e->value, $n->value, 0);
1729
+
1730
+ return $this->_normalize($temp);
1731
+ }
1732
+
1733
+ if (empty($e->value)) {
1734
+ $temp = new static();
1735
+ $temp->value = array(1);
1736
+ return $this->_normalize($temp);
1737
+ }
1738
+
1739
+ if ($e->value == array(1)) {
1740
+ list(, $temp) = $this->divide($n);
1741
+ return $this->_normalize($temp);
1742
+ }
1743
+
1744
+ if ($e->value == array(2)) {
1745
+ $temp = new static();
1746
+ $temp->value = $this->_square($this->value);
1747
+ list(, $temp) = $temp->divide($n);
1748
+ return $this->_normalize($temp);
1749
+ }
1750
+
1751
+ return $this->_normalize($this->_slidingWindow($e, $n, self::BARRETT));
1752
+
1753
+ // the following code, although not callable, can be run independently of the above code
1754
+ // although the above code performed better in my benchmarks the following could might
1755
+ // perform better under different circumstances. in lieu of deleting it it's just been
1756
+ // made uncallable
1757
+
1758
+ // is the modulo odd?
1759
+ if ($n->value[0] & 1) {
1760
+ return $this->_normalize($this->_slidingWindow($e, $n, self::MONTGOMERY));
1761
+ }
1762
+ // if it's not, it's even
1763
+
1764
+ // find the lowest set bit (eg. the max pow of 2 that divides $n)
1765
+ for ($i = 0; $i < count($n->value); ++$i) {
1766
+ if ($n->value[$i]) {
1767
+ $temp = decbin($n->value[$i]);
1768
+ $j = strlen($temp) - strrpos($temp, '1') - 1;
1769
+ $j+= 26 * $i;
1770
+ break;
1771
+ }
1772
+ }
1773
+ // at this point, 2^$j * $n/(2^$j) == $n
1774
+
1775
+ $mod1 = $n->copy();
1776
+ $mod1->_rshift($j);
1777
+ $mod2 = new static();
1778
+ $mod2->value = array(1);
1779
+ $mod2->_lshift($j);
1780
+
1781
+ $part1 = ($mod1->value != array(1)) ? $this->_slidingWindow($e, $mod1, self::MONTGOMERY) : new static();
1782
+ $part2 = $this->_slidingWindow($e, $mod2, self::POWEROF2);
1783
+
1784
+ $y1 = $mod2->modInverse($mod1);
1785
+ $y2 = $mod1->modInverse($mod2);
1786
+
1787
+ $result = $part1->multiply($mod2);
1788
+ $result = $result->multiply($y1);
1789
+
1790
+ $temp = $part2->multiply($mod1);
1791
+ $temp = $temp->multiply($y2);
1792
+
1793
+ $result = $result->add($temp);
1794
+ list(, $result) = $result->divide($n);
1795
+
1796
+ return $this->_normalize($result);
1797
+ }
1798
+
1799
+ /**
1800
+ * Performs modular exponentiation.
1801
+ *
1802
+ * Alias for modPow().
1803
+ *
1804
+ * @param \phpseclib\Math\BigInteger $e
1805
+ * @param \phpseclib\Math\BigInteger $n
1806
+ * @return \phpseclib\Math\BigInteger
1807
+ * @access public
1808
+ */
1809
+ function powMod($e, $n)
1810
+ {
1811
+ return $this->modPow($e, $n);
1812
+ }
1813
+
1814
+ /**
1815
+ * Sliding Window k-ary Modular Exponentiation
1816
+ *
1817
+ * Based on {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=27 HAC 14.85} /
1818
+ * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=210 MPM 7.7}. In a departure from those algorithims,
1819
+ * however, this function performs a modular reduction after every multiplication and squaring operation.
1820
+ * As such, this function has the same preconditions that the reductions being used do.
1821
+ *
1822
+ * @param \phpseclib\Math\BigInteger $e
1823
+ * @param \phpseclib\Math\BigInteger $n
1824
+ * @param int $mode
1825
+ * @return \phpseclib\Math\BigInteger
1826
+ * @access private
1827
+ */
1828
+ function _slidingWindow($e, $n, $mode)
1829
+ {
1830
+ static $window_ranges = array(7, 25, 81, 241, 673, 1793); // from BigInteger.java's oddModPow function
1831
+ //static $window_ranges = array(0, 7, 36, 140, 450, 1303, 3529); // from MPM 7.3.1
1832
+
1833
+ $e_value = $e->value;
1834
+ $e_length = count($e_value) - 1;
1835
+ $e_bits = decbin($e_value[$e_length]);
1836
+ for ($i = $e_length - 1; $i >= 0; --$i) {
1837
+ $e_bits.= str_pad(decbin($e_value[$i]), self::$base, '0', STR_PAD_LEFT);
1838
+ }
1839
+
1840
+ $e_length = strlen($e_bits);
1841
+
1842
+ // calculate the appropriate window size.
1843
+ // $window_size == 3 if $window_ranges is between 25 and 81, for example.
1844
+ for ($i = 0, $window_size = 1; $i < count($window_ranges) && $e_length > $window_ranges[$i]; ++$window_size, ++$i) {
1845
+ }
1846
+
1847
+ $n_value = $n->value;
1848
+
1849
+ // precompute $this^0 through $this^$window_size
1850
+ $powers = array();
1851
+ $powers[1] = $this->_prepareReduce($this->value, $n_value, $mode);
1852
+ $powers[2] = $this->_squareReduce($powers[1], $n_value, $mode);
1853
+
1854
+ // we do every other number since substr($e_bits, $i, $j+1) (see below) is supposed to end
1855
+ // in a 1. ie. it's supposed to be odd.
1856
+ $temp = 1 << ($window_size - 1);
1857
+ for ($i = 1; $i < $temp; ++$i) {
1858
+ $i2 = $i << 1;
1859
+ $powers[$i2 + 1] = $this->_multiplyReduce($powers[$i2 - 1], $powers[2], $n_value, $mode);
1860
+ }
1861
+
1862
+ $result = array(1);
1863
+ $result = $this->_prepareReduce($result, $n_value, $mode);
1864
+
1865
+ for ($i = 0; $i < $e_length;) {
1866
+ if (!$e_bits[$i]) {
1867
+ $result = $this->_squareReduce($result, $n_value, $mode);
1868
+ ++$i;
1869
+ } else {
1870
+ for ($j = $window_size - 1; $j > 0; --$j) {
1871
+ if (!empty($e_bits[$i + $j])) {
1872
+ break;
1873
+ }
1874
+ }
1875
+
1876
+ // eg. the length of substr($e_bits, $i, $j + 1)
1877
+ for ($k = 0; $k <= $j; ++$k) {
1878
+ $result = $this->_squareReduce($result, $n_value, $mode);
1879
+ }
1880
+
1881
+ $result = $this->_multiplyReduce($result, $powers[bindec(substr($e_bits, $i, $j + 1))], $n_value, $mode);
1882
+
1883
+ $i += $j + 1;
1884
+ }
1885
+ }
1886
+
1887
+ $temp = new static();
1888
+ $temp->value = $this->_reduce($result, $n_value, $mode);
1889
+
1890
+ return $temp;
1891
+ }
1892
+
1893
+ /**
1894
+ * Modular reduction
1895
+ *
1896
+ * For most $modes this will return the remainder.
1897
+ *
1898
+ * @see self::_slidingWindow()
1899
+ * @access private
1900
+ * @param array $x
1901
+ * @param array $n
1902
+ * @param int $mode
1903
+ * @return array
1904
+ */
1905
+ function _reduce($x, $n, $mode)
1906
+ {
1907
+ switch ($mode) {
1908
+ case self::MONTGOMERY:
1909
+ return $this->_montgomery($x, $n);
1910
+ case self::BARRETT:
1911
+ return $this->_barrett($x, $n);
1912
+ case self::POWEROF2:
1913
+ $lhs = new static();
1914
+ $lhs->value = $x;
1915
+ $rhs = new static();
1916
+ $rhs->value = $n;
1917
+ return $x->_mod2($n);
1918
+ case self::CLASSIC:
1919
+ $lhs = new static();
1920
+ $lhs->value = $x;
1921
+ $rhs = new static();
1922
+ $rhs->value = $n;
1923
+ list(, $temp) = $lhs->divide($rhs);
1924
+ return $temp->value;
1925
+ case self::NONE:
1926
+ return $x;
1927
+ default:
1928
+ // an invalid $mode was provided
1929
+ }
1930
+ }
1931
+
1932
+ /**
1933
+ * Modular reduction preperation
1934
+ *
1935
+ * @see self::_slidingWindow()
1936
+ * @access private
1937
+ * @param array $x
1938
+ * @param array $n
1939
+ * @param int $mode
1940
+ * @return array
1941
+ */
1942
+ function _prepareReduce($x, $n, $mode)
1943
+ {
1944
+ if ($mode == self::MONTGOMERY) {
1945
+ return $this->_prepMontgomery($x, $n);
1946
+ }
1947
+ return $this->_reduce($x, $n, $mode);
1948
+ }
1949
+
1950
+ /**
1951
+ * Modular multiply
1952
+ *
1953
+ * @see self::_slidingWindow()
1954
+ * @access private
1955
+ * @param array $x
1956
+ * @param array $y
1957
+ * @param array $n
1958
+ * @param int $mode
1959
+ * @return array
1960
+ */
1961
+ function _multiplyReduce($x, $y, $n, $mode)
1962
+ {
1963
+ if ($mode == self::MONTGOMERY) {
1964
+ return $this->_montgomeryMultiply($x, $y, $n);
1965
+ }
1966
+ $temp = $this->_multiply($x, false, $y, false);
1967
+ return $this->_reduce($temp[self::VALUE], $n, $mode);
1968
+ }
1969
+
1970
+ /**
1971
+ * Modular square
1972
+ *
1973
+ * @see self::_slidingWindow()
1974
+ * @access private
1975
+ * @param array $x
1976
+ * @param array $n
1977
+ * @param int $mode
1978
+ * @return array
1979
+ */
1980
+ function _squareReduce($x, $n, $mode)
1981
+ {
1982
+ if ($mode == self::MONTGOMERY) {
1983
+ return $this->_montgomeryMultiply($x, $x, $n);
1984
+ }
1985
+ return $this->_reduce($this->_square($x), $n, $mode);
1986
+ }
1987
+
1988
+ /**
1989
+ * Modulos for Powers of Two
1990
+ *
1991
+ * Calculates $x%$n, where $n = 2**$e, for some $e. Since this is basically the same as doing $x & ($n-1),
1992
+ * we'll just use this function as a wrapper for doing that.
1993
+ *
1994
+ * @see self::_slidingWindow()
1995
+ * @access private
1996
+ * @param \phpseclib\Math\BigInteger
1997
+ * @return \phpseclib\Math\BigInteger
1998
+ */
1999
+ function _mod2($n)
2000
+ {
2001
+ $temp = new static();
2002
+ $temp->value = array(1);
2003
+ return $this->bitwise_and($n->subtract($temp));
2004
+ }
2005
+
2006
+ /**
2007
+ * Barrett Modular Reduction
2008
+ *
2009
+ * See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=14 HAC 14.3.3} /
2010
+ * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=165 MPM 6.2.5} for more information. Modified slightly,
2011
+ * so as not to require negative numbers (initially, this script didn't support negative numbers).
2012
+ *
2013
+ * Employs "folding", as described at
2014
+ * {@link http://www.cosic.esat.kuleuven.be/publications/thesis-149.pdf#page=66 thesis-149.pdf#page=66}. To quote from
2015
+ * it, "the idea [behind folding] is to find a value x' such that x (mod m) = x' (mod m), with x' being smaller than x."
2016
+ *
2017
+ * Unfortunately, the "Barrett Reduction with Folding" algorithm described in thesis-149.pdf is not, as written, all that
2018
+ * usable on account of (1) its not using reasonable radix points as discussed in
2019
+ * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=162 MPM 6.2.2} and (2) the fact that, even with reasonable
2020
+ * radix points, it only works when there are an even number of digits in the denominator. The reason for (2) is that
2021
+ * (x >> 1) + (x >> 1) != x / 2 + x / 2. If x is even, they're the same, but if x is odd, they're not. See the in-line
2022
+ * comments for details.
2023
+ *
2024
+ * @see self::_slidingWindow()
2025
+ * @access private
2026
+ * @param array $n
2027
+ * @param array $m
2028
+ * @return array
2029
+ */
2030
+ function _barrett($n, $m)
2031
+ {
2032
+ static $cache = array(
2033
+ self::VARIABLE => array(),
2034
+ self::DATA => array()
2035
+ );
2036
+
2037
+ $m_length = count($m);
2038
+
2039
+ // if ($this->_compare($n, $this->_square($m)) >= 0) {
2040
+ if (count($n) > 2 * $m_length) {
2041
+ $lhs = new static();
2042
+ $rhs = new static();
2043
+ $lhs->value = $n;
2044
+ $rhs->value = $m;
2045
+ list(, $temp) = $lhs->divide($rhs);
2046
+ return $temp->value;
2047
+ }
2048
+
2049
+ // if (m.length >> 1) + 2 <= m.length then m is too small and n can't be reduced
2050
+ if ($m_length < 5) {
2051
+ return $this->_regularBarrett($n, $m);
2052
+ }
2053
+
2054
+ // n = 2 * m.length
2055
+
2056
+ if (($key = array_search($m, $cache[self::VARIABLE])) === false) {
2057
+ $key = count($cache[self::VARIABLE]);
2058
+ $cache[self::VARIABLE][] = $m;
2059
+
2060
+ $lhs = new static();
2061
+ $lhs_value = &$lhs->value;
2062
+ $lhs_value = $this->_array_repeat(0, $m_length + ($m_length >> 1));
2063
+ $lhs_value[] = 1;
2064
+ $rhs = new static();
2065
+ $rhs->value = $m;
2066
+
2067
+ list($u, $m1) = $lhs->divide($rhs);
2068
+ $u = $u->value;
2069
+ $m1 = $m1->value;
2070
+
2071
+ $cache[self::DATA][] = array(
2072
+ 'u' => $u, // m.length >> 1 (technically (m.length >> 1) + 1)
2073
+ 'm1'=> $m1 // m.length
2074
+ );
2075
+ } else {
2076
+ extract($cache[self::DATA][$key]);
2077
+ }
2078
+
2079
+ $cutoff = $m_length + ($m_length >> 1);
2080
+ $lsd = array_slice($n, 0, $cutoff); // m.length + (m.length >> 1)
2081
+ $msd = array_slice($n, $cutoff); // m.length >> 1
2082
+ $lsd = $this->_trim($lsd);
2083
+ $temp = $this->_multiply($msd, false, $m1, false);
2084
+ $n = $this->_add($lsd, false, $temp[self::VALUE], false); // m.length + (m.length >> 1) + 1
2085
+
2086
+ if ($m_length & 1) {
2087
+ return $this->_regularBarrett($n[self::VALUE], $m);
2088
+ }
2089
+
2090
+ // (m.length + (m.length >> 1) + 1) - (m.length - 1) == (m.length >> 1) + 2
2091
+ $temp = array_slice($n[self::VALUE], $m_length - 1);
2092
+ // if even: ((m.length >> 1) + 2) + (m.length >> 1) == m.length + 2
2093
+ // if odd: ((m.length >> 1) + 2) + (m.length >> 1) == (m.length - 1) + 2 == m.length + 1
2094
+ $temp = $this->_multiply($temp, false, $u, false);
2095
+ // if even: (m.length + 2) - ((m.length >> 1) + 1) = m.length - (m.length >> 1) + 1
2096
+ // if odd: (m.length + 1) - ((m.length >> 1) + 1) = m.length - (m.length >> 1)
2097
+ $temp = array_slice($temp[self::VALUE], ($m_length >> 1) + 1);
2098
+ // if even: (m.length - (m.length >> 1) + 1) + m.length = 2 * m.length - (m.length >> 1) + 1
2099
+ // if odd: (m.length - (m.length >> 1)) + m.length = 2 * m.length - (m.length >> 1)
2100
+ $temp = $this->_multiply($temp, false, $m, false);
2101
+
2102
+ // at this point, if m had an odd number of digits, we'd be subtracting a 2 * m.length - (m.length >> 1) digit
2103
+ // number from a m.length + (m.length >> 1) + 1 digit number. ie. there'd be an extra digit and the while loop
2104
+ // following this comment would loop a lot (hence our calling _regularBarrett() in that situation).
2105
+
2106
+ $result = $this->_subtract($n[self::VALUE], false, $temp[self::VALUE], false);
2107
+
2108
+ while ($this->_compare($result[self::VALUE], $result[self::SIGN], $m, false) >= 0) {
2109
+ $result = $this->_subtract($result[self::VALUE], $result[self::SIGN], $m, false);
2110
+ }
2111
+
2112
+ return $result[self::VALUE];
2113
+ }
2114
+
2115
+ /**
2116
+ * (Regular) Barrett Modular Reduction
2117
+ *
2118
+ * For numbers with more than four digits BigInteger::_barrett() is faster. The difference between that and this
2119
+ * is that this function does not fold the denominator into a smaller form.
2120
+ *
2121
+ * @see self::_slidingWindow()
2122
+ * @access private
2123
+ * @param array $x
2124
+ * @param array $n
2125
+ * @return array
2126
+ */
2127
+ function _regularBarrett($x, $n)
2128
+ {
2129
+ static $cache = array(
2130
+ self::VARIABLE => array(),
2131
+ self::DATA => array()
2132
+ );
2133
+
2134
+ $n_length = count($n);
2135
+
2136
+ if (count($x) > 2 * $n_length) {
2137
+ $lhs = new static();
2138
+ $rhs = new static();
2139
+ $lhs->value = $x;
2140
+ $rhs->value = $n;
2141
+ list(, $temp) = $lhs->divide($rhs);
2142
+ return $temp->value;
2143
+ }
2144
+
2145
+ if (($key = array_search($n, $cache[self::VARIABLE])) === false) {
2146
+ $key = count($cache[self::VARIABLE]);
2147
+ $cache[self::VARIABLE][] = $n;
2148
+ $lhs = new static();
2149
+ $lhs_value = &$lhs->value;
2150
+ $lhs_value = $this->_array_repeat(0, 2 * $n_length);
2151
+ $lhs_value[] = 1;
2152
+ $rhs = new static();
2153
+ $rhs->value = $n;
2154
+ list($temp, ) = $lhs->divide($rhs); // m.length
2155
+ $cache[self::DATA][] = $temp->value;
2156
+ }
2157
+
2158
+ // 2 * m.length - (m.length - 1) = m.length + 1
2159
+ $temp = array_slice($x, $n_length - 1);
2160
+ // (m.length + 1) + m.length = 2 * m.length + 1
2161
+ $temp = $this->_multiply($temp, false, $cache[self::DATA][$key], false);
2162
+ // (2 * m.length + 1) - (m.length - 1) = m.length + 2
2163
+ $temp = array_slice($temp[self::VALUE], $n_length + 1);
2164
+
2165
+ // m.length + 1
2166
+ $result = array_slice($x, 0, $n_length + 1);
2167
+ // m.length + 1
2168
+ $temp = $this->_multiplyLower($temp, false, $n, false, $n_length + 1);
2169
+ // $temp == array_slice($temp->_multiply($temp, false, $n, false)->value, 0, $n_length + 1)
2170
+
2171
+ if ($this->_compare($result, false, $temp[self::VALUE], $temp[self::SIGN]) < 0) {
2172
+ $corrector_value = $this->_array_repeat(0, $n_length + 1);
2173
+ $corrector_value[count($corrector_value)] = 1;
2174
+ $result = $this->_add($result, false, $corrector_value, false);
2175
+ $result = $result[self::VALUE];
2176
+ }
2177
+
2178
+ // at this point, we're subtracting a number with m.length + 1 digits from another number with m.length + 1 digits
2179
+ $result = $this->_subtract($result, false, $temp[self::VALUE], $temp[self::SIGN]);
2180
+ while ($this->_compare($result[self::VALUE], $result[self::SIGN], $n, false) > 0) {
2181
+ $result = $this->_subtract($result[self::VALUE], $result[self::SIGN], $n, false);
2182
+ }
2183
+
2184
+ return $result[self::VALUE];
2185
+ }
2186
+
2187
+ /**
2188
+ * Performs long multiplication up to $stop digits
2189
+ *
2190
+ * If you're going to be doing array_slice($product->value, 0, $stop), some cycles can be saved.
2191
+ *
2192
+ * @see self::_regularBarrett()
2193
+ * @param array $x_value
2194
+ * @param bool $x_negative
2195
+ * @param array $y_value
2196
+ * @param bool $y_negative
2197
+ * @param int $stop
2198
+ * @return array
2199
+ * @access private
2200
+ */
2201
+ function _multiplyLower($x_value, $x_negative, $y_value, $y_negative, $stop)
2202
+ {
2203
+ $x_length = count($x_value);
2204
+ $y_length = count($y_value);
2205
+
2206
+ if (!$x_length || !$y_length) { // a 0 is being multiplied
2207
+ return array(
2208
+ self::VALUE => array(),
2209
+ self::SIGN => false
2210
+ );
2211
+ }
2212
+
2213
+ if ($x_length < $y_length) {
2214
+ $temp = $x_value;
2215
+ $x_value = $y_value;
2216
+ $y_value = $temp;
2217
+
2218
+ $x_length = count($x_value);
2219
+ $y_length = count($y_value);
2220
+ }
2221
+
2222
+ $product_value = $this->_array_repeat(0, $x_length + $y_length);
2223
+
2224
+ // the following for loop could be removed if the for loop following it
2225
+ // (the one with nested for loops) initially set $i to 0, but
2226
+ // doing so would also make the result in one set of unnecessary adds,
2227
+ // since on the outermost loops first pass, $product->value[$k] is going
2228
+ // to always be 0
2229
+
2230
+ $carry = 0;
2231
+
2232
+ for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0, $k = $i
2233
+ $temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0
2234
+ $carry = self::$base === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
2235
+ $product_value[$j] = (int) ($temp - self::$baseFull * $carry);
2236
+ }
2237
+
2238
+ if ($j < $stop) {
2239
+ $product_value[$j] = $carry;
2240
+ }
2241
+
2242
+ // the above for loop is what the previous comment was talking about. the
2243
+ // following for loop is the "one with nested for loops"
2244
+
2245
+ for ($i = 1; $i < $y_length; ++$i) {
2246
+ $carry = 0;
2247
+
2248
+ for ($j = 0, $k = $i; $j < $x_length && $k < $stop; ++$j, ++$k) {
2249
+ $temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry;
2250
+ $carry = self::$base === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
2251
+ $product_value[$k] = (int) ($temp - self::$baseFull * $carry);
2252
+ }
2253
+
2254
+ if ($k < $stop) {
2255
+ $product_value[$k] = $carry;
2256
+ }
2257
+ }
2258
+
2259
+ return array(
2260
+ self::VALUE => $this->_trim($product_value),
2261
+ self::SIGN => $x_negative != $y_negative
2262
+ );
2263
+ }
2264
+
2265
+ /**
2266
+ * Montgomery Modular Reduction
2267
+ *
2268
+ * ($x->_prepMontgomery($n))->_montgomery($n) yields $x % $n.
2269
+ * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=170 MPM 6.3} provides insights on how this can be
2270
+ * improved upon (basically, by using the comba method). gcd($n, 2) must be equal to one for this function
2271
+ * to work correctly.
2272
+ *
2273
+ * @see self::_prepMontgomery()
2274
+ * @see self::_slidingWindow()
2275
+ * @access private
2276
+ * @param array $x
2277
+ * @param array $n
2278
+ * @return array
2279
+ */
2280
+ function _montgomery($x, $n)
2281
+ {
2282
+ static $cache = array(
2283
+ self::VARIABLE => array(),
2284
+ self::DATA => array()
2285
+ );
2286
+
2287
+ if (($key = array_search($n, $cache[self::VARIABLE])) === false) {
2288
+ $key = count($cache[self::VARIABLE]);
2289
+ $cache[self::VARIABLE][] = $x;
2290
+ $cache[self::DATA][] = $this->_modInverse67108864($n);
2291
+ }
2292
+
2293
+ $k = count($n);
2294
+
2295
+ $result = array(self::VALUE => $x);
2296
+
2297
+ for ($i = 0; $i < $k; ++$i) {
2298
+ $temp = $result[self::VALUE][$i] * $cache[self::DATA][$key];
2299
+ $temp = $temp - self::$baseFull * (self::$base === 26 ? intval($temp / 0x4000000) : ($temp >> 31));
2300
+ $temp = $this->_regularMultiply(array($temp), $n);
2301
+ $temp = array_merge($this->_array_repeat(0, $i), $temp);
2302
+ $result = $this->_add($result[self::VALUE], false, $temp, false);
2303
+ }
2304
+
2305
+ $result[self::VALUE] = array_slice($result[self::VALUE], $k);
2306
+
2307
+ if ($this->_compare($result, false, $n, false) >= 0) {
2308
+ $result = $this->_subtract($result[self::VALUE], false, $n, false);
2309
+ }
2310
+
2311
+ return $result[self::VALUE];
2312
+ }
2313
+
2314
+ /**
2315
+ * Montgomery Multiply
2316
+ *
2317
+ * Interleaves the montgomery reduction and long multiplication algorithms together as described in
2318
+ * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=13 HAC 14.36}
2319
+ *
2320
+ * @see self::_prepMontgomery()
2321
+ * @see self::_montgomery()
2322
+ * @access private
2323
+ * @param array $x
2324
+ * @param array $y
2325
+ * @param array $m
2326
+ * @return array
2327
+ */
2328
+ function _montgomeryMultiply($x, $y, $m)
2329
+ {
2330
+ $temp = $this->_multiply($x, false, $y, false);
2331
+ return $this->_montgomery($temp[self::VALUE], $m);
2332
+
2333
+ // the following code, although not callable, can be run independently of the above code
2334
+ // although the above code performed better in my benchmarks the following could might
2335
+ // perform better under different circumstances. in lieu of deleting it it's just been
2336
+ // made uncallable
2337
+
2338
+ static $cache = array(
2339
+ self::VARIABLE => array(),
2340
+ self::DATA => array()
2341
+ );
2342
+
2343
+ if (($key = array_search($m, $cache[self::VARIABLE])) === false) {
2344
+ $key = count($cache[self::VARIABLE]);
2345
+ $cache[self::VARIABLE][] = $m;
2346
+ $cache[self::DATA][] = $this->_modInverse67108864($m);
2347
+ }
2348
+
2349
+ $n = max(count($x), count($y), count($m));
2350
+ $x = array_pad($x, $n, 0);
2351
+ $y = array_pad($y, $n, 0);
2352
+ $m = array_pad($m, $n, 0);
2353
+ $a = array(self::VALUE => $this->_array_repeat(0, $n + 1));
2354
+ for ($i = 0; $i < $n; ++$i) {
2355
+ $temp = $a[self::VALUE][0] + $x[$i] * $y[0];
2356
+ $temp = $temp - self::$baseFull * (self::$base === 26 ? intval($temp / 0x4000000) : ($temp >> 31));
2357
+ $temp = $temp * $cache[self::DATA][$key];
2358
+ $temp = $temp - self::$baseFull * (self::$base === 26 ? intval($temp / 0x4000000) : ($temp >> 31));
2359
+ $temp = $this->_add($this->_regularMultiply(array($x[$i]), $y), false, $this->_regularMultiply(array($temp), $m), false);
2360
+ $a = $this->_add($a[self::VALUE], false, $temp[self::VALUE], false);
2361
+ $a[self::VALUE] = array_slice($a[self::VALUE], 1);
2362
+ }
2363
+ if ($this->_compare($a[self::VALUE], false, $m, false) >= 0) {
2364
+ $a = $this->_subtract($a[self::VALUE], false, $m, false);
2365
+ }
2366
+ return $a[self::VALUE];
2367
+ }
2368
+
2369
+ /**
2370
+ * Prepare a number for use in Montgomery Modular Reductions
2371
+ *
2372
+ * @see self::_montgomery()
2373
+ * @see self::_slidingWindow()
2374
+ * @access private
2375
+ * @param array $x
2376
+ * @param array $n
2377
+ * @return array
2378
+ */
2379
+ function _prepMontgomery($x, $n)
2380
+ {
2381
+ $lhs = new static();
2382
+ $lhs->value = array_merge($this->_array_repeat(0, count($n)), $x);
2383
+ $rhs = new static();
2384
+ $rhs->value = $n;
2385
+
2386
+ list(, $temp) = $lhs->divide($rhs);
2387
+ return $temp->value;
2388
+ }
2389
+
2390
+ /**
2391
+ * Modular Inverse of a number mod 2**26 (eg. 67108864)
2392
+ *
2393
+ * Based off of the bnpInvDigit function implemented and justified in the following URL:
2394
+ *
2395
+ * {@link http://www-cs-students.stanford.edu/~tjw/jsbn/jsbn.js}
2396
+ *
2397
+ * The following URL provides more info:
2398
+ *
2399
+ * {@link http://groups.google.com/group/sci.crypt/msg/7a137205c1be7d85}
2400
+ *
2401
+ * As for why we do all the bitmasking... strange things can happen when converting from floats to ints. For
2402
+ * instance, on some computers, var_dump((int) -4294967297) yields int(-1) and on others, it yields
2403
+ * int(-2147483648). To avoid problems stemming from this, we use bitmasks to guarantee that ints aren't
2404
+ * auto-converted to floats. The outermost bitmask is present because without it, there's no guarantee that
2405
+ * the "residue" returned would be the so-called "common residue". We use fmod, in the last step, because the
2406
+ * maximum possible $x is 26 bits and the maximum $result is 16 bits. Thus, we have to be able to handle up to
2407
+ * 40 bits, which only 64-bit floating points will support.
2408
+ *
2409
+ * Thanks to Pedro Gimeno Fortea for input!
2410
+ *
2411
+ * @see self::_montgomery()
2412
+ * @access private
2413
+ * @param array $x
2414
+ * @return int
2415
+ */
2416
+ function _modInverse67108864($x) // 2**26 == 67,108,864
2417
+ {
2418
+ $x = -$x[0];
2419
+ $result = $x & 0x3; // x**-1 mod 2**2
2420
+ $result = ($result * (2 - $x * $result)) & 0xF; // x**-1 mod 2**4
2421
+ $result = ($result * (2 - ($x & 0xFF) * $result)) & 0xFF; // x**-1 mod 2**8
2422
+ $result = ($result * ((2 - ($x & 0xFFFF) * $result) & 0xFFFF)) & 0xFFFF; // x**-1 mod 2**16
2423
+ $result = fmod($result * (2 - fmod($x * $result, self::$baseFull)), self::$baseFull); // x**-1 mod 2**26
2424
+ return $result & self::$maxDigit;
2425
+ }
2426
+
2427
+ /**
2428
+ * Calculates modular inverses.
2429
+ *
2430
+ * Say you have (30 mod 17 * x mod 17) mod 17 == 1. x can be found using modular inverses.
2431
+ *
2432
+ * Here's an example:
2433
+ * <code>
2434
+ * <?php
2435
+ * $a = new \phpseclib\Math\BigInteger(30);
2436
+ * $b = new \phpseclib\Math\BigInteger(17);
2437
+ *
2438
+ * $c = $a->modInverse($b);
2439
+ * echo $c->toString(); // outputs 4
2440
+ *
2441
+ * echo "\r\n";
2442
+ *
2443
+ * $d = $a->multiply($c);
2444
+ * list(, $d) = $d->divide($b);
2445
+ * echo $d; // outputs 1 (as per the definition of modular inverse)
2446
+ * ?>
2447
+ * </code>
2448
+ *
2449
+ * @param \phpseclib\Math\BigInteger $n
2450
+ * @return \phpseclib\Math\BigInteger|false
2451
+ * @access public
2452
+ * @internal See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=21 HAC 14.64} for more information.
2453
+ */
2454
+ function modInverse($n)
2455
+ {
2456
+ switch (MATH_BIGINTEGER_MODE) {
2457
+ case self::MODE_GMP:
2458
+ $temp = new static();
2459
+ $temp->value = gmp_invert($this->value, $n->value);
2460
+
2461
+ return ($temp->value === false) ? false : $this->_normalize($temp);
2462
+ }
2463
+
2464
+ static $zero, $one;
2465
+ if (!isset($zero)) {
2466
+ $zero = new static();
2467
+ $one = new static(1);
2468
+ }
2469
+
2470
+ // $x mod -$n == $x mod $n.
2471
+ $n = $n->abs();
2472
+
2473
+ if ($this->compare($zero) < 0) {
2474
+ $temp = $this->abs();
2475
+ $temp = $temp->modInverse($n);
2476
+ return $this->_normalize($n->subtract($temp));
2477
+ }
2478
+
2479
+ extract($this->extendedGCD($n));
2480
+
2481
+ if (!$gcd->equals($one)) {
2482
+ return false;
2483
+ }
2484
+
2485
+ $x = $x->compare($zero) < 0 ? $x->add($n) : $x;
2486
+
2487
+ return $this->compare($zero) < 0 ? $this->_normalize($n->subtract($x)) : $this->_normalize($x);
2488
+ }
2489
+
2490
+ /**
2491
+ * Calculates the greatest common divisor and Bezout's identity.
2492
+ *
2493
+ * Say you have 693 and 609. The GCD is 21. Bezout's identity states that there exist integers x and y such that
2494
+ * 693*x + 609*y == 21. In point of fact, there are actually an infinite number of x and y combinations and which
2495
+ * combination is returned is dependent upon which mode is in use. See
2496
+ * {@link http://en.wikipedia.org/wiki/B%C3%A9zout%27s_identity Bezout's identity - Wikipedia} for more information.
2497
+ *
2498
+ * Here's an example:
2499
+ * <code>
2500
+ * <?php
2501
+ * $a = new \phpseclib\Math\BigInteger(693);
2502
+ * $b = new \phpseclib\Math\BigInteger(609);
2503
+ *
2504
+ * extract($a->extendedGCD($b));
2505
+ *
2506
+ * echo $gcd->toString() . "\r\n"; // outputs 21
2507
+ * echo $a->toString() * $x->toString() + $b->toString() * $y->toString(); // outputs 21
2508
+ * ?>
2509
+ * </code>
2510
+ *
2511
+ * @param \phpseclib\Math\BigInteger $n
2512
+ * @return \phpseclib\Math\BigInteger
2513
+ * @access public
2514
+ * @internal Calculates the GCD using the binary xGCD algorithim described in
2515
+ * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=19 HAC 14.61}. As the text above 14.61 notes,
2516
+ * the more traditional algorithim requires "relatively costly multiple-precision divisions".
2517
+ */
2518
+ function extendedGCD($n)
2519
+ {
2520
+ switch (MATH_BIGINTEGER_MODE) {
2521
+ case self::MODE_GMP:
2522
+ extract(gmp_gcdext($this->value, $n->value));
2523
+
2524
+ return array(
2525
+ 'gcd' => $this->_normalize(new static($g)),
2526
+ 'x' => $this->_normalize(new static($s)),
2527
+ 'y' => $this->_normalize(new static($t))
2528
+ );
2529
+ case self::MODE_BCMATH:
2530
+ // it might be faster to use the binary xGCD algorithim here, as well, but (1) that algorithim works
2531
+ // best when the base is a power of 2 and (2) i don't think it'd make much difference, anyway. as is,
2532
+ // the basic extended euclidean algorithim is what we're using.
2533
+
2534
+ $u = $this->value;
2535
+ $v = $n->value;
2536
+
2537
+ $a = '1';
2538
+ $b = '0';
2539
+ $c = '0';
2540
+ $d = '1';
2541
+
2542
+ while (bccomp($v, '0', 0) != 0) {
2543
+ $q = bcdiv($u, $v, 0);
2544
+
2545
+ $temp = $u;
2546
+ $u = $v;
2547
+ $v = bcsub($temp, bcmul($v, $q, 0), 0);
2548
+
2549
+ $temp = $a;
2550
+ $a = $c;
2551
+ $c = bcsub($temp, bcmul($a, $q, 0), 0);
2552
+
2553
+ $temp = $b;
2554
+ $b = $d;
2555
+ $d = bcsub($temp, bcmul($b, $q, 0), 0);
2556
+ }
2557
+
2558
+ return array(
2559
+ 'gcd' => $this->_normalize(new static($u)),
2560
+ 'x' => $this->_normalize(new static($a)),
2561
+ 'y' => $this->_normalize(new static($b))
2562
+ );
2563
+ }
2564
+
2565
+ $y = $n->copy();
2566
+ $x = $this->copy();
2567
+ $g = new static();
2568
+ $g->value = array(1);
2569
+
2570
+ while (!(($x->value[0] & 1)|| ($y->value[0] & 1))) {
2571
+ $x->_rshift(1);
2572
+ $y->_rshift(1);
2573
+ $g->_lshift(1);
2574
+ }
2575
+
2576
+ $u = $x->copy();
2577
+ $v = $y->copy();
2578
+
2579
+ $a = new static();
2580
+ $b = new static();
2581
+ $c = new static();
2582
+ $d = new static();
2583
+
2584
+ $a->value = $d->value = $g->value = array(1);
2585
+ $b->value = $c->value = array();
2586
+
2587
+ while (!empty($u->value)) {
2588
+ while (!($u->value[0] & 1)) {
2589
+ $u->_rshift(1);
2590
+ if ((!empty($a->value) && ($a->value[0] & 1)) || (!empty($b->value) && ($b->value[0] & 1))) {
2591
+ $a = $a->add($y);
2592
+ $b = $b->subtract($x);
2593
+ }
2594
+ $a->_rshift(1);
2595
+ $b->_rshift(1);
2596
+ }
2597
+
2598
+ while (!($v->value[0] & 1)) {
2599
+ $v->_rshift(1);
2600
+ if ((!empty($d->value) && ($d->value[0] & 1)) || (!empty($c->value) && ($c->value[0] & 1))) {
2601
+ $c = $c->add($y);
2602
+ $d = $d->subtract($x);
2603
+ }
2604
+ $c->_rshift(1);
2605
+ $d->_rshift(1);
2606
+ }
2607
+
2608
+ if ($u->compare($v) >= 0) {
2609
+ $u = $u->subtract($v);
2610
+ $a = $a->subtract($c);
2611
+ $b = $b->subtract($d);
2612
+ } else {
2613
+ $v = $v->subtract($u);
2614
+ $c = $c->subtract($a);
2615
+ $d = $d->subtract($b);
2616
+ }
2617
+ }
2618
+
2619
+ return array(
2620
+ 'gcd' => $this->_normalize($g->multiply($v)),
2621
+ 'x' => $this->_normalize($c),
2622
+ 'y' => $this->_normalize($d)
2623
+ );
2624
+ }
2625
+
2626
+ /**
2627
+ * Calculates the greatest common divisor
2628
+ *
2629
+ * Say you have 693 and 609. The GCD is 21.
2630
+ *
2631
+ * Here's an example:
2632
+ * <code>
2633
+ * <?php
2634
+ * $a = new \phpseclib\Math\BigInteger(693);
2635
+ * $b = new \phpseclib\Math\BigInteger(609);
2636
+ *
2637
+ * $gcd = a->extendedGCD($b);
2638
+ *
2639
+ * echo $gcd->toString() . "\r\n"; // outputs 21
2640
+ * ?>
2641
+ * </code>
2642
+ *
2643
+ * @param \phpseclib\Math\BigInteger $n
2644
+ * @return \phpseclib\Math\BigInteger
2645
+ * @access public
2646
+ */
2647
+ function gcd($n)
2648
+ {
2649
+ extract($this->extendedGCD($n));
2650
+ return $gcd;
2651
+ }
2652
+
2653
+ /**
2654
+ * Absolute value.
2655
+ *
2656
+ * @return \phpseclib\Math\BigInteger
2657
+ * @access public
2658
+ */
2659
+ function abs()
2660
+ {
2661
+ $temp = new static();
2662
+
2663
+ switch (MATH_BIGINTEGER_MODE) {
2664
+ case self::MODE_GMP:
2665
+ $temp->value = gmp_abs($this->value);
2666
+ break;
2667
+ case self::MODE_BCMATH:
2668
+ $temp->value = (bccomp($this->value, '0', 0) < 0) ? substr($this->value, 1) : $this->value;
2669
+ break;
2670
+ default:
2671
+ $temp->value = $this->value;
2672
+ }
2673
+
2674
+ return $temp;
2675
+ }
2676
+
2677
+ /**
2678
+ * Compares two numbers.
2679
+ *
2680
+ * Although one might think !$x->compare($y) means $x != $y, it, in fact, means the opposite. The reason for this is
2681
+ * demonstrated thusly:
2682
+ *
2683
+ * $x > $y: $x->compare($y) > 0
2684
+ * $x < $y: $x->compare($y) < 0
2685
+ * $x == $y: $x->compare($y) == 0
2686
+ *
2687
+ * Note how the same comparison operator is used. If you want to test for equality, use $x->equals($y).
2688
+ *
2689
+ * @param \phpseclib\Math\BigInteger $y
2690
+ * @return int < 0 if $this is less than $y; > 0 if $this is greater than $y, and 0 if they are equal.
2691
+ * @access public
2692
+ * @see self::equals()
2693
+ * @internal Could return $this->subtract($x), but that's not as fast as what we do do.
2694
+ */
2695
+ function compare($y)
2696
+ {
2697
+ switch (MATH_BIGINTEGER_MODE) {
2698
+ case self::MODE_GMP:
2699
+ $r = gmp_cmp($this->value, $y->value);
2700
+ if ($r < -1) {
2701
+ $r = -1;
2702
+ }
2703
+ if ($r > 1) {
2704
+ $r = 1;
2705
+ }
2706
+ return $r;
2707
+ case self::MODE_BCMATH:
2708
+ return bccomp($this->value, $y->value, 0);
2709
+ }
2710
+
2711
+ return $this->_compare($this->value, $this->is_negative, $y->value, $y->is_negative);
2712
+ }
2713
+
2714
+ /**
2715
+ * Compares two numbers.
2716
+ *
2717
+ * @param array $x_value
2718
+ * @param bool $x_negative
2719
+ * @param array $y_value
2720
+ * @param bool $y_negative
2721
+ * @return int
2722
+ * @see self::compare()
2723
+ * @access private
2724
+ */
2725
+ function _compare($x_value, $x_negative, $y_value, $y_negative)
2726
+ {
2727
+ if ($x_negative != $y_negative) {
2728
+ return (!$x_negative && $y_negative) ? 1 : -1;
2729
+ }
2730
+
2731
+ $result = $x_negative ? -1 : 1;
2732
+
2733
+ if (count($x_value) != count($y_value)) {
2734
+ return (count($x_value) > count($y_value)) ? $result : -$result;
2735
+ }
2736
+ $size = max(count($x_value), count($y_value));
2737
+
2738
+ $x_value = array_pad($x_value, $size, 0);
2739
+ $y_value = array_pad($y_value, $size, 0);
2740
+
2741
+ for ($i = count($x_value) - 1; $i >= 0; --$i) {
2742
+ if ($x_value[$i] != $y_value[$i]) {
2743
+ return ($x_value[$i] > $y_value[$i]) ? $result : -$result;
2744
+ }
2745
+ }
2746
+
2747
+ return 0;
2748
+ }
2749
+
2750
+ /**
2751
+ * Tests the equality of two numbers.
2752
+ *
2753
+ * If you need to see if one number is greater than or less than another number, use BigInteger::compare()
2754
+ *
2755
+ * @param \phpseclib\Math\BigInteger $x
2756
+ * @return bool
2757
+ * @access public
2758
+ * @see self::compare()
2759
+ */
2760
+ function equals($x)
2761
+ {
2762
+ switch (MATH_BIGINTEGER_MODE) {
2763
+ case self::MODE_GMP:
2764
+ return gmp_cmp($this->value, $x->value) == 0;
2765
+ default:
2766
+ return $this->value === $x->value && $this->is_negative == $x->is_negative;
2767
+ }
2768
+ }
2769
+
2770
+ /**
2771
+ * Set Precision
2772
+ *
2773
+ * Some bitwise operations give different results depending on the precision being used. Examples include left
2774
+ * shift, not, and rotates.
2775
+ *
2776
+ * @param int $bits
2777
+ * @access public
2778
+ */
2779
+ function setPrecision($bits)
2780
+ {
2781
+ $this->precision = $bits;
2782
+ if (MATH_BIGINTEGER_MODE != self::MODE_BCMATH) {
2783
+ $this->bitmask = new static(chr((1 << ($bits & 0x7)) - 1) . str_repeat(chr(0xFF), $bits >> 3), 256);
2784
+ } else {
2785
+ $this->bitmask = new static(bcpow('2', $bits, 0));
2786
+ }
2787
+
2788
+ $temp = $this->_normalize($this);
2789
+ $this->value = $temp->value;
2790
+ }
2791
+
2792
+ /**
2793
+ * Logical And
2794
+ *
2795
+ * @param \phpseclib\Math\BigInteger $x
2796
+ * @access public
2797
+ * @internal Implemented per a request by Lluis Pamies i Juarez <lluis _a_ pamies.cat>
2798
+ * @return \phpseclib\Math\BigInteger
2799
+ */
2800
+ function bitwise_and($x)
2801
+ {
2802
+ switch (MATH_BIGINTEGER_MODE) {
2803
+ case self::MODE_GMP:
2804
+ $temp = new static();
2805
+ $temp->value = gmp_and($this->value, $x->value);
2806
+
2807
+ return $this->_normalize($temp);
2808
+ case self::MODE_BCMATH:
2809
+ $left = $this->toBytes();
2810
+ $right = $x->toBytes();
2811
+
2812
+ $length = max(strlen($left), strlen($right));
2813
+
2814
+ $left = str_pad($left, $length, chr(0), STR_PAD_LEFT);
2815
+ $right = str_pad($right, $length, chr(0), STR_PAD_LEFT);
2816
+
2817
+ return $this->_normalize(new static($left & $right, 256));
2818
+ }
2819
+
2820
+ $result = $this->copy();
2821
+
2822
+ $length = min(count($x->value), count($this->value));
2823
+
2824
+ $result->value = array_slice($result->value, 0, $length);
2825
+
2826
+ for ($i = 0; $i < $length; ++$i) {
2827
+ $result->value[$i]&= $x->value[$i];
2828
+ }
2829
+
2830
+ return $this->_normalize($result);
2831
+ }
2832
+
2833
+ /**
2834
+ * Logical Or
2835
+ *
2836
+ * @param \phpseclib\Math\BigInteger $x
2837
+ * @access public
2838
+ * @internal Implemented per a request by Lluis Pamies i Juarez <lluis _a_ pamies.cat>
2839
+ * @return \phpseclib\Math\BigInteger
2840
+ */
2841
+ function bitwise_or($x)
2842
+ {
2843
+ switch (MATH_BIGINTEGER_MODE) {
2844
+ case self::MODE_GMP:
2845
+ $temp = new static();
2846
+ $temp->value = gmp_or($this->value, $x->value);
2847
+
2848
+ return $this->_normalize($temp);
2849
+ case self::MODE_BCMATH:
2850
+ $left = $this->toBytes();
2851
+ $right = $x->toBytes();
2852
+
2853
+ $length = max(strlen($left), strlen($right));
2854
+
2855
+ $left = str_pad($left, $length, chr(0), STR_PAD_LEFT);
2856
+ $right = str_pad($right, $length, chr(0), STR_PAD_LEFT);
2857
+
2858
+ return $this->_normalize(new static($left | $right, 256));
2859
+ }
2860
+
2861
+ $length = max(count($this->value), count($x->value));
2862
+ $result = $this->copy();
2863
+ $result->value = array_pad($result->value, $length, 0);
2864
+ $x->value = array_pad($x->value, $length, 0);
2865
+
2866
+ for ($i = 0; $i < $length; ++$i) {
2867
+ $result->value[$i]|= $x->value[$i];
2868
+ }
2869
+
2870
+ return $this->_normalize($result);
2871
+ }
2872
+
2873
+ /**
2874
+ * Logical Exclusive-Or
2875
+ *
2876
+ * @param \phpseclib\Math\BigInteger $x
2877
+ * @access public
2878
+ * @internal Implemented per a request by Lluis Pamies i Juarez <lluis _a_ pamies.cat>
2879
+ * @return \phpseclib\Math\BigInteger
2880
+ */
2881
+ function bitwise_xor($x)
2882
+ {
2883
+ switch (MATH_BIGINTEGER_MODE) {
2884
+ case self::MODE_GMP:
2885
+ $temp = new static();
2886
+ $temp->value = gmp_xor(gmp_abs($this->value), gmp_abs($x->value));
2887
+ return $this->_normalize($temp);
2888
+ case self::MODE_BCMATH:
2889
+ $left = $this->toBytes();
2890
+ $right = $x->toBytes();
2891
+
2892
+ $length = max(strlen($left), strlen($right));
2893
+
2894
+ $left = str_pad($left, $length, chr(0), STR_PAD_LEFT);
2895
+ $right = str_pad($right, $length, chr(0), STR_PAD_LEFT);
2896
+
2897
+ return $this->_normalize(new static($left ^ $right, 256));
2898
+ }
2899
+
2900
+ $length = max(count($this->value), count($x->value));
2901
+ $result = $this->copy();
2902
+ $result->is_negative = false;
2903
+ $result->value = array_pad($result->value, $length, 0);
2904
+ $x->value = array_pad($x->value, $length, 0);
2905
+
2906
+ for ($i = 0; $i < $length; ++$i) {
2907
+ $result->value[$i]^= $x->value[$i];
2908
+ }
2909
+
2910
+ return $this->_normalize($result);
2911
+ }
2912
+
2913
+ /**
2914
+ * Logical Not
2915
+ *
2916
+ * @access public
2917
+ * @internal Implemented per a request by Lluis Pamies i Juarez <lluis _a_ pamies.cat>
2918
+ * @return \phpseclib\Math\BigInteger
2919
+ */
2920
+ function bitwise_not()
2921
+ {
2922
+ // calculuate "not" without regard to $this->precision
2923
+ // (will always result in a smaller number. ie. ~1 isn't 1111 1110 - it's 0)
2924
+ $temp = $this->toBytes();
2925
+ if ($temp == '') {
2926
+ return $this->_normalize(new static());
2927
+ }
2928
+ $pre_msb = decbin(ord($temp[0]));
2929
+ $temp = ~$temp;
2930
+ $msb = decbin(ord($temp[0]));
2931
+ if (strlen($msb) == 8) {
2932
+ $msb = substr($msb, strpos($msb, '0'));
2933
+ }
2934
+ $temp[0] = chr(bindec($msb));
2935
+
2936
+ // see if we need to add extra leading 1's
2937
+ $current_bits = strlen($pre_msb) + 8 * strlen($temp) - 8;
2938
+ $new_bits = $this->precision - $current_bits;
2939
+ if ($new_bits <= 0) {
2940
+ return $this->_normalize(new static($temp, 256));
2941
+ }
2942
+
2943
+ // generate as many leading 1's as we need to.
2944
+ $leading_ones = chr((1 << ($new_bits & 0x7)) - 1) . str_repeat(chr(0xFF), $new_bits >> 3);
2945
+ $this->_base256_lshift($leading_ones, $current_bits);
2946
+
2947
+ $temp = str_pad($temp, strlen($leading_ones), chr(0), STR_PAD_LEFT);
2948
+
2949
+ return $this->_normalize(new static($leading_ones | $temp, 256));
2950
+ }
2951
+
2952
+ /**
2953
+ * Logical Right Shift
2954
+ *
2955
+ * Shifts BigInteger's by $shift bits, effectively dividing by 2**$shift.
2956
+ *
2957
+ * @param int $shift
2958
+ * @return \phpseclib\Math\BigInteger
2959
+ * @access public
2960
+ * @internal The only version that yields any speed increases is the internal version.
2961
+ */
2962
+ function bitwise_rightShift($shift)
2963
+ {
2964
+ $temp = new static();
2965
+
2966
+ switch (MATH_BIGINTEGER_MODE) {
2967
+ case self::MODE_GMP:
2968
+ static $two;
2969
+
2970
+ if (!isset($two)) {
2971
+ $two = gmp_init('2');
2972
+ }
2973
+
2974
+ $temp->value = gmp_div_q($this->value, gmp_pow($two, $shift));
2975
+
2976
+ break;
2977
+ case self::MODE_BCMATH:
2978
+ $temp->value = bcdiv($this->value, bcpow('2', $shift, 0), 0);
2979
+
2980
+ break;
2981
+ default: // could just replace _lshift with this, but then all _lshift() calls would need to be rewritten
2982
+ // and I don't want to do that...
2983
+ $temp->value = $this->value;
2984
+ $temp->_rshift($shift);
2985
+ }
2986
+
2987
+ return $this->_normalize($temp);
2988
+ }
2989
+
2990
+ /**
2991
+ * Logical Left Shift
2992
+ *
2993
+ * Shifts BigInteger's by $shift bits, effectively multiplying by 2**$shift.
2994
+ *
2995
+ * @param int $shift
2996
+ * @return \phpseclib\Math\BigInteger
2997
+ * @access public
2998
+ * @internal The only version that yields any speed increases is the internal version.
2999
+ */
3000
+ function bitwise_leftShift($shift)
3001
+ {
3002
+ $temp = new static();
3003
+
3004
+ switch (MATH_BIGINTEGER_MODE) {
3005
+ case self::MODE_GMP:
3006
+ static $two;
3007
+
3008
+ if (!isset($two)) {
3009
+ $two = gmp_init('2');
3010
+ }
3011
+
3012
+ $temp->value = gmp_mul($this->value, gmp_pow($two, $shift));
3013
+
3014
+ break;
3015
+ case self::MODE_BCMATH:
3016
+ $temp->value = bcmul($this->value, bcpow('2', $shift, 0), 0);
3017
+
3018
+ break;
3019
+ default: // could just replace _rshift with this, but then all _lshift() calls would need to be rewritten
3020
+ // and I don't want to do that...
3021
+ $temp->value = $this->value;
3022
+ $temp->_lshift($shift);
3023
+ }
3024
+
3025
+ return $this->_normalize($temp);
3026
+ }
3027
+
3028
+ /**
3029
+ * Logical Left Rotate
3030
+ *
3031
+ * Instead of the top x bits being dropped they're appended to the shifted bit string.
3032
+ *
3033
+ * @param int $shift
3034
+ * @return \phpseclib\Math\BigInteger
3035
+ * @access public
3036
+ */
3037
+ function bitwise_leftRotate($shift)
3038
+ {
3039
+ $bits = $this->toBytes();
3040
+
3041
+ if ($this->precision > 0) {
3042
+ $precision = $this->precision;
3043
+ if (MATH_BIGINTEGER_MODE == self::MODE_BCMATH) {
3044
+ $mask = $this->bitmask->subtract(new static(1));
3045
+ $mask = $mask->toBytes();
3046
+ } else {
3047
+ $mask = $this->bitmask->toBytes();
3048
+ }
3049
+ } else {
3050
+ $temp = ord($bits[0]);
3051
+ for ($i = 0; $temp >> $i; ++$i) {
3052
+ }
3053
+ $precision = 8 * strlen($bits) - 8 + $i;
3054
+ $mask = chr((1 << ($precision & 0x7)) - 1) . str_repeat(chr(0xFF), $precision >> 3);
3055
+ }
3056
+
3057
+ if ($shift < 0) {
3058
+ $shift+= $precision;
3059
+ }
3060
+ $shift%= $precision;
3061
+
3062
+ if (!$shift) {
3063
+ return $this->copy();
3064
+ }
3065
+
3066
+ $left = $this->bitwise_leftShift($shift);
3067
+ $left = $left->bitwise_and(new static($mask, 256));
3068
+ $right = $this->bitwise_rightShift($precision - $shift);
3069
+ $result = MATH_BIGINTEGER_MODE != self::MODE_BCMATH ? $left->bitwise_or($right) : $left->add($right);
3070
+ return $this->_normalize($result);
3071
+ }
3072
+
3073
+ /**
3074
+ * Logical Right Rotate
3075
+ *
3076
+ * Instead of the bottom x bits being dropped they're prepended to the shifted bit string.
3077
+ *
3078
+ * @param int $shift
3079
+ * @return \phpseclib\Math\BigInteger
3080
+ * @access public
3081
+ */
3082
+ function bitwise_rightRotate($shift)
3083
+ {
3084
+ return $this->bitwise_leftRotate(-$shift);
3085
+ }
3086
+
3087
+ /**
3088
+ * Generates a random BigInteger
3089
+ *
3090
+ * Byte length is equal to $length. Uses \phpseclib\Crypt\Random if it's loaded and mt_rand if it's not.
3091
+ *
3092
+ * @param int $length
3093
+ * @return \phpseclib\Math\BigInteger
3094
+ * @access private
3095
+ */
3096
+ function _random_number_helper($size)
3097
+ {
3098
+ if (class_exists('\phpseclib\Crypt\Random')) {
3099
+ $random = Random::string($size);
3100
+ } else {
3101
+ $random = '';
3102
+
3103
+ if ($size & 1) {
3104
+ $random.= chr(mt_rand(0, 255));
3105
+ }
3106
+
3107
+ $blocks = $size >> 1;
3108
+ for ($i = 0; $i < $blocks; ++$i) {
3109
+ // mt_rand(-2147483648, 0x7FFFFFFF) always produces -2147483648 on some systems
3110
+ $random.= pack('n', mt_rand(0, 0xFFFF));
3111
+ }
3112
+ }
3113
+
3114
+ return new static($random, 256);
3115
+ }
3116
+
3117
+ /**
3118
+ * Generate a random number
3119
+ *
3120
+ * Returns a random number between $min and $max where $min and $max
3121
+ * can be defined using one of the two methods:
3122
+ *
3123
+ * $min->random($max)
3124
+ * $max->random($min)
3125
+ *
3126
+ * @param \phpseclib\Math\BigInteger $arg1
3127
+ * @param \phpseclib\Math\BigInteger $arg2
3128
+ * @return \phpseclib\Math\BigInteger
3129
+ * @access public
3130
+ * @internal The API for creating random numbers used to be $a->random($min, $max), where $a was a BigInteger object.
3131
+ * That method is still supported for BC purposes.
3132
+ */
3133
+ function random($arg1, $arg2 = false)
3134
+ {
3135
+ if ($arg1 === false) {
3136
+ return false;
3137
+ }
3138
+
3139
+ if ($arg2 === false) {
3140
+ $max = $arg1;
3141
+ $min = $this;
3142
+ } else {
3143
+ $min = $arg1;
3144
+ $max = $arg2;
3145
+ }
3146
+
3147
+ $compare = $max->compare($min);
3148
+
3149
+ if (!$compare) {
3150
+ return $this->_normalize($min);
3151
+ } elseif ($compare < 0) {
3152
+ // if $min is bigger then $max, swap $min and $max
3153
+ $temp = $max;
3154
+ $max = $min;
3155
+ $min = $temp;
3156
+ }
3157
+
3158
+ static $one;
3159
+ if (!isset($one)) {
3160
+ $one = new static(1);
3161
+ }
3162
+
3163
+ $max = $max->subtract($min->subtract($one));
3164
+ $size = strlen(ltrim($max->toBytes(), chr(0)));
3165
+
3166
+ /*
3167
+ doing $random % $max doesn't work because some numbers will be more likely to occur than others.
3168
+ eg. if $max is 140 and $random's max is 255 then that'd mean both $random = 5 and $random = 145
3169
+ would produce 5 whereas the only value of random that could produce 139 would be 139. ie.
3170
+ not all numbers would be equally likely. some would be more likely than others.
3171
+
3172
+ creating a whole new random number until you find one that is within the range doesn't work
3173
+ because, for sufficiently small ranges, the likelihood that you'd get a number within that range
3174
+ would be pretty small. eg. with $random's max being 255 and if your $max being 1 the probability
3175
+ would be pretty high that $random would be greater than $max.
3176
+
3177
+ phpseclib works around this using the technique described here:
3178
+
3179
+ http://crypto.stackexchange.com/questions/5708/creating-a-small-number-from-a-cryptographically-secure-random-string
3180
+ */
3181
+ $random_max = new static(chr(1) . str_repeat("\0", $size), 256);
3182
+ $random = $this->_random_number_helper($size);
3183
+
3184
+ list($max_multiple) = $random_max->divide($max);
3185
+ $max_multiple = $max_multiple->multiply($max);
3186
+
3187
+ while ($random->compare($max_multiple) >= 0) {
3188
+ $random = $random->subtract($max_multiple);
3189
+ $random_max = $random_max->subtract($max_multiple);
3190
+ $random = $random->bitwise_leftShift(8);
3191
+ $random = $random->add($this->_random_number_helper(1));
3192
+ $random_max = $random_max->bitwise_leftShift(8);
3193
+ list($max_multiple) = $random_max->divide($max);
3194
+ $max_multiple = $max_multiple->multiply($max);
3195
+ }
3196
+ list(, $random) = $random->divide($max);
3197
+
3198
+ return $this->_normalize($random->add($min));
3199
+ }
3200
+
3201
+ /**
3202
+ * Generate a random prime number.
3203
+ *
3204
+ * If there's not a prime within the given range, false will be returned.
3205
+ * If more than $timeout seconds have elapsed, give up and return false.
3206
+ *
3207
+ * @param \phpseclib\Math\BigInteger $arg1
3208
+ * @param \phpseclib\Math\BigInteger $arg2
3209
+ * @param int $timeout
3210
+ * @return Math_BigInteger|false
3211
+ * @access public
3212
+ * @internal See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap4.pdf#page=15 HAC 4.44}.
3213
+ */
3214
+ function randomPrime($arg1, $arg2 = false, $timeout = false)
3215
+ {
3216
+ if ($arg1 === false) {
3217
+ return false;
3218
+ }
3219
+
3220
+ if ($arg2 === false) {
3221
+ $max = $arg1;
3222
+ $min = $this;
3223
+ } else {
3224
+ $min = $arg1;
3225
+ $max = $arg2;
3226
+ }
3227
+
3228
+ $compare = $max->compare($min);
3229
+
3230
+ if (!$compare) {
3231
+ return $min->isPrime() ? $min : false;
3232
+ } elseif ($compare < 0) {
3233
+ // if $min is bigger then $max, swap $min and $max
3234
+ $temp = $max;
3235
+ $max = $min;
3236
+ $min = $temp;
3237
+ }
3238
+
3239
+ static $one, $two;
3240
+ if (!isset($one)) {
3241
+ $one = new static(1);
3242
+ $two = new static(2);
3243
+ }
3244
+
3245
+ $start = time();
3246
+
3247
+ $x = $this->random($min, $max);
3248
+
3249
+ // gmp_nextprime() requires PHP 5 >= 5.2.0 per <http://php.net/gmp-nextprime>.
3250
+ if (MATH_BIGINTEGER_MODE == self::MODE_GMP && extension_loaded('gmp')) {
3251
+ $p = new static();
3252
+ $p->value = gmp_nextprime($x->value);
3253
+
3254
+ if ($p->compare($max) <= 0) {
3255
+ return $p;
3256
+ }
3257
+
3258
+ if (!$min->equals($x)) {
3259
+ $x = $x->subtract($one);
3260
+ }
3261
+
3262
+ return $x->randomPrime($min, $x);
3263
+ }
3264
+
3265
+ if ($x->equals($two)) {
3266
+ return $x;
3267
+ }
3268
+
3269
+ $x->_make_odd();
3270
+ if ($x->compare($max) > 0) {
3271
+ // if $x > $max then $max is even and if $min == $max then no prime number exists between the specified range
3272
+ if ($min->equals($max)) {
3273
+ return false;
3274
+ }
3275
+ $x = $min->copy();
3276
+ $x->_make_odd();
3277
+ }
3278
+
3279
+ $initial_x = $x->copy();
3280
+
3281
+ while (true) {
3282
+ if ($timeout !== false && time() - $start > $timeout) {
3283
+ return false;
3284
+ }
3285
+
3286
+ if ($x->isPrime()) {
3287
+ return $x;
3288
+ }
3289
+
3290
+ $x = $x->add($two);
3291
+
3292
+ if ($x->compare($max) > 0) {
3293
+ $x = $min->copy();
3294
+ if ($x->equals($two)) {
3295
+ return $x;
3296
+ }
3297
+ $x->_make_odd();
3298
+ }
3299
+
3300
+ if ($x->equals($initial_x)) {
3301
+ return false;
3302
+ }
3303
+ }
3304
+ }
3305
+
3306
+ /**
3307
+ * Make the current number odd
3308
+ *
3309
+ * If the current number is odd it'll be unchanged. If it's even, one will be added to it.
3310
+ *
3311
+ * @see self::randomPrime()
3312
+ * @access private
3313
+ */
3314
+ function _make_odd()
3315
+ {
3316
+ switch (MATH_BIGINTEGER_MODE) {
3317
+ case self::MODE_GMP:
3318
+ gmp_setbit($this->value, 0);
3319
+ break;
3320
+ case self::MODE_BCMATH:
3321
+ if ($this->value[strlen($this->value) - 1] % 2 == 0) {
3322
+ $this->value = bcadd($this->value, '1');
3323
+ }
3324
+ break;
3325
+ default:
3326
+ $this->value[0] |= 1;
3327
+ }
3328
+ }
3329
+
3330
+ /**
3331
+ * Checks a numer to see if it's prime
3332
+ *
3333
+ * Assuming the $t parameter is not set, this function has an error rate of 2**-80. The main motivation for the
3334
+ * $t parameter is distributability. BigInteger::randomPrime() can be distributed across multiple pageloads
3335
+ * on a website instead of just one.
3336
+ *
3337
+ * @param \phpseclib\Math\BigInteger $t
3338
+ * @return bool
3339
+ * @access public
3340
+ * @internal Uses the
3341
+ * {@link http://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test Miller-Rabin primality test}. See
3342
+ * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap4.pdf#page=8 HAC 4.24}.
3343
+ */
3344
+ function isPrime($t = false)
3345
+ {
3346
+ $length = strlen($this->toBytes());
3347
+
3348
+ if (!$t) {
3349
+ // see HAC 4.49 "Note (controlling the error probability)"
3350
+ // @codingStandardsIgnoreStart
3351
+ if ($length >= 163) { $t = 2; } // floor(1300 / 8)
3352
+ else if ($length >= 106) { $t = 3; } // floor( 850 / 8)
3353
+ else if ($length >= 81 ) { $t = 4; } // floor( 650 / 8)
3354
+ else if ($length >= 68 ) { $t = 5; } // floor( 550 / 8)
3355
+ else if ($length >= 56 ) { $t = 6; } // floor( 450 / 8)
3356
+ else if ($length >= 50 ) { $t = 7; } // floor( 400 / 8)
3357
+ else if ($length >= 43 ) { $t = 8; } // floor( 350 / 8)
3358
+ else if ($length >= 37 ) { $t = 9; } // floor( 300 / 8)
3359
+ else if ($length >= 31 ) { $t = 12; } // floor( 250 / 8)
3360
+ else if ($length >= 25 ) { $t = 15; } // floor( 200 / 8)
3361
+ else if ($length >= 18 ) { $t = 18; } // floor( 150 / 8)
3362
+ else { $t = 27; }
3363
+ // @codingStandardsIgnoreEnd
3364
+ }
3365
+
3366
+ // ie. gmp_testbit($this, 0)
3367
+ // ie. isEven() or !isOdd()
3368
+ switch (MATH_BIGINTEGER_MODE) {
3369
+ case self::MODE_GMP:
3370
+ return gmp_prob_prime($this->value, $t) != 0;
3371
+ case self::MODE_BCMATH:
3372
+ if ($this->value === '2') {
3373
+ return true;
3374
+ }
3375
+ if ($this->value[strlen($this->value) - 1] % 2 == 0) {
3376
+ return false;
3377
+ }
3378
+ break;
3379
+ default:
3380
+ if ($this->value == array(2)) {
3381
+ return true;
3382
+ }
3383
+ if (~$this->value[0] & 1) {
3384
+ return false;
3385
+ }
3386
+ }
3387
+
3388
+ static $primes, $zero, $one, $two;
3389
+
3390
+ if (!isset($primes)) {
3391
+ $primes = array(
3392
+ 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59,
3393
+ 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137,
3394
+ 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227,
3395
+ 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313,
3396
+ 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419,
3397
+ 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509,
3398
+ 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617,
3399
+ 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727,
3400
+ 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829,
3401
+ 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947,
3402
+ 953, 967, 971, 977, 983, 991, 997
3403
+ );
3404
+
3405
+ if (MATH_BIGINTEGER_MODE != self::MODE_INTERNAL) {
3406
+ for ($i = 0; $i < count($primes); ++$i) {
3407
+ $primes[$i] = new static($primes[$i]);
3408
+ }
3409
+ }
3410
+
3411
+ $zero = new static();
3412
+ $one = new static(1);
3413
+ $two = new static(2);
3414
+ }
3415
+
3416
+ if ($this->equals($one)) {
3417
+ return false;
3418
+ }
3419
+
3420
+ // see HAC 4.4.1 "Random search for probable primes"
3421
+ if (MATH_BIGINTEGER_MODE != self::MODE_INTERNAL) {
3422
+ foreach ($primes as $prime) {
3423
+ list(, $r) = $this->divide($prime);
3424
+ if ($r->equals($zero)) {
3425
+ return $this->equals($prime);
3426
+ }
3427
+ }
3428
+ } else {
3429
+ $value = $this->value;
3430
+ foreach ($primes as $prime) {
3431
+ list(, $r) = $this->_divide_digit($value, $prime);
3432
+ if (!$r) {
3433
+ return count($value) == 1 && $value[0] == $prime;
3434
+ }
3435
+ }
3436
+ }
3437
+
3438
+ $n = $this->copy();
3439
+ $n_1 = $n->subtract($one);
3440
+ $n_2 = $n->subtract($two);
3441
+
3442
+ $r = $n_1->copy();
3443
+ $r_value = $r->value;
3444
+ // ie. $s = gmp_scan1($n, 0) and $r = gmp_div_q($n, gmp_pow(gmp_init('2'), $s));
3445
+ if (MATH_BIGINTEGER_MODE == self::MODE_BCMATH) {
3446
+ $s = 0;
3447
+ // if $n was 1, $r would be 0 and this would be an infinite loop, hence our $this->equals($one) check earlier
3448
+ while ($r->value[strlen($r->value) - 1] % 2 == 0) {
3449
+ $r->value = bcdiv($r->value, '2', 0);
3450
+ ++$s;
3451
+ }
3452
+ } else {
3453
+ for ($i = 0, $r_length = count($r_value); $i < $r_length; ++$i) {
3454
+ $temp = ~$r_value[$i] & 0xFFFFFF;
3455
+ for ($j = 1; ($temp >> $j) & 1; ++$j) {
3456
+ }
3457
+ if ($j != 25) {
3458
+ break;
3459
+ }
3460
+ }
3461
+ $s = 26 * $i + $j;
3462
+ $r->_rshift($s);
3463
+ }
3464
+
3465
+ for ($i = 0; $i < $t; ++$i) {
3466
+ $a = $this->random($two, $n_2);
3467
+ $y = $a->modPow($r, $n);
3468
+
3469
+ if (!$y->equals($one) && !$y->equals($n_1)) {
3470
+ for ($j = 1; $j < $s && !$y->equals($n_1); ++$j) {
3471
+ $y = $y->modPow($two, $n);
3472
+ if ($y->equals($one)) {
3473
+ return false;
3474
+ }
3475
+ }
3476
+
3477
+ if (!$y->equals($n_1)) {
3478
+ return false;
3479
+ }
3480
+ }
3481
+ }
3482
+ return true;
3483
+ }
3484
+
3485
+ /**
3486
+ * Logical Left Shift
3487
+ *
3488
+ * Shifts BigInteger's by $shift bits.
3489
+ *
3490
+ * @param int $shift
3491
+ * @access private
3492
+ */
3493
+ function _lshift($shift)
3494
+ {
3495
+ if ($shift == 0) {
3496
+ return;
3497
+ }
3498
+
3499
+ $num_digits = (int) ($shift / self::$base);
3500
+ $shift %= self::$base;
3501
+ $shift = 1 << $shift;
3502
+
3503
+ $carry = 0;
3504
+
3505
+ for ($i = 0; $i < count($this->value); ++$i) {
3506
+ $temp = $this->value[$i] * $shift + $carry;
3507
+ $carry = self::$base === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
3508
+ $this->value[$i] = (int) ($temp - $carry * self::$baseFull);
3509
+ }
3510
+
3511
+ if ($carry) {
3512
+ $this->value[count($this->value)] = $carry;
3513
+ }
3514
+
3515
+ while ($num_digits--) {
3516
+ array_unshift($this->value, 0);
3517
+ }
3518
+ }
3519
+
3520
+ /**
3521
+ * Logical Right Shift
3522
+ *
3523
+ * Shifts BigInteger's by $shift bits.
3524
+ *
3525
+ * @param int $shift
3526
+ * @access private
3527
+ */
3528
+ function _rshift($shift)
3529
+ {
3530
+ if ($shift == 0) {
3531
+ return;
3532
+ }
3533
+
3534
+ $num_digits = (int) ($shift / self::$base);
3535
+ $shift %= self::$base;
3536
+ $carry_shift = self::$base - $shift;
3537
+ $carry_mask = (1 << $shift) - 1;
3538
+
3539
+ if ($num_digits) {
3540
+ $this->value = array_slice($this->value, $num_digits);
3541
+ }
3542
+
3543
+ $carry = 0;
3544
+
3545
+ for ($i = count($this->value) - 1; $i >= 0; --$i) {
3546
+ $temp = $this->value[$i] >> $shift | $carry;
3547
+ $carry = ($this->value[$i] & $carry_mask) << $carry_shift;
3548
+ $this->value[$i] = $temp;
3549
+ }
3550
+
3551
+ $this->value = $this->_trim($this->value);
3552
+ }
3553
+
3554
+ /**
3555
+ * Normalize
3556
+ *
3557
+ * Removes leading zeros and truncates (if necessary) to maintain the appropriate precision
3558
+ *
3559
+ * @param \phpseclib\Math\BigInteger
3560
+ * @return \phpseclib\Math\BigInteger
3561
+ * @see self::_trim()
3562
+ * @access private
3563
+ */
3564
+ function _normalize($result)
3565
+ {
3566
+ $result->precision = $this->precision;
3567
+ $result->bitmask = $this->bitmask;
3568
+
3569
+ switch (MATH_BIGINTEGER_MODE) {
3570
+ case self::MODE_GMP:
3571
+ if ($this->bitmask !== false) {
3572
+ $result->value = gmp_and($result->value, $result->bitmask->value);
3573
+ }
3574
+
3575
+ return $result;
3576
+ case self::MODE_BCMATH:
3577
+ if (!empty($result->bitmask->value)) {
3578
+ $result->value = bcmod($result->value, $result->bitmask->value);
3579
+ }
3580
+
3581
+ return $result;
3582
+ }
3583
+
3584
+ $value = &$result->value;
3585
+
3586
+ if (!count($value)) {
3587
+ $result->is_negative = false;
3588
+ return $result;
3589
+ }
3590
+
3591
+ $value = $this->_trim($value);
3592
+
3593
+ if (!empty($result->bitmask->value)) {
3594
+ $length = min(count($value), count($this->bitmask->value));
3595
+ $value = array_slice($value, 0, $length);
3596
+
3597
+ for ($i = 0; $i < $length; ++$i) {
3598
+ $value[$i] = $value[$i] & $this->bitmask->value[$i];
3599
+ }
3600
+ }
3601
+
3602
+ return $result;
3603
+ }
3604
+
3605
+ /**
3606
+ * Trim
3607
+ *
3608
+ * Removes leading zeros
3609
+ *
3610
+ * @param array $value
3611
+ * @return \phpseclib\Math\BigInteger
3612
+ * @access private
3613
+ */
3614
+ function _trim($value)
3615
+ {
3616
+ for ($i = count($value) - 1; $i >= 0; --$i) {
3617
+ if ($value[$i]) {
3618
+ break;
3619
+ }
3620
+ unset($value[$i]);
3621
+ }
3622
+
3623
+ return $value;
3624
+ }
3625
+
3626
+ /**
3627
+ * Array Repeat
3628
+ *
3629
+ * @param $input Array
3630
+ * @param $multiplier mixed
3631
+ * @return array
3632
+ * @access private
3633
+ */
3634
+ function _array_repeat($input, $multiplier)
3635
+ {
3636
+ return ($multiplier) ? array_fill(0, $multiplier, $input) : array();
3637
+ }
3638
+
3639
+ /**
3640
+ * Logical Left Shift
3641
+ *
3642
+ * Shifts binary strings $shift bits, essentially multiplying by 2**$shift.
3643
+ *
3644
+ * @param $x String
3645
+ * @param $shift Integer
3646
+ * @return string
3647
+ * @access private
3648
+ */
3649
+ function _base256_lshift(&$x, $shift)
3650
+ {
3651
+ if ($shift == 0) {
3652
+ return;
3653
+ }
3654
+
3655
+ $num_bytes = $shift >> 3; // eg. floor($shift/8)
3656
+ $shift &= 7; // eg. $shift % 8
3657
+
3658
+ $carry = 0;
3659
+ for ($i = strlen($x) - 1; $i >= 0; --$i) {
3660
+ $temp = ord($x[$i]) << $shift | $carry;
3661
+ $x[$i] = chr($temp);
3662
+ $carry = $temp >> 8;
3663
+ }
3664
+ $carry = ($carry != 0) ? chr($carry) : '';
3665
+ $x = $carry . $x . str_repeat(chr(0), $num_bytes);
3666
+ }
3667
+
3668
+ /**
3669
+ * Logical Right Shift
3670
+ *
3671
+ * Shifts binary strings $shift bits, essentially dividing by 2**$shift and returning the remainder.
3672
+ *
3673
+ * @param $x String
3674
+ * @param $shift Integer
3675
+ * @return string
3676
+ * @access private
3677
+ */
3678
+ function _base256_rshift(&$x, $shift)
3679
+ {
3680
+ if ($shift == 0) {
3681
+ $x = ltrim($x, chr(0));
3682
+ return '';
3683
+ }
3684
+
3685
+ $num_bytes = $shift >> 3; // eg. floor($shift/8)
3686
+ $shift &= 7; // eg. $shift % 8
3687
+
3688
+ $remainder = '';
3689
+ if ($num_bytes) {
3690
+ $start = $num_bytes > strlen($x) ? -strlen($x) : -$num_bytes;
3691
+ $remainder = substr($x, $start);
3692
+ $x = substr($x, 0, -$num_bytes);
3693
+ }
3694
+
3695
+ $carry = 0;
3696
+ $carry_shift = 8 - $shift;
3697
+ for ($i = 0; $i < strlen($x); ++$i) {
3698
+ $temp = (ord($x[$i]) >> $shift) | $carry;
3699
+ $carry = (ord($x[$i]) << $carry_shift) & 0xFF;
3700
+ $x[$i] = chr($temp);
3701
+ }
3702
+ $x = ltrim($x, chr(0));
3703
+
3704
+ $remainder = chr($carry >> $carry_shift) . $remainder;
3705
+
3706
+ return ltrim($remainder, chr(0));
3707
+ }
3708
+
3709
+ // one quirk about how the following functions are implemented is that PHP defines N to be an unsigned long
3710
+ // at 32-bits, while java's longs are 64-bits.
3711
+
3712
+ /**
3713
+ * Converts 32-bit integers to bytes.
3714
+ *
3715
+ * @param int $x
3716
+ * @return string
3717
+ * @access private
3718
+ */
3719
+ function _int2bytes($x)
3720
+ {
3721
+ return ltrim(pack('N', $x), chr(0));
3722
+ }
3723
+
3724
+ /**
3725
+ * Converts bytes to 32-bit integers
3726
+ *
3727
+ * @param string $x
3728
+ * @return int
3729
+ * @access private
3730
+ */
3731
+ function _bytes2int($x)
3732
+ {
3733
+ $temp = unpack('Nint', str_pad($x, 4, chr(0), STR_PAD_LEFT));
3734
+ return $temp['int'];
3735
+ }
3736
+
3737
+ /**
3738
+ * DER-encode an integer
3739
+ *
3740
+ * The ability to DER-encode integers is needed to create RSA public keys for use with OpenSSL
3741
+ *
3742
+ * @see self::modPow()
3743
+ * @access private
3744
+ * @param int $length
3745
+ * @return string
3746
+ */
3747
+ function _encodeASN1Length($length)
3748
+ {
3749
+ if ($length <= 0x7F) {
3750
+ return chr($length);
3751
+ }
3752
+
3753
+ $temp = ltrim(pack('N', $length), chr(0));
3754
+ return pack('Ca*', 0x80 | strlen($temp), $temp);
3755
+ }
3756
+
3757
+ /**
3758
+ * Single digit division
3759
+ *
3760
+ * Even if int64 is being used the division operator will return a float64 value
3761
+ * if the dividend is not evenly divisible by the divisor. Since a float64 doesn't
3762
+ * have the precision of int64 this is a problem so, when int64 is being used,
3763
+ * we'll guarantee that the dividend is divisible by first subtracting the remainder.
3764
+ *
3765
+ * @access private
3766
+ * @param int $x
3767
+ * @param int $y
3768
+ * @return int
3769
+ */
3770
+ function _safe_divide($x, $y)
3771
+ {
3772
+ if (self::$base === 26) {
3773
+ return (int) ($x / $y);
3774
+ }
3775
+
3776
+ // self::$base === 31
3777
+ return ($x - ($x % $y)) / $y;
3778
+ }
3779
+ }
vendor/phpseclib/phpseclib/phpseclib/bootstrap.php CHANGED
@@ -1,16 +1,16 @@
1
- <?php
2
- /**
3
- * Bootstrapping File for phpseclib
4
- *
5
- * @license http://www.opensource.org/licenses/mit-license.html MIT License
6
- */
7
-
8
- if (extension_loaded('mbstring')) {
9
- // 2 - MB_OVERLOAD_STRING
10
- if (ini_get('mbstring.func_overload') & 2) {
11
- throw new \UnexpectedValueException(
12
- 'Overloading of string functions using mbstring.func_overload ' .
13
- 'is not supported by phpseclib.'
14
- );
15
- }
16
- }
1
+ <?php
2
+ /**
3
+ * Bootstrapping File for phpseclib
4
+ *
5
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
6
+ */
7
+
8
+ if (extension_loaded('mbstring')) {
9
+ // 2 - MB_OVERLOAD_STRING
10
+ if (ini_get('mbstring.func_overload') & 2) {
11
+ throw new \UnexpectedValueException(
12
+ 'Overloading of string functions using mbstring.func_overload ' .
13
+ 'is not supported by phpseclib.'
14
+ );
15
+ }
16
+ }
vendor/phpseclib/phpseclib/phpseclib/openssl.cnf CHANGED
@@ -1,6 +1,6 @@
1
- # minimalist openssl.cnf file for use with phpseclib
2
-
3
- HOME = .
4
- RANDFILE = $ENV::HOME/.rnd
5
-
6
- [ v3_ca ]
1
+ # minimalist openssl.cnf file for use with phpseclib
2
+
3
+ HOME = .
4
+ RANDFILE = $ENV::HOME/.rnd
5
+
6
+ [ v3_ca ]
vendor/phpseclib/phpseclib/travis/code_coverage_id_rsa ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ -----BEGIN RSA PRIVATE KEY-----
2
+ Proc-Type: 4,ENCRYPTED
3
+ DEK-Info: AES-128-CBC,2F15FCF0B21FCFB5A37D709322F9B9EB
4
+
5
+ JpGgJqRnr0+3mHQoeYXXUzSWeA1wGwMzm6KOPnQLEmA9ztPlBQulzZRh6QJckCwy
6
+ TC7BMo+XRnYVXF3e0rjji0k7cfEk5Gs8saNcxxOa0u0SUOCXelGnZeqzwiT0a6Fe
7
+ qAc7NLgTEo9zul9s+MHsplkVk71Oke+1dL7kksMRT0TdXIaqSvk/+nyAeLzAot04
8
+ wo61T3+Y7/v/8oVxlCbxI5YfYZkm/4jTy7AfbXZBvC0R+F0ZYvIDRCuBe6h6XvcH
9
+ AiYtw5+Qek6FwIa2CFVxsefvsEnZQYaiJpEFAq2xVHlTjQHHYrfd5cgu1koUNsAt
10
+ nX1zpsK7tIregXFa07KfDaBBPxfEBqVJQInzj0Rc8HUt0AZ+MrPldrZ28+YQ4RXk
11
+ /qk5UyKkdHMSKBb4va3mxcpDq1As9HREfeUeOjjduRh1LnNQCJaOhydXBqCFvhFy
12
+ +Q9utDXP6q4OUxeDHCPGQ7K1I7erwiwuTeSXB3BEDZyZywHXABvJpsidkDlD/aNo
13
+ QmM19V8y0IAxEAZvc8N0MIOO8hmd8R9U1RK4S24o9M8mgRrmuXjViJjZd5E3h6tX
14
+ Mgxm8dpOiT77i+NsJwyp2A+MhkAHg2ruwlCIrSCC81zvdphVTfuc/vx3JpXYvhTP
15
+ Xf9R8ppGnDUFauroN7E7odJKDhLVuAbmU1lWwue2iaNEKZ3L/o9dpRz4Td4NzzSf
16
+ HKvKbJR35FCsqZq2krmNVd6ynF5PzWfYmz850yn/qdU8zwnW0fV+iHKS2oXuH9X1
17
+ ZW02/MDdCylpRftNJMntR4Yxim7WEZ5Dif9ZLj8IGRQdWbbIn0WjtiVrFrcUbIfk
18
+ TCP/3GeEcUa/XbE9hO9APw+7rO3sOehGJ84n4tXxFTFSnOJ5ZxTKpLvxRrmC8DaD
19
+ cvqy8bbjPfn1EjZmRpCjanLZ1UJbLitFfpUT55aTrcozS4FMHmFm74X2xZGeBhxC
20
+ CpWQe/agxhWxG+ZXdxt9ExI78ftQCQoGE0Si1KZXH5KQ/xiGmebY9wbtEHWG+q25
21
+ sKqvjQHQsE3NZq7kne3mnyvjzMDDFYPLDlQLgcKInNrLZ3GszyemtzqcVf3YVur4
22
+ N+nN0gu6LCx0vtw3yNRqjjmGN1V6sKMCqmIAtFDh9zRTlDTs7ZUBGPgakmmJLLVM
23
+ ESme0JrRxCP+eEU8JNti9pKlKPGOFVpu4shLjmnmKuDpOytFNpcB/NylkGwZCxvE
24
+ 1KI+EQMZOE5VROAfkvwBLE0SsVxMq7H87zSEOtOqr+QN8RoY1V6N/woBVWda9GFk
25
+ HI44PM2ZywQbLGthaQV/Kxwf9YZruJdunNoTfEufZgv2Vp+3VAs+gCTGIsbblTnH
26
+ J8QGfs/lHRBqK1pMZrYy0ubFqifA+b9Xa6VJWToCgcQuWbOVWn1zKQTTXZPksVbB
27
+ qyE8BJkQCDGgoeq4kdxm0XUR5p3UZWQv0HoykQt33U06TCzU9HOcp0z+Glhrzsvd
28
+ rbNBhRK0zXF/BFSNBHwKEg02TNlj7gSFJXmvZqvyCAFo5D6nSDbzqm6ARuscsrF0
29
+ 6Zd3toOZTWmrVsKvTlsNPfHXyoGqP3+0NXcTY+kKXG58u4TbEtw8pVyPikuVdh/m
30
+ -----END RSA PRIVATE KEY-----
wp_mail_smtp.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  /**
3
  * Plugin Name: WP Mail SMTP
4
- * Version: 1.5.1
5
  * Plugin URI: https://wpforms.com/
6
  * Description: Reconfigures the <code>wp_mail()</code> function to use Gmail/Mailgun/SendGrid/SMTP instead of the default <code>mail()</code> and creates an options page to manage the settings.
7
  * Author: WPForms
@@ -134,7 +134,7 @@ if ( ! function_exists( 'wp_mail_smtp_check_pro_loading_allowed' ) ) {
134
  }
135
 
136
  if ( ! defined( 'WPMS_PLUGIN_VER' ) ) {
137
- define( 'WPMS_PLUGIN_VER', '1.5.1' );
138
  }
139
  if ( ! defined( 'WPMS_PHP_VER' ) ) {
140
  define( 'WPMS_PHP_VER', '5.3.6' );
1
  <?php
2
  /**
3
  * Plugin Name: WP Mail SMTP
4
+ * Version: 1.5.2
5
  * Plugin URI: https://wpforms.com/
6
  * Description: Reconfigures the <code>wp_mail()</code> function to use Gmail/Mailgun/SendGrid/SMTP instead of the default <code>mail()</code> and creates an options page to manage the settings.
7
  * Author: WPForms
134
  }
135
 
136
  if ( ! defined( 'WPMS_PLUGIN_VER' ) ) {
137
+ define( 'WPMS_PLUGIN_VER', '1.5.2' );
138
  }
139
  if ( ! defined( 'WPMS_PHP_VER' ) ) {
140
  define( 'WPMS_PHP_VER', '5.3.6' );