Ecwid Ecommerce Shopping Cart - Version 3.4.4

Version Description

  • Added compatibility with the "Add Meta Tags" plugin. The "Add Meta Tags" plugin is a popular tool to set SEO meta tags on site pages. Previously it rewrote the titles and description that Ecwid generated for search engines on your site. It's now fixed so if you use the plugin, everything should work fine and Google will index your products pages properly.
  • Fixed a problem in the recently viewed products widget caused by Autoptimize plugin. Previously, if Autoptimize plugin is used on the site, the recently viewed products widget reset the displayed products when page reloads. We fixed that.
  • A few internal improvements to make the plugin more stable and ready for the upcoming cool features. Stay tuned! More updates are coming.
Download this release

Release Info

Developer Ecwid
Plugin Icon 128x128 Ecwid Ecommerce Shopping Cart
Version 3.4.4
Comparing to
See all releases

Code changes from version 3.4.2 to 3.4.4

css/settings.css CHANGED
@@ -391,6 +391,11 @@ display: none;
391
  margin-bottom: 38px;
392
  }
393
 
 
 
 
 
 
394
  .ecwid-connect .box .connect-button {
395
  margin-top: 8px;
396
  }
@@ -405,6 +410,10 @@ display: none;
405
  font-size: 13px;
406
  }
407
 
 
 
 
 
408
  .ecwid-connect .box .create-account-link {
409
  margin-top: 35px;
410
  }
391
  margin-bottom: 38px;
392
  }
393
 
394
+
395
+ .ecwid-connect.ecwid-reconnect .box .greeting-message {
396
+ margin-bottom: inherit;
397
+ }
398
+
399
  .ecwid-connect .box .connect-button {
400
  margin-top: 8px;
401
  }
410
  font-size: 13px;
411
  }
412
 
413
+ .ecwid-connect .box .note.reconnect-message {
414
+ margin-bottom: 38px;
415
+ color: #707070;
416
+ }
417
  .ecwid-connect .box .create-account-link {
418
  margin-top: 35px;
419
  }
ecwid-shopping-cart.php CHANGED
@@ -5,7 +5,7 @@ Plugin URI: http://www.ecwid.com?source=wporg
5
  Description: Ecwid is a free full-featured shopping cart. It can be easily integrated with any Wordpress blog and takes less than 5 minutes to set up.
6
  Text Domain: ecwid-shopping-cart
7
  Author: Ecwid Team
8
- Version: 3.4.2
9
  Author URI: http://www.ecwid.com?source=wporg
10
  */
11
 
@@ -26,7 +26,6 @@ if ( ! defined( 'ECWID_PLUGIN_URL' ) ) {
26
  define( 'ECWID_PLUGIN_URL', plugin_dir_url( realpath(__FILE__) ) );
27
  }
28
 
29
-
30
  // Older versions of Google XML Sitemaps plugin generate it in admin, newer in site area, so the hook should be assigned in both of them
31
  add_action('sm_buildmap', 'ecwid_build_google_xml_sitemap');
32
 
@@ -40,6 +39,7 @@ add_filter('plugins_loaded', 'ecwid_load_textdomain');
40
  if ( is_admin() ){
41
  add_action('admin_init', 'ecwid_settings_api_init');
42
  add_action('admin_init', 'ecwid_check_version');
 
43
  add_action('admin_notices', 'ecwid_show_admin_messages');
44
  add_action('admin_menu', 'ecwid_options_add_page');
45
  add_action('wp_dashboard_setup', 'ecwid_add_dashboard_widgets' );
@@ -69,7 +69,7 @@ if ( is_admin() ){
69
  add_action('wp', 'ecwid_seo_ultimate_compatibility', 0);
70
  add_action('wp', 'ecwid_remove_default_canonical');
71
  add_filter('wp', 'ecwid_seo_compatibility_init', 0);
72
- add_filter('wp_title', 'ecwid_seo_title', 20);
73
  add_action('plugins_loaded', 'ecwid_minifier_compatibility', 0);
74
  add_action('wp_head', 'ecwid_meta_description', 0);
75
  add_action('wp_head', 'ecwid_ajax_crawling_fragment');
@@ -417,6 +417,12 @@ function ecwid_check_version()
417
  $current_version = $plugin_data['Version'];
418
  $stored_version = get_option('ecwid_plugin_version', null);
419
 
 
 
 
 
 
 
420
  $fresh_install = !$stored_version;
421
  $upgrade = $stored_version && version_compare($current_version, $stored_version) > 0;
422
 
@@ -441,19 +447,6 @@ function ecwid_check_version()
441
 
442
  add_option('ecwid_use_new_horizontal_categories', '');
443
  }
444
-
445
- $migration_since_version = get_option('ecwid_plugin_migration_since_version', null);
446
-
447
- if ($migration_since_version == '3.4' || $migration_since_version == '3.4.1' || is_null($migration_since_version)) {
448
-
449
- $install_date = get_option('ecwid_installation_date');
450
- if ($install_date < strtotime("18 September 2015")) {
451
- update_option('ecwid_plugin_migration_since_version', '0');
452
- } elseif (is_null($migration_since_version)) {
453
- update_option('ecwid_plugin_migration_since_version', $current_version);
454
- }
455
- }
456
-
457
  }
458
 
459
  function ecwid_migrations_is_original_plugin_version_older_than($version)
@@ -549,10 +542,22 @@ function ecwid_seo_compatibility_init($title)
549
  // Title
550
  ecwid_override_option('aiosp_rewrite_titles', false);
551
 
 
552
  return $title;
553
 
554
  }
555
 
 
 
 
 
 
 
 
 
 
 
 
556
  function ecwid_seo_compatibility_restore()
557
  {
558
  if (!array_key_exists('_escaped_fragment_', $_GET) || !ecwid_page_has_productbrowser()) {
@@ -853,10 +858,10 @@ function ecwid_content_started($content)
853
 
854
  function ecwid_wrap_shortcode_content($content, $name, $attrs)
855
  {
856
- return "<!-- Ecwid shopping cart plugin v 3.4.2 --><!-- noptimize -->"
857
  . ecwid_get_scriptjs_code(@$attrs['lang'])
858
  . "<div class=\"ecwid-shopping-cart-$name\">$content</div>"
859
- . "<!-- /noptimize --><!-- END Ecwid Shopping Cart v 3.4.2 -->";
860
  }
861
 
862
  function ecwid_get_scriptjs_code($force_lang = null) {
@@ -1384,6 +1389,7 @@ function ecwid_uninstall() {
1384
  delete_option('ecwid_api_check_time');
1385
  delete_option('ecwid_show_vote_message');
1386
  delete_option("ecwid_sso_secret_key");
 
1387
  delete_option('ecwid_hide_appearance_menu');
1388
  delete_option("ecwid_advanced_theme_layout");
1389
 
@@ -1583,21 +1589,62 @@ function ecwid_general_settings_do_page() {
1583
  }
1584
  }
1585
 
 
 
1586
  if (get_option('ecwid_store_id') == ECWID_DEMO_STORE_ID && !$no_oauth) {
1587
- global $ecwid_oauth;
1588
 
1589
  $register = !$connection_error && !isset($_GET['connect']) && !@$_COOKIE['ecwid_create_store_clicked'];
1590
 
1591
  require_once(ECWID_PLUGIN_DIR . '/templates/landing.php');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1592
  } else {
 
 
 
1593
 
1594
- if (get_ecwid_store_id() == ECWID_DEMO_STORE_ID) {
1595
- global $ecwid_oauth;
1596
 
1597
- require_once ECWID_PLUGIN_DIR . '/templates/connect.php';
1598
- } else {
1599
- require_once ECWID_PLUGIN_DIR . '/templates/dashboard.php';
1600
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1601
  }
1602
  }
1603
 
@@ -1609,14 +1656,19 @@ function ecwid_admin_post_connect()
1609
  update_option('ecwid_api_check_time', 0);
1610
  update_option('ecwid_last_oauth_fail_time', 1);
1611
  wp_redirect('admin.php?page=ecwid');
 
1612
  }
1613
  global $ecwid_oauth;
1614
 
1615
  if (ecwid_test_oauth(true)) {
 
1616
  wp_redirect($ecwid_oauth->get_auth_dialog_url());
1617
- } else {
1618
  wp_redirect('admin.php?page=ecwid&oauth=no');
 
 
1619
  }
 
1620
  }
1621
 
1622
  function ecwid_test_oauth($force = false)
@@ -2209,7 +2261,7 @@ class EcwidRecentlyViewedWidget extends WP_Widget {
2209
  if ( $title )
2210
  echo $before_title . $title . $after_title;
2211
 
2212
- echo ecwid_get_scriptjs_code();
2213
 
2214
  $recently_viewed = false;
2215
  if (isset($_COOKIE['ecwid-shopping-cart-recently-viewed'])) {
@@ -2229,6 +2281,7 @@ class EcwidRecentlyViewedWidget extends WP_Widget {
2229
  $api = ecwid_new_product_api();
2230
  }
2231
 
 
2232
  $ids = array();
2233
  if ($recently_viewed && isset($recently_viewed->products)) {
2234
 
@@ -2244,14 +2297,17 @@ class EcwidRecentlyViewedWidget extends WP_Widget {
2244
  $product_https = $api->get_product_https($product->id);
2245
  }
2246
 
 
 
2247
  echo <<<HTML
2248
- <a class="product$hide" href="$product->link" alt="$product->name" title="$product->name">
2249
  <div class="ecwid ecwid-SingleProduct ecwid-Product ecwid-Product-$product->id" data-single-product-link="$product->link" itemscope itemtype="http://schema.org/Product" data-single-product-id="$product->id">
2250
  <div itemprop="image" data-force-image="$product_https[imageUrl]"></div>
2251
  <div class="ecwid-title" itemprop="name"></div>
2252
  <div itemtype="http://schema.org/Offer" itemscope itemprop="offers"><div class="ecwid-productBrowser-price ecwid-price" itemprop="price"></div></div>
2253
  </div>
2254
- <script type="text/javascript">xSingleProduct();</script>
 
2255
  </a>
2256
  HTML;
2257
  }
@@ -2398,7 +2454,8 @@ function ecwid_gather_stats()
2398
  'recently_viewed_widget',
2399
  'avalanche_used',
2400
  'chameleon_used',
2401
- 'http_post_fails'
 
2402
  );
2403
 
2404
  $usage_stats = ecwid_gather_usage_stats();
@@ -2436,7 +2493,8 @@ function ecwid_gather_usage_stats()
2436
  'recently_viewed_widget',
2437
  'avalanche_used',
2438
  'chameleon_used',
2439
- 'http_post_fails'
 
2440
  );
2441
 
2442
  $usage_stats = array();
@@ -2460,6 +2518,8 @@ function ecwid_gather_usage_stats()
2460
  $usage_stats['avalanche_used'] = (bool) is_plugin_active('ecwid-widgets-avalanche/ecwid_widgets_avalanche.php');
2461
  $usage_stats['chameleon_used'] = (bool)get_option('ecwid_use_chameleon');
2462
  $usage_stats['http_post_fails'] = get_option('ecwid_last_oauth_fail_time') > 0;
 
 
2463
 
2464
  return $usage_stats;
2465
  }
5
  Description: Ecwid is a free full-featured shopping cart. It can be easily integrated with any Wordpress blog and takes less than 5 minutes to set up.
6
  Text Domain: ecwid-shopping-cart
7
  Author: Ecwid Team
8
+ Version: 3.4.4
9
  Author URI: http://www.ecwid.com?source=wporg
10
  */
11
 
26
  define( 'ECWID_PLUGIN_URL', plugin_dir_url( realpath(__FILE__) ) );
27
  }
28
 
 
29
  // Older versions of Google XML Sitemaps plugin generate it in admin, newer in site area, so the hook should be assigned in both of them
30
  add_action('sm_buildmap', 'ecwid_build_google_xml_sitemap');
31
 
39
  if ( is_admin() ){
40
  add_action('admin_init', 'ecwid_settings_api_init');
41
  add_action('admin_init', 'ecwid_check_version');
42
+ add_action('admin_init', 'ecwid_process_oauth_params');
43
  add_action('admin_notices', 'ecwid_show_admin_messages');
44
  add_action('admin_menu', 'ecwid_options_add_page');
45
  add_action('wp_dashboard_setup', 'ecwid_add_dashboard_widgets' );
69
  add_action('wp', 'ecwid_seo_ultimate_compatibility', 0);
70
  add_action('wp', 'ecwid_remove_default_canonical');
71
  add_filter('wp', 'ecwid_seo_compatibility_init', 0);
72
+ add_filter('wp_title', 'ecwid_seo_title', 10000);
73
  add_action('plugins_loaded', 'ecwid_minifier_compatibility', 0);
74
  add_action('wp_head', 'ecwid_meta_description', 0);
75
  add_action('wp_head', 'ecwid_ajax_crawling_fragment');
417
  $current_version = $plugin_data['Version'];
418
  $stored_version = get_option('ecwid_plugin_version', null);
419
 
420
+
421
+ $migration_since_version = get_option('ecwid_plugin_migration_since_version', null);
422
+ if (is_null($migration_since_version)) {
423
+ update_option('ecwid_plugin_migration_since_version', $current_version);
424
+ }
425
+
426
  $fresh_install = !$stored_version;
427
  $upgrade = $stored_version && version_compare($current_version, $stored_version) > 0;
428
 
447
 
448
  add_option('ecwid_use_new_horizontal_categories', '');
449
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
450
  }
451
 
452
  function ecwid_migrations_is_original_plugin_version_older_than($version)
542
  // Title
543
  ecwid_override_option('aiosp_rewrite_titles', false);
544
 
545
+ add_action('amt_basic_metadata_head', 'ecwid_amt_remove_description');
546
  return $title;
547
 
548
  }
549
 
550
+ function ecwid_amt_remove_description($params)
551
+ {
552
+ foreach ($params as $key => $value) {
553
+ if (preg_match('/meta name="description"/', $value)) {
554
+ unset ($params[$key]);
555
+ }
556
+ }
557
+
558
+ return $params;
559
+ }
560
+
561
  function ecwid_seo_compatibility_restore()
562
  {
563
  if (!array_key_exists('_escaped_fragment_', $_GET) || !ecwid_page_has_productbrowser()) {
858
 
859
  function ecwid_wrap_shortcode_content($content, $name, $attrs)
860
  {
861
+ return "<!-- Ecwid shopping cart plugin v 3.4.4 --><!-- noptimize -->"
862
  . ecwid_get_scriptjs_code(@$attrs['lang'])
863
  . "<div class=\"ecwid-shopping-cart-$name\">$content</div>"
864
+ . "<!-- /noptimize --><!-- END Ecwid Shopping Cart v 3.4.4 -->";
865
  }
866
 
867
  function ecwid_get_scriptjs_code($force_lang = null) {
1389
  delete_option('ecwid_api_check_time');
1390
  delete_option('ecwid_show_vote_message');
1391
  delete_option("ecwid_sso_secret_key");
1392
+ delete_option("ecwid_installation_date");
1393
  delete_option('ecwid_hide_appearance_menu');
1394
  delete_option("ecwid_advanced_theme_layout");
1395
 
1589
  }
1590
  }
1591
 
1592
+ global $ecwid_oauth;
1593
+
1594
  if (get_option('ecwid_store_id') == ECWID_DEMO_STORE_ID && !$no_oauth) {
 
1595
 
1596
  $register = !$connection_error && !isset($_GET['connect']) && !@$_COOKIE['ecwid_create_store_clicked'];
1597
 
1598
  require_once(ECWID_PLUGIN_DIR . '/templates/landing.php');
1599
+ } else if (isset($_GET['reconnect'])) {
1600
+ if (isset($_GET['reason'])) switch ($_GET['reason']) {
1601
+ case '1': $reconnect_message = "Message 1"; break;
1602
+ case '2': $reconnect_message = "Message 2"; break;
1603
+ }
1604
+
1605
+ $scopes = '';
1606
+
1607
+ $connection_error = isset($_GET['connection_error']);
1608
+
1609
+ require_once ECWID_PLUGIN_DIR . '/templates/reconnect.php';
1610
+ } else if (get_ecwid_store_id() == ECWID_DEMO_STORE_ID || isset($_GET['connection_error'])) {
1611
+
1612
+ require_once ECWID_PLUGIN_DIR . '/templates/connect.php';
1613
  } else {
1614
+ require_once ECWID_PLUGIN_DIR . '/templates/dashboard.php';
1615
+ }
1616
+ }
1617
 
1618
+ function ecwid_process_oauth_params() {
 
1619
 
1620
+ if (strtoupper($_SERVER['REQUEST_METHOD']) != 'GET' || !isset($_GET['page'])) {
1621
+ return;
1622
+ }
1623
+
1624
+ $is_dashboard = $_GET['page'] == 'ecwid';
1625
+
1626
+ if (!$is_dashboard) {
1627
+ return;
1628
+ }
1629
+
1630
+ global $ecwid_oauth;
1631
+ $is_connect = get_ecwid_store_id() != ECWID_DEMO_STORE_ID && !isset($_GET['connection_error']);
1632
+
1633
+ $is_reconnect = isset($_GET['reconnect']) && !isset($_GET['connection_error']);
1634
+
1635
+ if ($is_connect) {
1636
+ $ecwid_oauth->update_state( array( 'mode' => 'connect' ) );
1637
+ }
1638
+
1639
+ if ($is_reconnect) {
1640
+ $ecwid_oauth->update_state( array(
1641
+ 'mode' => 'reconnect',
1642
+ // explicitly set to empty array if not available to reset current state
1643
+ 'scope' => isset($_GET['scope']) ? $_GET['scope'] : array(),
1644
+ // explicitly set to empty string if not available to reset current state
1645
+ 'return_url' => isset($_GET['return-url']) ? $_GET['return-url'] : '',
1646
+ 'reason' => isset($_GET['reason']) ? $_GET['reason'] : ''
1647
+ ));
1648
  }
1649
  }
1650
 
1656
  update_option('ecwid_api_check_time', 0);
1657
  update_option('ecwid_last_oauth_fail_time', 1);
1658
  wp_redirect('admin.php?page=ecwid');
1659
+ exit;
1660
  }
1661
  global $ecwid_oauth;
1662
 
1663
  if (ecwid_test_oauth(true)) {
1664
+
1665
  wp_redirect($ecwid_oauth->get_auth_dialog_url());
1666
+ } else if (!isset($_GET['reconnect'])) {
1667
  wp_redirect('admin.php?page=ecwid&oauth=no');
1668
+ } else {
1669
+ wp_redirect('admin.php?page=ecwid&reconnect&connection_error');
1670
  }
1671
+ exit;
1672
  }
1673
 
1674
  function ecwid_test_oauth($force = false)
2261
  if ( $title )
2262
  echo $before_title . $title . $after_title;
2263
 
2264
+ echo '<!-- noptimize -->' . ecwid_get_scriptjs_code() . '<!-- /noptimize -->';
2265
 
2266
  $recently_viewed = false;
2267
  if (isset($_COOKIE['ecwid-shopping-cart-recently-viewed'])) {
2281
  $api = ecwid_new_product_api();
2282
  }
2283
 
2284
+ $counter = 0;
2285
  $ids = array();
2286
  if ($recently_viewed && isset($recently_viewed->products)) {
2287
 
2297
  $product_https = $api->get_product_https($product->id);
2298
  }
2299
 
2300
+ $name = isset($product_https) ? $product_https['name']: '';
2301
+
2302
  echo <<<HTML
2303
+ <a class="product$hide" href="$product->link" alt="$name" title="$name">
2304
  <div class="ecwid ecwid-SingleProduct ecwid-Product ecwid-Product-$product->id" data-single-product-link="$product->link" itemscope itemtype="http://schema.org/Product" data-single-product-id="$product->id">
2305
  <div itemprop="image" data-force-image="$product_https[imageUrl]"></div>
2306
  <div class="ecwid-title" itemprop="name"></div>
2307
  <div itemtype="http://schema.org/Offer" itemscope itemprop="offers"><div class="ecwid-productBrowser-price ecwid-price" itemprop="price"></div></div>
2308
  </div>
2309
+
2310
+ <!-- noptimize --><script type="text/javascript">xSingleProduct();</script><!-- /noptimize -->
2311
  </a>
2312
  HTML;
2313
  }
2454
  'recently_viewed_widget',
2455
  'avalanche_used',
2456
  'chameleon_used',
2457
+ 'http_post_fails',
2458
+ 'ecwid_use_new_horizontal_categories'
2459
  );
2460
 
2461
  $usage_stats = ecwid_gather_usage_stats();
2493
  'recently_viewed_widget',
2494
  'avalanche_used',
2495
  'chameleon_used',
2496
+ 'http_post_fails',
2497
+ 'ecwid_use_new_horizontal_categories'
2498
  );
2499
 
2500
  $usage_stats = array();
2518
  $usage_stats['avalanche_used'] = (bool) is_plugin_active('ecwid-widgets-avalanche/ecwid_widgets_avalanche.php');
2519
  $usage_stats['chameleon_used'] = (bool)get_option('ecwid_use_chameleon');
2520
  $usage_stats['http_post_fails'] = get_option('ecwid_last_oauth_fail_time') > 0;
2521
+ $usage_stats['ecwid_use_new_horizontal_categories'] = (bool) get_option('ecwid_use_new_horizontal_categories');
2522
+
2523
 
2524
  return $usage_stats;
2525
  }
includes/class-ecwid-message-manager.php CHANGED
@@ -212,6 +212,10 @@ class Ecwid_Message_Manager
212
  $admin_page = $screen->base;
213
  }
214
 
 
 
 
 
215
  switch ($name) {
216
  case 'on_activate':
217
  return $admin_page == 'plugins' && get_ecwid_store_id() == ECWID_DEMO_STORE_ID;
212
  $admin_page = $screen->base;
213
  }
214
 
215
+ if ($admin_page == 'toplevel_page_ecwid' && isset($_GET['reconnect'])) {
216
+ return false;
217
+ }
218
+
219
  switch ($name) {
220
  case 'on_activate':
221
  return $admin_page == 'plugins' && get_ecwid_store_id() == ECWID_DEMO_STORE_ID;
includes/class-ecwid-oauth.php CHANGED
@@ -1,12 +1,33 @@
1
  <?php
2
 
 
 
 
3
  class Ecwid_OAuth {
4
 
 
 
 
 
 
 
 
 
 
 
 
 
5
  public function __construct()
6
  {
7
  add_action('admin_post_ecwid_oauth', array($this, 'process_authorization'));
 
8
  add_action('admin_post_ecwid_disconnect', array($this, 'disconnect_store'));
9
  add_action('admin_post_ecwid_show_reconnect', array($this, 'show_reconnect'));
 
 
 
 
 
10
  }
11
 
12
  public function show_reconnect()
@@ -22,33 +43,64 @@ class Ecwid_OAuth {
22
  return is_array($return);
23
  }
24
 
25
- public function get_auth_dialog_url( $scopes = array( 'read_store_profile', 'read_catalog' ) )
26
  {
27
- if ( !is_array( $scopes ) ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  return false;
29
  }
30
 
31
  $url = 'https://my.ecwid.com/api/oauth/authorize';
32
 
33
- $params['source'] = 'wporg';
34
- $params['client_id'] = get_option( 'ecwid_oauth_client_id' );
35
- $params['redirect_uri'] = admin_url( 'admin-post.php?action=ecwid_oauth' );
36
- $params['response_type'] = 'code';
37
- $params['scope'] = implode( ',', $scopes );
 
 
 
 
 
38
 
39
- return $url . '?' . build_query( $params );
40
  }
41
 
42
  public function process_authorization()
43
  {
 
 
44
  if ( isset( $_REQUEST['error'] ) || !isset( $_REQUEST['code'] ) ) {
45
- return $this->trigger_auth_error();
 
 
 
 
 
 
 
46
  }
47
 
 
 
48
  $params['code'] = $_REQUEST['code'];
49
- $params['client_id'] = get_option( 'ecwid_oauth_client_id' );
50
- $params['client_secret'] = get_option( 'ecwid_oauth_client_secret' );
51
- $params['redirect_uri'] = admin_url( 'admin-post.php?action=ecwid_oauth' );
 
52
  $params['grant_type'] = 'authorization_code';
53
 
54
  $return = wp_remote_post('https://my.ecwid.com/api/oauth/token', array('body' => $params));
@@ -65,28 +117,57 @@ class Ecwid_OAuth {
65
  || ( $result->token_type != 'Bearer' )
66
  ) {
67
  ecwid_log_error(var_export($return, true));
68
- return $this->trigger_auth_error();
69
  }
70
 
71
  update_option( 'ecwid_store_id', $result->store_id );
72
- update_option( 'ecwid_oauth_token', $result->access_token );
 
73
 
 
 
74
  setcookie('ecwid_create_store_clicked', null, strtotime('-1 day'), ADMIN_COOKIE_PATH, COOKIE_DOMAIN);
75
 
76
- wp_redirect('admin.php?page=ecwid&settings-updated=true');
 
 
 
 
 
77
  }
78
 
79
  public function disconnect_store()
80
  {
81
  update_option( 'ecwid_store_id', '' );
82
  update_option( 'ecwid_oauth_token', '' );
83
- update_option('ecwid_is_api_enabled', 'off');
84
- update_option('ecwid_api_check_time', 0);
85
 
86
  wp_redirect('admin.php?page=ecwid');
 
87
  }
88
 
89
- protected function trigger_auth_error()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
  {
91
  update_option('ecwid_last_oauth_fail_time', time());
92
 
@@ -96,21 +177,172 @@ class Ecwid_OAuth {
96
  $logs = json_decode($logs);
97
  }
98
 
99
- if (count($logs) > 0) {
100
  $entry = $logs[count($logs) - 1];
101
  if (isset($entry->message)) {
102
  $last_error = $entry->message;
103
  }
104
  }
105
- if (!$last_error) {
106
- return;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
107
  }
108
 
109
- $url = 'http://' . APP_ECWID_COM . '/script.js?805056&data_platform=wporg&data_wporg_error=' . urlencode($last_error) . '&url=' . urlencode(get_bloginfo('url'));
 
110
 
111
- wp_remote_get($url);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
112
 
113
- wp_redirect('admin.php?page=ecwid&connection_error=true');
 
114
  }
115
  }
116
 
1
  <?php
2
 
3
+
4
+ include ECWID_PLUGIN_DIR . "lib/phpseclib/AES.php";
5
+
6
  class Ecwid_OAuth {
7
 
8
+ const OAUTH_CLIENT_ID = 'RD4o2KQimiGUrFZc';
9
+ const OAUTH_CLIENT_SECRET = 'jEPVdcA3KbzKVrG8FZDgNnsY3wKHDTF8';
10
+
11
+ const TOKEN_OPTION_NAME = 'ecwid_oauth_token';
12
+
13
+ const MODE_CONNECT = 'connect';
14
+ const MODE_RECONNECT = 'reconnect';
15
+
16
+ protected $crypt = null;
17
+
18
+ protected $state;
19
+
20
  public function __construct()
21
  {
22
  add_action('admin_post_ecwid_oauth', array($this, 'process_authorization'));
23
+ add_action('admin_post_ecwid_oauth_reconnect', array($this, 'process_authorization'));
24
  add_action('admin_post_ecwid_disconnect', array($this, 'disconnect_store'));
25
  add_action('admin_post_ecwid_show_reconnect', array($this, 'show_reconnect'));
26
+
27
+ $this->crypt = new Crypt_AES();
28
+ $this->_init_crypt();
29
+
30
+ $this->_load_state();
31
  }
32
 
33
  public function show_reconnect()
43
  return is_array($return);
44
  }
45
 
46
+ public function get_auth_dialog_url()
47
  {
48
+ $action = 'ecwid_oauth';
49
+ if ( $this->_is_reconnect() ) {
50
+ $action = 'ecwid_oauth_reconnect';
51
+ }
52
+
53
+ $redirect_uri = 'admin-post.php?action=' . $action;
54
+
55
+ $params = array(
56
+ 'scopes' => implode(' ', $this->_get_scope()),
57
+ 'redirect_uri' => admin_url( $redirect_uri )
58
+ );
59
+
60
+ if ( !is_array( $params )
61
+ || empty( $params['scopes'] )
62
+ ) {
63
  return false;
64
  }
65
 
66
  $url = 'https://my.ecwid.com/api/oauth/authorize';
67
 
68
+ $query = array();
69
+
70
+ $query['source'] = 'wporg';
71
+ $query['client_id'] = self::OAUTH_CLIENT_ID;
72
+ $query['redirect_uri'] = $params['redirect_uri'];
73
+ $query['response_type'] = 'code';
74
+ $query['scope'] = $params['scopes'];
75
+ foreach ($query as $key => $value) {
76
+ $query[$key] = urlencode($value);
77
+ }
78
 
79
+ return $url . '?' . build_query( $query );
80
  }
81
 
82
  public function process_authorization()
83
  {
84
+ $reconnect = $_REQUEST['action'] == 'ecwid_oauth_reconnect';
85
+
86
  if ( isset( $_REQUEST['error'] ) || !isset( $_REQUEST['code'] ) ) {
87
+ if ($reconnect) {
88
+ $this->update_state(array('mode' => self::MODE_RECONNECT, 'error' => 'cancelled'));
89
+ } else {
90
+ $this->update_state(array('mode' => self::MODE_CONNECT, 'error' => 'cancelled'));
91
+ }
92
+
93
+ wp_redirect('admin.php?page=ecwid&connection_error' . ($reconnect ? '&reconnect' : ''));
94
+ exit;
95
  }
96
 
97
+ $base_admin_url = 'admin-post.php?action=ecwid_oauth' . ($reconnect ? '_reconnect' : '');
98
+
99
  $params['code'] = $_REQUEST['code'];
100
+ $params['client_id'] = self::OAUTH_CLIENT_ID;
101
+ $params['client_secret'] = self::OAUTH_CLIENT_SECRET;
102
+ $params['redirect_uri'] = admin_url( $base_admin_url );
103
+
104
  $params['grant_type'] = 'authorization_code';
105
 
106
  $return = wp_remote_post('https://my.ecwid.com/api/oauth/token', array('body' => $params));
117
  || ( $result->token_type != 'Bearer' )
118
  ) {
119
  ecwid_log_error(var_export($return, true));
120
+ return $this->trigger_auth_error($reconnect ? 'reconnect' : 'default');
121
  }
122
 
123
  update_option( 'ecwid_store_id', $result->store_id );
124
+ $this->_init_crypt();
125
+ $this->_save_token($result->access_token);
126
 
127
+ // Reset "Create store cookie" set previously to display the landing page
128
+ //in "Connect" mode rather than "Create" mode
129
  setcookie('ecwid_create_store_clicked', null, strtotime('-1 day'), ADMIN_COOKIE_PATH, COOKIE_DOMAIN);
130
 
131
+ if ( isset( $this->state->return_url ) && !empty( $this->state->return_url ) ) {
132
+ wp_redirect( admin_url( $this->state->return_url ) );
133
+ } else {
134
+ wp_redirect( 'admin.php?page=ecwid&settings-updated=true' );
135
+ }
136
+ exit;
137
  }
138
 
139
  public function disconnect_store()
140
  {
141
  update_option( 'ecwid_store_id', '' );
142
  update_option( 'ecwid_oauth_token', '' );
143
+ update_option( 'ecwid_is_api_enabled', 'off' );
144
+ update_option( 'ecwid_api_check_time', 0 );
145
 
146
  wp_redirect('admin.php?page=ecwid');
147
+ exit;
148
  }
149
 
150
+ public function get_safe_scopes_array($scopes)
151
+ {
152
+ if (!isset($scopes) || empty($scopes)) {
153
+ return array( 'read_store_profile', 'read_catalog' );
154
+ }
155
+
156
+ if (!empty($scopes)) {
157
+ $scopes_array = explode(' ', $scopes);
158
+
159
+ foreach ($scopes_array as $key => $scope) {
160
+ if (!preg_match('/^[a-z_]+$/', $scope)) {
161
+ unset($scopes_array[$key]);
162
+ }
163
+ }
164
+ }
165
+
166
+ return $scopes_array;
167
+ }
168
+
169
+
170
+ protected function trigger_auth_error($mode = 'default')
171
  {
172
  update_option('ecwid_last_oauth_fail_time', time());
173
 
177
  $logs = json_decode($logs);
178
  }
179
 
180
+ if (is_array($logs) && count($logs) > 0) {
181
  $entry = $logs[count($logs) - 1];
182
  if (isset($entry->message)) {
183
  $last_error = $entry->message;
184
  }
185
  }
186
+
187
+ if ( $mode == self::MODE_RECONNECT ) {
188
+ $this->update_state(array(
189
+ 'mode' => 'reconnect',
190
+ 'error' => 'other'
191
+ ));
192
+ }
193
+
194
+ if (isset($last_error)) {
195
+ $url = 'http://' . APP_ECWID_COM . '/script.js?805056&data_platform=wporg&data_wporg_error=' . urlencode($last_error) . '&url=' . urlencode(get_bloginfo('url'));
196
+ wp_remote_get($url);
197
+ }
198
+
199
+ wp_redirect('admin.php?page=ecwid&connection_error' . ($mode == self::MODE_RECONNECT ? '&reconnect' : ''));
200
+ exit;
201
+ }
202
+
203
+ public function get_oauth_token()
204
+ {
205
+ if ($this->is_initialized()) {
206
+ return $this->_load_token();
207
  }
208
 
209
+ return null;
210
+ }
211
 
212
+ protected function _get_scope() {
213
+ $default = array( 'read_store_profile', 'read_catalog' );
214
+
215
+ $scopes = array();
216
+ if ( $this->_is_reconnect() ) {
217
+ $scopes = isset($this->state->reconnect_scopes) && is_array($this->state->reconnect_scopes)
218
+ ? $this->state->reconnect_scopes
219
+ : array();
220
+ }
221
+
222
+ $scopes = array_merge($scopes, $default);
223
+
224
+ return $scopes;
225
+ }
226
+
227
+ public function is_initialized()
228
+ {
229
+ return get_option( self::TOKEN_OPTION_NAME );
230
+ }
231
+
232
+ protected function _save_token($token)
233
+ {
234
+ $value = base64_encode($this->crypt->encrypt($token));
235
+
236
+ update_option(self::TOKEN_OPTION_NAME, $value);
237
+ }
238
+
239
+ protected function _load_token()
240
+ {
241
+
242
+ $db_value = get_option(self::TOKEN_OPTION_NAME);
243
+ if (empty($db_value)) return false;
244
+
245
+ if (strlen($db_value) == 64) {
246
+ $encrypted = base64_decode($db_value);
247
+ if (empty($encrypted)) return false;
248
+
249
+ $token = $this->crypt->decrypt($encrypted);
250
+ } else {
251
+ $token = $db_value;
252
+ }
253
+
254
+ return $token;
255
+ }
256
+
257
+ public function _init_crypt() {
258
+ $this->crypt->setIV( substr( md5( SECURE_AUTH_SALT . get_option('ecwid_store_id') ), 0, 16 ) );
259
+ $this->crypt->setKey( SECURE_AUTH_KEY );
260
+ }
261
+
262
+ protected function _load_state() {
263
+ if (isset($_COOKIE['ecwid_oauth_state'])) {
264
+ $this->state = unserialize( $_COOKIE['ecwid_oauth_state'] );
265
+ } else {
266
+ $this->state = new stdClass();
267
+ $this->state->reconnect_scopes = array();
268
+ $this->state->reconnect_error = '';
269
+ $this->state->return_url = '';
270
+ $this->state->reason = '';
271
+ }
272
+
273
+ $this->state->create_store_clicked = @$_COOKIE['ecwid_create_store_clicked'];
274
+ }
275
+
276
+ public function get_state() {
277
+ return $this->state;
278
+ }
279
+
280
+ public function was_create_store_clicked() {
281
+ return $this->state->create_store_clicked;
282
+ }
283
+
284
+ protected function _save_state() {
285
+ setcookie('ecwid_oauth_state', serialize($this->state), strtotime('+1 day'), ADMIN_COOKIE_PATH, COOKIE_DOMAIN);
286
+ }
287
+
288
+ public function get_reconnect_error() {
289
+ return $this->state->reconnect_error;
290
+ }
291
+
292
+ public function update_state($params) {
293
+
294
+ if (isset($params['mode'])) {
295
+ $this->state->mode = $params['mode'] == self::MODE_RECONNECT ? self::MODE_RECONNECT : self::MODE_CONNECT;
296
+ }
297
+
298
+ if ( $this->_is_reconnect() ) {
299
+ if ( isset( $params['scope'] ) ) {
300
+ $this->state->reconnect_scopes = $this->get_safe_scopes_array( @$params['scope'] );
301
+ }
302
+ if ( isset( $params['return_url'] ) ) {
303
+ $this->state->return_url = $params['return_url'];
304
+ }
305
+
306
+ if ( isset( $params['error'] ) ) {
307
+ $this->state->reconnect_error = $params['error'];
308
+ }
309
+
310
+ if ( isset( $params['reason'] ) ) {
311
+ $this->state->reason = $params['reason'];
312
+ }
313
+ }
314
+
315
+ $this->_save_state();
316
+ }
317
+
318
+ public function get_error() {
319
+
320
+ if ($this->_is_reconnect()) {
321
+ return $this->state->reconnect_error;
322
+ } else {
323
+ return $this->state->error;
324
+ }
325
+ }
326
+
327
+ public function get_reconnect_message() {
328
+ $reconnect_message = '';
329
+
330
+ if (isset($this->state->reason)) {
331
+ switch ( $this->state->reason ) {
332
+ case '1':
333
+ $reconnect_message = "Message 1";
334
+ break;
335
+ case '2':
336
+ $reconnect_message = "Message 2";
337
+ break;
338
+ }
339
+ }
340
+
341
+ return $reconnect_message;
342
+ }
343
 
344
+ protected function _is_reconnect() {
345
+ return $this->state->mode == self::MODE_RECONNECT;
346
  }
347
  }
348
 
js/recently-viewed.js CHANGED
@@ -79,4 +79,3 @@ jQuery.widget('ecwid.recentlyViewedProducts', jQuery.ecwid.productsList, {
79
  }
80
  });
81
 
82
- jQuery('.ecwid-recently-viewed-products').recentlyViewedProducts();
79
  }
80
  });
81
 
 
languages/ecwid-shopping-cart-it_IT.mo CHANGED
Binary file
languages/ecwid-shopping-cart-it_IT.po CHANGED
@@ -58,8 +58,11 @@ msgstr "Avanzate"
58
  msgid "Hidden category"
59
  msgstr "Categoria nascosta"
60
 
61
- msgid "If you like Ecwid and want to help it grow and become the most popular e-commerce solution, you can now add a fancy 'Powered by Ecwid' badge on your site to show your visitors that you're a proud user of Ecwid."
62
- msgstr "Se ti piace Ecwid e vuoi aiutarlo a crescere in modo da farlo diventare la soluzione e-commerce più popolare, è ora possibile aggiungere un badge 'Powered by Ecwid' sul tuo sito per mostrare ai tuoi visitatori che sei un utente fiero di Ecwid."
 
 
 
63
 
64
  msgid "Ecwid Badge"
65
  msgstr "Ecwid Badge"
@@ -79,42 +82,51 @@ msgstr "Ecwid shopping cart"
79
  msgid "Ecwid e-commerce widgets"
80
  msgstr "Widget Ecwid e-commerce "
81
 
82
- msgid "Your store's minicart"
83
- msgstr "Carrello del tuo negozio"
 
 
 
84
 
85
- msgid "Ecwid Shopping Bag (Normal)"
86
- msgstr "Carrello Ecwid Shopping Bag (Normale)"
87
 
88
- msgid "Ecwid Shopping Bag (Mini view)"
89
- msgstr "Carrello Ecwid Shopping (Mini)"
90
 
91
- msgid "Your store's search box"
92
- msgstr "La casella di ricerca del tuo negozio"
93
 
94
- msgid "Ecwid Search Box"
95
- msgstr "Casella di ricerca negozio"
96
 
97
- msgid "Vertical menu of categories"
98
- msgstr "Menu verticale categorie"
99
 
100
- msgid "Ecwid Vertical Categories"
101
- msgstr "Categorie Verticali Ecwid "
102
 
103
- msgid "A link to your store page"
104
- msgstr "Un link alla tua pagina del negozio"
105
 
106
- msgid "Ecwid Store Page Link"
107
- msgstr "Link alla pagina negozio Ecwid"
108
 
109
  msgid "Shop"
110
  msgstr "Negozio"
111
 
112
- msgid "A list of products recently viewed by a customer. Add this widget to the sidebar to let them later return to the products they saw in your shop."
113
- msgstr "Un elenco di prodotti visualizzate di recente da un cliente. Aggiungi questo widget nella barra laterale per farli tornare successivamente per i prodotti che hanno visto nel tuo negozio."
114
 
115
  msgid "Recently Viewed Products"
116
  msgstr "Prodotti visti recentemente"
117
 
 
 
 
 
 
 
118
  msgid "Number of products to show"
119
  msgstr "Numero di prodotti da mostrare"
120
 
@@ -202,6 +214,21 @@ msgstr "Questa funzione opzionale consente di abilitare la Sign-on Secret Key, q
202
  msgid "In order to enable this feature, opt to use a secret key. You will find this key in your Ecwid control panel, at \"System Settings > Apps > Legacy API Keys > Single Sign-On Secret Key\" page. This feature is available for <a href=\"http://www.ecwid.com/compare-plans.html\" target=\"_blank\">paid users</a> only."
203
  msgstr "Per abilitare questa funzione è necessario essere in possesso di una chiave segreta. Troverai questo pulsante nel pannello di controllo Ecwid, in \"Impostazioni di sistema > Apps > Single Sign-on API secret key\" . Questa funzione è disponibile per tutti gli <a href=\"http://www.ecwid.com/compare-plans.html\" target=\"_blank\">utenti paganti</a>."
204
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
205
  msgid "Save changes"
206
  msgstr "Salva modifiche"
207
 
@@ -214,14 +241,14 @@ msgstr "Mostra casella di ricerca sopra prodotti"
214
  msgid "Or you can add search box to your website's toolbar using <a href=\"%s\">WordPress native widgets</a>"
215
  msgstr "Puoi anche aggiungere alla barra degli strumenti la casella di ricerca del tuo sito web utilizzando i <a href=\"%s\">widgets nativi di WordPress</a>"
216
 
217
- msgid "Display horizontal categories above products"
218
- msgstr "Visualizza le categorie orizzontali sopra i prodotti"
219
 
220
  msgid "Or you can add vertical categories to your website's toolbar using <a href=\"%s\">WordPress native widgets</a>"
221
  msgstr "Puoi anche aggiungere alla barra degli strumenti le categorie verticali utilizzando i <a href=\"%s\">widgets nativi di WordPress</a>"
222
 
223
- msgid "Enable minicart attached to horizontal categories"
224
- msgstr "Abilita carrello attaccato alle categorie orizzontali"
225
 
226
  msgid "You should disable this option, if you added minicart to your website's&nbsp;sidebar"
227
  msgstr "È necessario disattivare questa opzione, se hai aggiunto il carrello al tuo sito web&nbsp;sidebar"
@@ -262,15 +289,27 @@ msgstr "Modalità di visualizzazione predefinita nei risultati di ricerca"
262
  msgid "Connect your store<br /> to this WordPress site"
263
  msgstr "Collega il tuo negozio<br /> a questo sito WordPress"
264
 
 
 
 
265
  msgid "Connect Ecwid store"
266
  msgstr "Collega Ecwid store"
267
 
 
 
 
268
  msgid "After clicking button you need to login and accept permissions to use our plugin"
269
  msgstr "Dopo aver cliccato il pulsante devi accedere e accettare le autorizzazioni necessarie per utilizzare il nostro plugin"
270
 
271
  msgid "Connection error - after clicking button you need to login and accept permissions to use our plugin. Please, try again."
272
  msgstr "Errore di connessione - dopo aver cliccato il pulsante, è necessario accedere e accettare le autorizzazioni necessarie per utilizzare il nostro plugin. Per favore, riprova."
273
 
 
 
 
 
 
 
274
  msgid "Don't have Ecwid account? Create it here"
275
  msgstr "Non hai un accont Ecwid? Crealo qui"
276
 
@@ -382,8 +421,8 @@ msgstr "Ecwid i comatibile con il tuo<br>“%s” tema WordPress<br>e altri temi
382
  msgid "Free and always up to date"
383
  msgstr "Gratuito e sempre aggiornato"
384
 
385
- msgid "Free plan always available with tons of features<br>at no additional cost. Seamless upgrades occur<br>automatically for free."
386
- msgstr "Piano gratuito sempre disponibile con tante caratteristiche<br>senza alcun costo aggiuntivo. Continui aggiornamenti<br>automatici e gratuiti."
387
 
388
  msgid "Responsive design"
389
  msgstr "Design eccezionale"
@@ -400,8 +439,8 @@ msgstr "Checkout sicuro con oltre 40<br />opzioni di pagamento"
400
  msgid "Global Reach"
401
  msgstr "Portata globale"
402
 
403
- msgid "More than 700,000 merchants in 175 countries"
404
- msgstr "Più di 700.000 venditori in 175 paesi"
405
 
406
  msgid "Start selling <br>on your WordPress <nobr>site for free</nobr>"
407
  msgstr "Inizia a vendere <br>sul tuo WordPress <nobr>sito gratis</nobr>"
@@ -439,8 +478,8 @@ msgstr "Mostra ricerca"
439
  msgid "Show minicart"
440
  msgstr "Mostra carrello"
441
 
442
- msgid "Show horizontal categories"
443
- msgstr "Mostra categorie orizzontali"
444
 
445
  msgid "Additionally, you can add store controls to your website's toolbar using <a %s>WordPress native widgets</a>"
446
  msgstr "Inoltre, è possibile aggiungere altri controlli alla barra degli strumenti del tuo sito Web utilizzando i <a %s>widgets nativi WordPress</a>"
@@ -457,3 +496,21 @@ msgstr "Qui verrà mostrato il tuo negozio!"
457
  msgid "Demo Store"
458
  msgstr "Negozio demo"
459
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
  msgid "Hidden category"
59
  msgstr "Categoria nascosta"
60
 
61
+ msgid "Recommendations for Your Online Store"
62
+ msgstr "Consigli per il tuo negozio Online"
63
+
64
+ msgid "Do you like Ecwid and want to help it grow? You can add this fancy 'Powered by Ecwid' badge on your site to show your visitors that you're a proud user of Ecwid."
65
+ msgstr "Do you like Ecwid and want to help it grow? You can add this fancy 'Powered by Ecwid' badge on your site to show your visitors that you're a proud user of Ecwid."
66
 
67
  msgid "Ecwid Badge"
68
  msgstr "Ecwid Badge"
82
  msgid "Ecwid e-commerce widgets"
83
  msgstr "Widget Ecwid e-commerce "
84
 
85
+ msgid "Adds a cart widget for customer to see the products they added to the cart."
86
+ msgstr "Adds a cart widget for customer to see the products they added to the cart."
87
+
88
+ msgid "Shopping Cart"
89
+ msgstr "Shopping Cart"
90
 
91
+ msgid "Adds a compact cart widget for customer to see the products they added to the cart."
92
+ msgstr "Adds a compact cart widget for customer to see the products they added to the cart."
93
 
94
+ msgid "Shopping Cart (Mini)"
95
+ msgstr "Shopping Cart (Mini)"
96
 
97
+ msgid "Displays a simple search box for your customers to find a product in your storex"
98
+ msgstr "Displays a simple search box for your customers to find a product in your storex"
99
 
100
+ msgid "Product Search"
101
+ msgstr "Product Search"
102
 
103
+ msgid "Adds vertical categories block to let the customer navigate your store."
104
+ msgstr "Adds vertical categories block to let the customer navigate your store."
105
 
106
+ msgid "Store Categories"
107
+ msgstr "Store Categories"
108
 
109
+ msgid "Displays a link to the store page in sidebar for customer to quickly access your store from any page on the site."
110
+ msgstr "Displays a link to the store page in sidebar for customer to quickly access your store from any page on the site."
111
 
112
+ msgid "Store Page Link"
113
+ msgstr "Store Page Link"
114
 
115
  msgid "Shop"
116
  msgstr "Negozio"
117
 
118
+ msgid "Displays a list of products recently viewed by the customer to easily return to the products they saw in your shop."
119
+ msgstr "Displays a list of products recently viewed by the customer to easily return to the products they saw in your shop."
120
 
121
  msgid "Recently Viewed Products"
122
  msgstr "Prodotti visti recentemente"
123
 
124
+ msgid "You have not viewed any product yet. Open store."
125
+ msgstr "You have not viewed any product yet. Open store."
126
+
127
+ msgid "Store Link Title"
128
+ msgstr "Titolo link per il negozio"
129
+
130
  msgid "Number of products to show"
131
  msgstr "Numero di prodotti da mostrare"
132
 
214
  msgid "In order to enable this feature, opt to use a secret key. You will find this key in your Ecwid control panel, at \"System Settings > Apps > Legacy API Keys > Single Sign-On Secret Key\" page. This feature is available for <a href=\"http://www.ecwid.com/compare-plans.html\" target=\"_blank\">paid users</a> only."
215
  msgstr "Per abilitare questa funzione è necessario essere in possesso di una chiave segreta. Troverai questo pulsante nel pannello di controllo Ecwid, in \"Impostazioni di sistema > Apps > Single Sign-on API secret key\" . Questa funzione è disponibile per tutti gli <a href=\"http://www.ecwid.com/compare-plans.html\" target=\"_blank\">utenti paganti</a>."
216
 
217
+ msgid "Chameleon skin <sup>beta</sup>"
218
+ msgstr "Tema Chameleon <sup>beta</sup>"
219
+
220
+ msgid "Automatic adjustment of your store design to your Wordpress theme. Whatever Wordpress theme you use, Ecwid will detect predominant colors and font and use them in your product catalog."
221
+ msgstr "Regolazione automatica del design del tuo negozio per il tema Wordpress. Qualsiasi tema Wordpress utilizzi, Ecwid rileverà font e colori predominanti e li utilizzerà nel tuo catalogo prodotti."
222
+
223
+ msgid "Please note this functionality is in beta. So if you run into difficulties or find problems with Chameleon, please <a %s>let us know</a>."
224
+ msgstr "Please note this functionality is in beta. So if you run into difficulties or find problems with Chameleon, please <a %s>let us know</a>."
225
+
226
+ msgid "Enable the new category menu"
227
+ msgstr "Enable the new category menu"
228
+
229
+ msgid "The new category menu looks better and is more mobile-friendly. If you haven't yet added category menu to your store page, you can do that in the <a %s>store page editor</a> (enable the \"Show categories\" option)"
230
+ msgstr "The new category menu looks better and is more mobile-friendly. If you haven't yet added category menu to your store page, you can do that in the <a %s>store page editor</a> (enable the \"Show categories\" option)"
231
+
232
  msgid "Save changes"
233
  msgstr "Salva modifiche"
234
 
241
  msgid "Or you can add search box to your website's toolbar using <a href=\"%s\">WordPress native widgets</a>"
242
  msgstr "Puoi anche aggiungere alla barra degli strumenti la casella di ricerca del tuo sito web utilizzando i <a href=\"%s\">widgets nativi di WordPress</a>"
243
 
244
+ msgid "Display categories above products"
245
+ msgstr "Display categories above products"
246
 
247
  msgid "Or you can add vertical categories to your website's toolbar using <a href=\"%s\">WordPress native widgets</a>"
248
  msgstr "Puoi anche aggiungere alla barra degli strumenti le categorie verticali utilizzando i <a href=\"%s\">widgets nativi di WordPress</a>"
249
 
250
+ msgid "Enable minicart attached to categories"
251
+ msgstr "Enable minicart attached to categories"
252
 
253
  msgid "You should disable this option, if you added minicart to your website's&nbsp;sidebar"
254
  msgstr "È necessario disattivare questa opzione, se hai aggiunto il carrello al tuo sito web&nbsp;sidebar"
289
  msgid "Connect your store<br /> to this WordPress site"
290
  msgstr "Collega il tuo negozio<br /> a questo sito WordPress"
291
 
292
+ msgid "Enter your Store ID"
293
+ msgstr "Enter your Store ID"
294
+
295
  msgid "Connect Ecwid store"
296
  msgstr "Collega Ecwid store"
297
 
298
+ msgid "Save and connect"
299
+ msgstr "Save and connect"
300
+
301
  msgid "After clicking button you need to login and accept permissions to use our plugin"
302
  msgstr "Dopo aver cliccato il pulsante devi accedere e accettare le autorizzazioni necessarie per utilizzare il nostro plugin"
303
 
304
  msgid "Connection error - after clicking button you need to login and accept permissions to use our plugin. Please, try again."
305
  msgstr "Errore di connessione - dopo aver cliccato il pulsante, è necessario accedere e accettare le autorizzazioni necessarie per utilizzare il nostro plugin. Per favore, riprova."
306
 
307
+ msgid "Where to find your Store ID:"
308
+ msgstr "Where to find your Store ID:"
309
+
310
+ msgid "Store ID is a unique identifier of your Ecwid account. You can find it in your Ecwid control panel: open the <a %s>Dashboard page</a> and find the \"<b>Store ID: NNNNNNN</b>\" text, where <b>NNNNNNN</b> is your Store&nbsp;ID."
311
+ msgstr "Store ID is a unique identifier of your Ecwid account. You can find it in your Ecwid control panel: open the <a %s>Dashboard page</a> and find the \"<b>Store ID: NNNNNNN</b>\" text, where <b>NNNNNNN</b> is your Store&nbsp;ID."
312
+
313
  msgid "Don't have Ecwid account? Create it here"
314
  msgstr "Non hai un accont Ecwid? Crealo qui"
315
 
421
  msgid "Free and always up to date"
422
  msgstr "Gratuito e sempre aggiornato"
423
 
424
+ msgid "Free plan always available with tons of features<br>at no additional cost. Updates are seamless, automatic<br>and free of charge."
425
+ msgstr "Free plan always available with tons of features<br>at no additional cost. Updates are seamless, automatic<br>and free of charge."
426
 
427
  msgid "Responsive design"
428
  msgstr "Design eccezionale"
439
  msgid "Global Reach"
440
  msgstr "Portata globale"
441
 
442
+ msgid "More than 800,000 merchants in 175 countries"
443
+ msgstr "More than 800,000 merchants in 175 countries"
444
 
445
  msgid "Start selling <br>on your WordPress <nobr>site for free</nobr>"
446
  msgstr "Inizia a vendere <br>sul tuo WordPress <nobr>sito gratis</nobr>"
478
  msgid "Show minicart"
479
  msgstr "Mostra carrello"
480
 
481
+ msgid "Show categories"
482
+ msgstr "Show categories"
483
 
484
  msgid "Additionally, you can add store controls to your website's toolbar using <a %s>WordPress native widgets</a>"
485
  msgstr "Inoltre, è possibile aggiungere altri controlli alla barra degli strumenti del tuo sito Web utilizzando i <a %s>widgets nativi WordPress</a>"
496
  msgid "Demo Store"
497
  msgstr "Negozio demo"
498
 
499
+ msgid "Sell On The Go with Ecwid iOS Application"
500
+ msgstr "Sell On The Go with Ecwid iOS Application"
501
+
502
+ msgid "Ecwid iOS app allows you to manage your online store, sell your products on the go, and accept payments with your phone. Just download the Ecwid app, connect it to your Ecwid shop and have your sales at your fingertips!"
503
+ msgstr "Ecwid iOS app allows you to manage your online store, sell your products on the go, and accept payments with your phone. Just download the Ecwid app, connect it to your Ecwid shop and have your sales at your fingertips!"
504
+
505
+ msgid "Get Your Products Found on Google using XML Sitemap"
506
+ msgstr "Get Your Products Found on Google using XML Sitemap"
507
+
508
+ msgid "Free Google XML Sitemaps plugin creates a sitemap that includes your store product links. This makes your product pages more visible to search engines and appear in the search results."
509
+ msgstr "Free Google XML Sitemaps plugin creates a sitemap that includes your store product links. This makes your product pages more visible to search engines and appear in the search results."
510
+
511
+ msgid "Add Product Slider to Your Store"
512
+ msgstr "Add Product Slider to Your Store"
513
+
514
+ msgid "Add a fancy product slider to your site using a free WP Widgets Avalanche plugin which works perfectly with Ecwid"
515
+ msgstr "Add a fancy product slider to your site using a free WP Widgets Avalanche plugin which works perfectly with Ecwid"
516
+
languages/ecwid-shopping-cart-ru_RU.mo CHANGED
Binary file
languages/ecwid-shopping-cart-ru_RU.po CHANGED
@@ -280,8 +280,8 @@ msgstr "Ошибка подключения: после нажатия на кн
280
  msgid "Don't have Ecwid account? Create it here"
281
  msgstr "Ещё нет аккаунта в Эквиде? Зарегистрируйтесь"
282
 
283
- msgid "Questions? Visit <a %s>Ecwid support center</a>"
284
- msgstr "Есть вопросы? Посетите <a %s>Центр поддержки Эквида (англ)</a> или <a target=\"_blank\" href=\"http://www.ecwid.com/forums/forumdisplay.php?f=10\"> русскоязычный раздел форума</a>"
285
 
286
  msgid "Store ID"
287
  msgstr "ID Магазина"
280
  msgid "Don't have Ecwid account? Create it here"
281
  msgstr "Ещё нет аккаунта в Эквиде? Зарегистрируйтесь"
282
 
283
+ msgid "Questions? <a %s>Read FAQ</a> or contact support at <a %s>wordpress@ecwid.com</a>"
284
+ msgstr "Есть вопросы? Посетите <a %s>Центр поддержки Эквида (англ)</a> или напишите нам на <a %s>wordpress@ecwid.com</a>"
285
 
286
  msgid "Store ID"
287
  msgstr "ID Магазина"
languages/ecwid-shopping-cart-tr_TR.mo CHANGED
Binary file
languages/ecwid-shopping-cart-tr_TR.po CHANGED
@@ -1,11 +1,11 @@
1
  msgid "Ecwid Shopping Cart"
2
- msgstr "Ecwid Shopping Cart"
3
 
4
  msgid "Ecwid Team"
5
  msgstr "Ecwid Team"
6
 
7
  msgid "Ecwid is a free full-featured shopping cart. It can be easily integrated with any Wordpress blog and takes less than 5 minutes to set up."
8
- msgstr "Ecwid is a free full-featured shopping cart. It can be easily integrated with any Wordpress blog and takes less than 5 minutes to set up."
9
 
10
  msgid "Get help"
11
  msgstr "Yardım alın"
@@ -35,13 +35,13 @@ msgid "Ecwid shopping cart settings"
35
  msgstr "Ecwid alışveriş sepeti ayarları"
36
 
37
  msgid "Ecwid Store"
38
- msgstr "Ecwid Mağazası"
39
 
40
  msgid "Setup"
41
  msgstr "Kurulum"
42
 
43
  msgid "Dashboard"
44
- msgstr "Dashboard"
45
 
46
  msgid "Appearance settings"
47
  msgstr "Görünüm ayarları"
@@ -58,8 +58,11 @@ msgstr "Gelişmiş"
58
  msgid "Hidden category"
59
  msgstr "Gizli kategori"
60
 
61
- msgid "If you like Ecwid and want to help it grow and become the most popular e-commerce solution, you can now add a fancy 'Powered by Ecwid' badge on your site to show your visitors that you're a proud user of Ecwid."
62
- msgstr "Ecwid online mağazasını beğendiyseniz ve büyümesine yardımcı olmak istiyorsanız, web sitenize güzel görünümlü 'Ecwid Tarafından Desteklenmektedir' yamasını ekleyebilir ve kullanıcılarınıza Ecwid mağazasının tanıtımını yapabilirsiniz."
 
 
 
63
 
64
  msgid "Ecwid Badge"
65
  msgstr "Ecwid Yaması"
@@ -79,42 +82,51 @@ msgstr "Ecwid alışveriş sepeti"
79
  msgid "Ecwid e-commerce widgets"
80
  msgstr "Ecwid e-ticaret widgetleri"
81
 
82
- msgid "Your store's minicart"
83
- msgstr "Mağazanızın mini alışveriş sepeti"
84
 
85
- msgid "Ecwid Shopping Bag (Normal)"
86
- msgstr "Ecwid Alşv. Sepeti (Normal)"
87
 
88
- msgid "Ecwid Shopping Bag (Mini view)"
89
- msgstr "Ecwid Alşv. Sepeti (Küçük)"
90
 
91
- msgid "Your store's search box"
92
- msgstr "Mağazanız için arama kutusu"
93
 
94
- msgid "Ecwid Search Box"
95
- msgstr "Ecwid Arama Kutusu"
96
 
97
- msgid "Vertical menu of categories"
98
- msgstr "Dikey kategori menüsü"
99
 
100
- msgid "Ecwid Vertical Categories"
101
- msgstr "Ecwid Dikey Kategoriler"
102
 
103
- msgid "A link to your store page"
104
- msgstr "A link to your store page"
105
 
106
- msgid "Ecwid Store Page Link"
107
- msgstr "Ecwid Store Page Link"
 
 
 
108
 
109
  msgid "Shop"
110
- msgstr "Shop"
111
 
112
- msgid "A list of products recently viewed by a customer. Add this widget to the sidebar to let them later return to the products they saw in your shop."
113
- msgstr "A list of products recently viewed by a customer. Add this widget to the sidebar to let them later return to the products they saw in your shop."
114
 
115
  msgid "Recently Viewed Products"
116
  msgstr "Recently Viewed Products"
117
 
 
 
 
 
 
 
118
  msgid "Number of products to show"
119
  msgstr "Number of products to show"
120
 
@@ -161,13 +173,13 @@ msgid "Rate Ecwid at WordPress.org"
161
  msgstr "WordPress.org sitesinde Ecwid uygulamasını oylayın"
162
 
163
  msgid "Add Store"
164
- msgstr "Add Store"
165
 
166
  msgid "Edit Store"
167
- msgstr "Edit Store"
168
 
169
  msgid "Edit Appearance"
170
- msgstr "Edit Appearance"
171
 
172
  msgid "Price"
173
  msgstr "Fiyat"
@@ -199,8 +211,23 @@ msgstr "Tek giriş (Single Sign-On) Gizli Anahtarı"
199
  msgid "Single Sign-On Secret Key is an option that allows your customers access to your WordPress site as well as the Ecwid shopping cart. When customers log in to your site, they will automatically be logged in to your Ecwid store as well. It makes sense to enable this feature if your visitors actually create accounts in your WordPress website."
200
  msgstr "Tek giriş (Single Sign-On) gizli anahtarı müşterilerinizin WordPress sayfanızı Ecwid sayfanızı ziyaret eder gibi görüntülemelerini sağlar. Müşteriler sitenize giriş yaptıklarında otomatik olarak Ecwid mağazanıza da giriş yaparlar. Ziyaretçileriniz WordPress sayfanızda hesap oluşturmaya başladığında bu özelliği kullanabilirsiniz."
201
 
202
- msgid "In order to enable this feature, opt to use a secret key. You will find this key in your Ecwid control panel, at \"System Settings > API > Single Sign-On API\" page. This feature is available for <a href=\"http://www.ecwid.com/compare-plans.html\" target=\"_blank\">paid users</a> only."
203
- msgstr "Bu özelliği etkinleştirmek için gizli anahtarı kullanmayı tercih edin. Bu gizli anahtarı Ecwid kontrol panelinizdeki \"Sistem Ayarları > API > Single Sign-On API\" sayfasında bulabilirsiniz. Ancak <a href=\"http://www.ecwid.com/compare-plans.html\" target=\"_blank\">ücretli kullanıcılar</a> bu özellikten faydalanabilir."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
204
 
205
  msgid "Save changes"
206
  msgstr "Değişiklikleri kaydet"
@@ -214,14 +241,14 @@ msgstr "Arama kutusunu ürünlerin üzerinde göster"
214
  msgid "Or you can add search box to your website's toolbar using <a href=\"%s\">WordPress native widgets</a>"
215
  msgstr "Ya da arama kutusunu <a href=\"%s\">WordPress yerleşik widgetlerını</a> kullanarak ekleyebilirsiniz"
216
 
217
- msgid "Display horizontal categories above products"
218
- msgstr "Kategorileri ürünler üzerinde yatay olarak görüntüle"
219
 
220
  msgid "Or you can add vertical categories to your website's toolbar using <a href=\"%s\">WordPress native widgets</a>"
221
  msgstr "Ya da dikey kategorileri sitenin araç çubuğuna <a href=\"%s\">WordPress yerleşik widgetlerını</a> kullanarak ekleyebilirsiniz"
222
 
223
- msgid "Enable minicart attached to horizontal categories"
224
- msgstr "Yatay kategorilere bağlı küçük sepeti etkinleştir"
225
 
226
  msgid "You should disable this option, if you added minicart to your website's&nbsp;sidebar"
227
  msgstr "Web sitenize küçük alışveriş sepeti eklediyseniz bu ayarı devre dışı bırakınız"
@@ -262,26 +289,38 @@ msgstr "Arama sonuçlarının varsayılan görünümü"
262
  msgid "Connect your store<br /> to this WordPress site"
263
  msgstr "Connect your store<br /> to this WordPress site"
264
 
 
 
 
265
  msgid "Connect Ecwid store"
266
  msgstr "Connect Ecwid store"
267
 
 
 
 
268
  msgid "After clicking button you need to login and accept permissions to use our plugin"
269
- msgstr "After clicking button you need to login and accept permissions to use our plugin"
270
 
271
  msgid "Connection error - after clicking button you need to login and accept permissions to use our plugin. Please, try again."
272
- msgstr "Connection error - after clicking button you need to login and accept permissions to use our plugin. Please, try again."
 
 
 
 
 
 
273
 
274
  msgid "Don't have Ecwid account? Create it here"
275
- msgstr "Don't have Ecwid account? Create it here"
276
 
277
- msgid "Questions? Visit <a href=\"http://help.ecwid.com/?source=wporg\">Ecwid support center</a>"
278
- msgstr "Sorun mu yaşıyorsunuz? <a href=\"http://help.ecwid.com/?source=wporg\">Ecwid destek merkezini</a> ziyaret edin"
279
 
280
  msgid "Store ID"
281
  msgstr "Mağaza ID"
282
 
283
  msgid "Disconnect store"
284
- msgstr "Disconnect store"
285
 
286
  msgid "Congratulations!"
287
  msgstr "Tebrikler!"
@@ -296,46 +335,46 @@ msgid "Your Ecwid store is connected<br /> to your WordPress website"
296
  msgstr "Your Ecwid store is connected<br /> to your WordPress website"
297
 
298
  msgid "Open control panel"
299
- msgstr "Open control panel"
300
 
301
  msgid "Plugin is installed successfully!"
302
- msgstr "Plugin is installed successfully!"
303
 
304
- msgid "There are just a few steps left to start selling<br />on your WordPress site"
305
- msgstr "There are just a few steps left to start selling<br />on your WordPress site"
306
 
307
- msgid "There are few little steps left to start selling<br />on your WordPress site"
308
- msgstr "There are few little steps left to start selling<br />on your WordPress site"
309
 
310
  msgid "Register"
311
- msgstr "Register"
312
 
313
- msgid "Create a free Ecwid account to manage your<br />store and inventory. No credit card required"
314
- msgstr "Create a free Ecwid account to manage your<br />store and inventory. No credit card required"
315
 
316
  msgid "Connect"
317
- msgstr "Connect"
318
 
319
- msgid "Add your Ecwid store to your site<br />in two clicks"
320
- msgstr "Add your Ecwid store to your site<br />in two clicks"
321
 
322
- msgid "Connect your Ecwid store to this site<br />in two clicks"
323
- msgstr "Connect your Ecwid store to this site<br />in two clicks"
324
 
325
  msgid "Start selling"
326
- msgstr "Start selling"
327
 
328
  msgid "Your storefront is ready"
329
  msgstr "Your storefront is ready"
330
 
331
  msgid "Create Ecwid store"
332
- msgstr "Create Ecwid store"
333
 
334
  msgid "Connect your store"
335
- msgstr "Connect your store"
336
 
337
  msgid "Free registration, No credit card required"
338
- msgstr "Free registration, No credit card required"
339
 
340
  msgid "Connection error: please click the button again and give permissions for this plugin<br /> to show your Ecwid store on this site."
341
  msgstr "Connection error: please click the button again and give permissions for this plugin<br /> to show your Ecwid store on this site."
@@ -353,16 +392,16 @@ msgid "Don't have an Ecwid account?"
353
  msgstr "Don't have an Ecwid account?"
354
 
355
  msgid "Register at Ecwid for free"
356
- msgstr "Register at Ecwid for free"
357
 
358
  msgid "No credit card required"
359
- msgstr "No credit card required"
360
 
361
  msgid "Get ready to sell online"
362
  msgstr "Get ready to sell online"
363
 
364
  msgid "Sell Everywhere<br>with your Ecwid store"
365
- msgstr "Sell Everywhere<br>with your Ecwid store"
366
 
367
  msgid "Start selling on your WordPress site. Then mirror your shop on your Facebook page, blog and marketplaces like Google Shopping, Yahoo and Shopping.com."
368
  msgstr "Start selling on your WordPress site. Then mirror your shop on your Facebook page, blog and marketplaces like Google Shopping, Yahoo and Shopping.com."
@@ -376,14 +415,14 @@ msgstr "Features"
376
  msgid "Compatible with your theme"
377
  msgstr "Compatible with your theme"
378
 
379
- msgid "Ecwid is compatible with your<br>“Responsive” WordPress theme<br>out of the box."
380
- msgstr "Ecwid is compatible with your<br>“Responsive” WordPress theme<br>out of the box."
381
 
382
  msgid "Free and always up to date"
383
  msgstr "Free and always up to date"
384
 
385
- msgid "Free plan always available with tons of features<br>at no additional cost. Seamless upgrades occur<br>automatically for free."
386
- msgstr "Free plan always available with tons of features<br>at no additional cost. Seamless upgrades occur<br>automatically for free."
387
 
388
  msgid "Responsive design"
389
  msgstr "Responsive design"
@@ -400,8 +439,8 @@ msgstr "Secure checkout with over 40<br />payment options"
400
  msgid "Global Reach"
401
  msgstr "Global Reach"
402
 
403
- msgid "More than 700,000 merchants in 175 countries"
404
- msgstr "More than 700,000 merchants in 175 countries"
405
 
406
  msgid "Start selling <br>on your WordPress <nobr>site for free</nobr>"
407
  msgstr "Start selling <br>on your WordPress <nobr>site for free</nobr>"
@@ -421,8 +460,8 @@ msgstr "Reconnect Ecwid store"
421
  msgid "New features available, reconnect to be in touch with our updates"
422
  msgstr "New features available, reconnect to be in touch with our updates"
423
 
424
- msgid "Add store"
425
- msgstr "Add store"
426
 
427
  msgid "Store settings"
428
  msgstr "Store settings"
@@ -439,8 +478,8 @@ msgstr "Show search"
439
  msgid "Show minicart"
440
  msgstr "Show minicart"
441
 
442
- msgid "Show horizontal categories"
443
- msgstr "Show horizontal categories"
444
 
445
  msgid "Additionally, you can add store controls to your website's toolbar using <a %s>WordPress native widgets</a>"
446
  msgstr "Additionally, you can add store controls to your website's toolbar using <a %s>WordPress native widgets</a>"
@@ -451,12 +490,27 @@ msgstr "Demo store"
451
  msgid "Ecwid plugin settings"
452
  msgstr "Ecwid plugin settings"
453
 
454
- msgid "Save and close"
455
- msgstr "Save and close"
456
-
457
  msgid "Your store will be shown here!"
458
- msgstr "Your store will be shown here!"
459
 
460
  msgid "Demo Store"
461
- msgstr "Demo Store"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
462
 
1
  msgid "Ecwid Shopping Cart"
2
+ msgstr "Ecwid alışveriş sepeti"
3
 
4
  msgid "Ecwid Team"
5
  msgstr "Ecwid Team"
6
 
7
  msgid "Ecwid is a free full-featured shopping cart. It can be easily integrated with any Wordpress blog and takes less than 5 minutes to set up."
8
+ msgstr "Ecwid, ücretsiz ve tam özellikli bir alışveriş sepetidir. Beş dakikadan daha kısa bir sürede kurulabilir ve her hangi bir Wordpress bloğuyla bütünleştirilebilir."
9
 
10
  msgid "Get help"
11
  msgstr "Yardım alın"
35
  msgstr "Ecwid alışveriş sepeti ayarları"
36
 
37
  msgid "Ecwid Store"
38
+ msgstr "Eсwid Mağazası"
39
 
40
  msgid "Setup"
41
  msgstr "Kurulum"
42
 
43
  msgid "Dashboard"
44
+ msgstr "Kontrol paneli"
45
 
46
  msgid "Appearance settings"
47
  msgstr "Görünüm ayarları"
58
  msgid "Hidden category"
59
  msgstr "Gizli kategori"
60
 
61
+ msgid "Recommendations for Your Online Store"
62
+ msgstr "Çevrimiçi Mağazanız için Öneriler"
63
+
64
+ msgid "Do you like Ecwid and want to help it grow? You can add this fancy 'Powered by Ecwid' badge on your site to show your visitors that you're a proud user of Ecwid."
65
+ msgstr "Do you like Ecwid and want to help it grow? You can add this fancy 'Powered by Ecwid' badge on your site to show your visitors that you're a proud user of Ecwid."
66
 
67
  msgid "Ecwid Badge"
68
  msgstr "Ecwid Yaması"
82
  msgid "Ecwid e-commerce widgets"
83
  msgstr "Ecwid e-ticaret widgetleri"
84
 
85
+ msgid "Adds a cart widget for customer to see the products they added to the cart."
86
+ msgstr "Adds a cart widget for customer to see the products they added to the cart."
87
 
88
+ msgid "Shopping Cart"
89
+ msgstr "Shopping Cart"
90
 
91
+ msgid "Adds a compact cart widget for customer to see the products they added to the cart."
92
+ msgstr "Adds a compact cart widget for customer to see the products they added to the cart."
93
 
94
+ msgid "Shopping Cart (Mini)"
95
+ msgstr "Shopping Cart (Mini)"
96
 
97
+ msgid "Displays a simple search box for your customers to find a product in your storex"
98
+ msgstr "Displays a simple search box for your customers to find a product in your storex"
99
 
100
+ msgid "Product Search"
101
+ msgstr "Product Search"
102
 
103
+ msgid "Adds vertical categories block to let the customer navigate your store."
104
+ msgstr "Adds vertical categories block to let the customer navigate your store."
105
 
106
+ msgid "Store Categories"
107
+ msgstr "Store Categories"
108
 
109
+ msgid "Displays a link to the store page in sidebar for customer to quickly access your store from any page on the site."
110
+ msgstr "Displays a link to the store page in sidebar for customer to quickly access your store from any page on the site."
111
+
112
+ msgid "Store Page Link"
113
+ msgstr "Store Page Link"
114
 
115
  msgid "Shop"
116
+ msgstr "Mağaza"
117
 
118
+ msgid "Displays a list of products recently viewed by the customer to easily return to the products they saw in your shop."
119
+ msgstr "Displays a list of products recently viewed by the customer to easily return to the products they saw in your shop."
120
 
121
  msgid "Recently Viewed Products"
122
  msgstr "Recently Viewed Products"
123
 
124
+ msgid "You have not viewed any product yet. Open store."
125
+ msgstr "You have not viewed any product yet. Open store."
126
+
127
+ msgid "Store Link Title"
128
+ msgstr "Store Link Title"
129
+
130
  msgid "Number of products to show"
131
  msgstr "Number of products to show"
132
 
173
  msgstr "WordPress.org sitesinde Ecwid uygulamasını oylayın"
174
 
175
  msgid "Add Store"
176
+ msgstr "Mağaza Ekle"
177
 
178
  msgid "Edit Store"
179
+ msgstr "Mağazayı Düzenle"
180
 
181
  msgid "Edit Appearance"
182
+ msgstr "Görünümü Düzenle"
183
 
184
  msgid "Price"
185
  msgstr "Fiyat"
211
  msgid "Single Sign-On Secret Key is an option that allows your customers access to your WordPress site as well as the Ecwid shopping cart. When customers log in to your site, they will automatically be logged in to your Ecwid store as well. It makes sense to enable this feature if your visitors actually create accounts in your WordPress website."
212
  msgstr "Tek giriş (Single Sign-On) gizli anahtarı müşterilerinizin WordPress sayfanızı Ecwid sayfanızı ziyaret eder gibi görüntülemelerini sağlar. Müşteriler sitenize giriş yaptıklarında otomatik olarak Ecwid mağazanıza da giriş yaparlar. Ziyaretçileriniz WordPress sayfanızda hesap oluşturmaya başladığında bu özelliği kullanabilirsiniz."
213
 
214
+ msgid "In order to enable this feature, opt to use a secret key. You will find this key in your Ecwid control panel, at \"System Settings > Apps > Legacy API Keys > Single Sign-On Secret Key\" page. This feature is available for <a href=\"http://www.ecwid.com/compare-plans.html\" target=\"_blank\">paid users</a> only."
215
+ msgstr "In order to enable this feature, opt to use a secret key. You will find this key in your Ecwid control panel, at \"System Settings > Apps > Legacy API Keys > Single Sign-On Secret Key\" page. This feature is available for <a href=\"http://www.ecwid.com/compare-plans.html\" target=\"_blank\">paid users</a> only."
216
+
217
+ msgid "Chameleon skin <sup>beta</sup>"
218
+ msgstr "Chameleon skin <sup>beta</sup>"
219
+
220
+ msgid "Automatic adjustment of your store design to your Wordpress theme. Whatever Wordpress theme you use, Ecwid will detect predominant colors and font and use them in your product catalog."
221
+ msgstr "Automatic adjustment of your store design to your Wordpress theme. Whatever Wordpress theme you use, Ecwid will detect predominant colors and font and use them in your product catalog."
222
+
223
+ msgid "Please note this functionality is in beta. So if you run into difficulties or find problems with Chameleon, please <a %s>let us know</a>."
224
+ msgstr "Please note this functionality is in beta. So if you run into difficulties or find problems with Chameleon, please <a %s>let us know</a>."
225
+
226
+ msgid "Enable the new category menu"
227
+ msgstr "Enable the new category menu"
228
+
229
+ msgid "The new category menu looks better and is more mobile-friendly. If you haven't yet added category menu to your store page, you can do that in the <a %s>store page editor</a> (enable the \"Show categories\" option)"
230
+ msgstr "The new category menu looks better and is more mobile-friendly. If you haven't yet added category menu to your store page, you can do that in the <a %s>store page editor</a> (enable the \"Show categories\" option)"
231
 
232
  msgid "Save changes"
233
  msgstr "Değişiklikleri kaydet"
241
  msgid "Or you can add search box to your website's toolbar using <a href=\"%s\">WordPress native widgets</a>"
242
  msgstr "Ya da arama kutusunu <a href=\"%s\">WordPress yerleşik widgetlerını</a> kullanarak ekleyebilirsiniz"
243
 
244
+ msgid "Display categories above products"
245
+ msgstr "Display categories above products"
246
 
247
  msgid "Or you can add vertical categories to your website's toolbar using <a href=\"%s\">WordPress native widgets</a>"
248
  msgstr "Ya da dikey kategorileri sitenin araç çubuğuna <a href=\"%s\">WordPress yerleşik widgetlerını</a> kullanarak ekleyebilirsiniz"
249
 
250
+ msgid "Enable minicart attached to categories"
251
+ msgstr "Enable minicart attached to categories"
252
 
253
  msgid "You should disable this option, if you added minicart to your website's&nbsp;sidebar"
254
  msgstr "Web sitenize küçük alışveriş sepeti eklediyseniz bu ayarı devre dışı bırakınız"
289
  msgid "Connect your store<br /> to this WordPress site"
290
  msgstr "Connect your store<br /> to this WordPress site"
291
 
292
+ msgid "Enter your Store ID"
293
+ msgstr "Enter your Store ID"
294
+
295
  msgid "Connect Ecwid store"
296
  msgstr "Connect Ecwid store"
297
 
298
+ msgid "Save and connect"
299
+ msgstr "Save and connect"
300
+
301
  msgid "After clicking button you need to login and accept permissions to use our plugin"
302
+ msgstr "Düğmeye tıkladıktan sonra eklentiyi kullanmak için giriş yapıp izinleri onaylamalısınız"
303
 
304
  msgid "Connection error - after clicking button you need to login and accept permissions to use our plugin. Please, try again."
305
+ msgstr "Bağlantı hatası - düğmeye tıkladıktan sonra eklentiyi kullanmak için giriş yapıp izinleri onaylamalısınız. Lütfen tekrar deneyin."
306
+
307
+ msgid "Where to find your Store ID:"
308
+ msgstr "Where to find your Store ID:"
309
+
310
+ msgid "Store ID is a unique identifier of your Ecwid account. You can find it in your Ecwid control panel: open the <a %s>Dashboard page</a> and find the \"<b>Store ID: NNNNNNN</b>\" text, where <b>NNNNNNN</b> is your Store&nbsp;ID."
311
+ msgstr "Store ID is a unique identifier of your Ecwid account. You can find it in your Ecwid control panel: open the <a %s>Dashboard page</a> and find the \"<b>Store ID: NNNNNNN</b>\" text, where <b>NNNNNNN</b> is your Store&nbsp;ID."
312
 
313
  msgid "Don't have Ecwid account? Create it here"
314
+ msgstr "Ecwid hesabınız yok mu? Burada oluşturun"
315
 
316
+ msgid "Questions? Visit <a %s>Ecwid support center</a>"
317
+ msgstr "Questions? Visit <a %s>Ecwid support center</a>"
318
 
319
  msgid "Store ID"
320
  msgstr "Mağaza ID"
321
 
322
  msgid "Disconnect store"
323
+ msgstr "Mağaza bağlantısını kes"
324
 
325
  msgid "Congratulations!"
326
  msgstr "Tebrikler!"
335
  msgstr "Your Ecwid store is connected<br /> to your WordPress website"
336
 
337
  msgid "Open control panel"
338
+ msgstr "Kontrol panelini "
339
 
340
  msgid "Plugin is installed successfully!"
341
+ msgstr "Eklenti başarıyla yüklendi!"
342
 
343
+ msgid "There are just a few steps left to start selling<br /> on your WordPress site"
344
+ msgstr "There are just a few steps left to start selling<br /> on your WordPress site"
345
 
346
+ msgid "There are few little steps left to start selling<br /> on your WordPress site"
347
+ msgstr "There are few little steps left to start selling<br /> on your WordPress site"
348
 
349
  msgid "Register"
350
+ msgstr "Kayıt Ol"
351
 
352
+ msgid "Create a free Ecwid account to manage your store and inventory.<br /> No credit card required"
353
+ msgstr "Create a free Ecwid account to manage your store and inventory.<br /> No credit card required"
354
 
355
  msgid "Connect"
356
+ msgstr "Bağlan"
357
 
358
+ msgid "Add your Ecwid store to your site <nobr>in two clicks</nobr>"
359
+ msgstr "Add your Ecwid store to your site <nobr>in two clicks</nobr>"
360
 
361
+ msgid "Connect your Ecwid store to this site <nobr>in two clicks</nobr>"
362
+ msgstr "Connect your Ecwid store to this site <nobr>in two clicks</nobr>"
363
 
364
  msgid "Start selling"
365
+ msgstr "Satmaya başlayın"
366
 
367
  msgid "Your storefront is ready"
368
  msgstr "Your storefront is ready"
369
 
370
  msgid "Create Ecwid store"
371
+ msgstr "Ecwid Mağazası oluştur"
372
 
373
  msgid "Connect your store"
374
+ msgstr "Mağazanızı bağlayın"
375
 
376
  msgid "Free registration, No credit card required"
377
+ msgstr "Ücretsiz kayıt, kredi kartı gerekli değil"
378
 
379
  msgid "Connection error: please click the button again and give permissions for this plugin<br /> to show your Ecwid store on this site."
380
  msgstr "Connection error: please click the button again and give permissions for this plugin<br /> to show your Ecwid store on this site."
392
  msgstr "Don't have an Ecwid account?"
393
 
394
  msgid "Register at Ecwid for free"
395
+ msgstr "Ecwid'e ücretsiz kayıt olun"
396
 
397
  msgid "No credit card required"
398
+ msgstr "Kredi kartı gerekmez"
399
 
400
  msgid "Get ready to sell online"
401
  msgstr "Get ready to sell online"
402
 
403
  msgid "Sell Everywhere<br>with your Ecwid store"
404
+ msgstr "Ecwid mağazası<br>ile Her Yerde Satın"
405
 
406
  msgid "Start selling on your WordPress site. Then mirror your shop on your Facebook page, blog and marketplaces like Google Shopping, Yahoo and Shopping.com."
407
  msgstr "Start selling on your WordPress site. Then mirror your shop on your Facebook page, blog and marketplaces like Google Shopping, Yahoo and Shopping.com."
415
  msgid "Compatible with your theme"
416
  msgstr "Compatible with your theme"
417
 
418
+ msgid "Ecwid is compatible with your<br>“%s” WordPress theme<br>out of the box."
419
+ msgstr "Ecwid is compatible with your<br>“%s” WordPress theme<br>out of the box."
420
 
421
  msgid "Free and always up to date"
422
  msgstr "Free and always up to date"
423
 
424
+ msgid "Free plan always available with tons of features<br>at no additional cost. Updates are seamless, automatic<br>and free of charge."
425
+ msgstr "Free plan always available with tons of features<br>at no additional cost. Updates are seamless, automatic<br>and free of charge."
426
 
427
  msgid "Responsive design"
428
  msgstr "Responsive design"
439
  msgid "Global Reach"
440
  msgstr "Global Reach"
441
 
442
+ msgid "More than 800,000 merchants in 175 countries"
443
+ msgstr "More than 800,000 merchants in 175 countries"
444
 
445
  msgid "Start selling <br>on your WordPress <nobr>site for free</nobr>"
446
  msgstr "Start selling <br>on your WordPress <nobr>site for free</nobr>"
460
  msgid "New features available, reconnect to be in touch with our updates"
461
  msgstr "New features available, reconnect to be in touch with our updates"
462
 
463
+ msgid "Questions? Visit <a href=\"http://help.ecwid.com/?source=wporg\">Ecwid support center</a>"
464
+ msgstr "Sorun mu yaşıyorsunuz? <a href=\"http://help.ecwid.com/?source=wporg\">Ecwid destek merkezini</a> ziyaret edin"
465
 
466
  msgid "Store settings"
467
  msgstr "Store settings"
478
  msgid "Show minicart"
479
  msgstr "Show minicart"
480
 
481
+ msgid "Show categories"
482
+ msgstr "Show categories"
483
 
484
  msgid "Additionally, you can add store controls to your website's toolbar using <a %s>WordPress native widgets</a>"
485
  msgstr "Additionally, you can add store controls to your website's toolbar using <a %s>WordPress native widgets</a>"
490
  msgid "Ecwid plugin settings"
491
  msgstr "Ecwid plugin settings"
492
 
 
 
 
493
  msgid "Your store will be shown here!"
494
+ msgstr "Mağazanız burada görünecek!"
495
 
496
  msgid "Demo Store"
497
+ msgstr "Deneme mağazası"
498
+
499
+ msgid "Sell On The Go with Ecwid iOS Application"
500
+ msgstr "Ecwid iOS uygulamasıyla Hareket Halinde Satın"
501
+
502
+ msgid "Ecwid iOS app allows you to manage your online store, sell your products on the go, and accept payments with your phone. Just download the Ecwid app, connect it to your Ecwid shop and have your sales at your fingertips!"
503
+ msgstr "Ecwid iOS app allows you to manage your online store, sell your products on the go, and accept payments with your phone. Just download the Ecwid app, connect it to your Ecwid shop and have your sales at your fingertips!"
504
+
505
+ msgid "Get Your Products Found on Google using XML Sitemap"
506
+ msgstr "Get Your Products Found on Google using XML Sitemap"
507
+
508
+ msgid "Free Google XML Sitemaps plugin creates a sitemap that includes your store product links. This makes your product pages more visible to search engines and appear in the search results."
509
+ msgstr "Free Google XML Sitemaps plugin creates a sitemap that includes your store product links. This makes your product pages more visible to search engines and appear in the search results."
510
+
511
+ msgid "Add Product Slider to Your Store"
512
+ msgstr "Mağazanıza Ürün Kaydırıcı Ekleyin"
513
+
514
+ msgid "Add a fancy product slider to your site using a free WP Widgets Avalanche plugin which works perfectly with Ecwid"
515
+ msgstr "Ecwid ile mükemmel bir şekilde çalışan WP Widgets Avalanche eklentisini indirerek sitenize süslü bir ürün kaydırıcısı ekleyin"
516
 
lib/phpseclib/AES.php ADDED
@@ -0,0 +1,197 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Pure-PHP implementation of AES.
5
+ *
6
+ * Uses mcrypt, if available/possible, and an internal implementation, otherwise.
7
+ *
8
+ * PHP versions 4 and 5
9
+ *
10
+ * NOTE: Since AES.php is (for compatibility and phpseclib-historical reasons) virtually
11
+ * just a wrapper to Rijndael.php you may consider using Rijndael.php instead of
12
+ * to save one include_once().
13
+ *
14
+ * If {@link Crypt_AES::setKeyLength() setKeyLength()} isn't called, it'll be calculated from
15
+ * {@link Crypt_AES::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 Crypt_AES::setKey() setKey()}
17
+ * is called, again, at which point, it'll be recalculated.
18
+ *
19
+ * Since Crypt_AES extends Crypt_Rijndael, some functions are available to be called that, in the context of AES, don't
20
+ * make a whole lot of sense. {@link Crypt_AES::setBlockLength() setBlockLength()}, for instance. Calling that function,
21
+ * however possible, won't do anything (AES has a fixed block length whereas Rijndael has a variable one).
22
+ *
23
+ * Here's a short example of how to use this library:
24
+ * <code>
25
+ * <?php
26
+ * include 'Crypt/AES.php';
27
+ *
28
+ * $aes = new Crypt_AES();
29
+ *
30
+ * $aes->setKey('abcdefghijklmnop');
31
+ *
32
+ * $size = 10 * 1024;
33
+ * $plaintext = '';
34
+ * for ($i = 0; $i < $size; $i++) {
35
+ * $plaintext.= 'a';
36
+ * }
37
+ *
38
+ * echo $aes->decrypt($aes->encrypt($plaintext));
39
+ * ?>
40
+ * </code>
41
+ *
42
+ * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
43
+ * of this software and associated documentation files (the "Software"), to deal
44
+ * in the Software without restriction, including without limitation the rights
45
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
46
+ * copies of the Software, and to permit persons to whom the Software is
47
+ * furnished to do so, subject to the following conditions:
48
+ *
49
+ * The above copyright notice and this permission notice shall be included in
50
+ * all copies or substantial portions of the Software.
51
+ *
52
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
53
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
54
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
55
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
56
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
57
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
58
+ * THE SOFTWARE.
59
+ *
60
+ * @category Crypt
61
+ * @package Crypt_AES
62
+ * @author Jim Wigginton <terrafrost@php.net>
63
+ * @copyright 2008 Jim Wigginton
64
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
65
+ * @link http://phpseclib.sourceforge.net
66
+ */
67
+
68
+ /**
69
+ * Include Crypt_Rijndael
70
+ */
71
+ if (!class_exists('Crypt_Rijndael')) {
72
+ include_once 'Rijndael.php';
73
+ }
74
+
75
+ /**#@+
76
+ * @access public
77
+ * @see Crypt_AES::encrypt()
78
+ * @see Crypt_AES::decrypt()
79
+ */
80
+ /**
81
+ * Encrypt / decrypt using the Counter mode.
82
+ *
83
+ * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
84
+ *
85
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
86
+ */
87
+ define('CRYPT_AES_MODE_CTR', CRYPT_MODE_CTR);
88
+ /**
89
+ * Encrypt / decrypt using the Electronic Code Book mode.
90
+ *
91
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
92
+ */
93
+ define('CRYPT_AES_MODE_ECB', CRYPT_MODE_ECB);
94
+ /**
95
+ * Encrypt / decrypt using the Code Book Chaining mode.
96
+ *
97
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
98
+ */
99
+ define('CRYPT_AES_MODE_CBC', CRYPT_MODE_CBC);
100
+ /**
101
+ * Encrypt / decrypt using the Cipher Feedback mode.
102
+ *
103
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
104
+ */
105
+ define('CRYPT_AES_MODE_CFB', CRYPT_MODE_CFB);
106
+ /**
107
+ * Encrypt / decrypt using the Cipher Feedback mode.
108
+ *
109
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
110
+ */
111
+ define('CRYPT_AES_MODE_OFB', CRYPT_MODE_OFB);
112
+ /**#@-*/
113
+
114
+ /**
115
+ * Pure-PHP implementation of AES.
116
+ *
117
+ * @package Crypt_AES
118
+ * @author Jim Wigginton <terrafrost@php.net>
119
+ * @access public
120
+ */
121
+ class Crypt_AES extends Crypt_Rijndael
122
+ {
123
+ /**
124
+ * The namespace used by the cipher for its constants.
125
+ *
126
+ * @see Crypt_Base::const_namespace
127
+ * @var string
128
+ * @access private
129
+ */
130
+ var $const_namespace = 'AES';
131
+
132
+ /**
133
+ * Dummy function
134
+ *
135
+ * Since Crypt_AES extends Crypt_Rijndael, this function is, technically, available, but it doesn't do anything.
136
+ *
137
+ * @see Crypt_Rijndael::setBlockLength()
138
+ * @access public
139
+ * @param int $length
140
+ */
141
+ function setBlockLength($length)
142
+ {
143
+ return;
144
+ }
145
+
146
+ /**
147
+ * Sets the key length
148
+ *
149
+ * Valid key lengths are 128, 192, and 256. If the length is less than 128, it will be rounded up to
150
+ * 128. If the length is greater than 128 and invalid, it will be rounded down to the closest valid amount.
151
+ *
152
+ * @see Crypt_Rijndael:setKeyLength()
153
+ * @access public
154
+ * @param int $length
155
+ */
156
+ function setKeyLength($length)
157
+ {
158
+ switch ($length) {
159
+ case 160:
160
+ $length = 192;
161
+ break;
162
+ case 224:
163
+ $length = 256;
164
+ }
165
+ parent::setKeyLength($length);
166
+ }
167
+
168
+ /**
169
+ * Sets the key.
170
+ *
171
+ * Rijndael supports five different key lengths, AES only supports three.
172
+ *
173
+ * @see Crypt_Rijndael:setKey()
174
+ * @see setKeyLength()
175
+ * @access public
176
+ * @param string $key
177
+ */
178
+ function setKey($key)
179
+ {
180
+ parent::setKey($key);
181
+
182
+ if (!$this->explicit_key_length) {
183
+ $length = strlen($key);
184
+ switch (true) {
185
+ case $length <= 16:
186
+ $this->key_length = 16;
187
+ break;
188
+ case $length <= 24:
189
+ $this->key_length = 24;
190
+ break;
191
+ default:
192
+ $this->key_length = 32;
193
+ }
194
+ $this->_setEngine();
195
+ }
196
+ }
197
+ }
lib/phpseclib/Base.php ADDED
@@ -0,0 +1,2593 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Base Class for all Crypt_* cipher classes
5
+ *
6
+ * PHP versions 4 and 5
7
+ *
8
+ * Internally for phpseclib developers:
9
+ * If you plan to add a new cipher class, please note following rules:
10
+ *
11
+ * - The new Crypt_* cipher class should extend Crypt_Base
12
+ *
13
+ * - Following methods are then required to be overridden/overloaded:
14
+ *
15
+ * - _encryptBlock()
16
+ *
17
+ * - _decryptBlock()
18
+ *
19
+ * - _setupKey()
20
+ *
21
+ * - All other methods are optional to be overridden/overloaded
22
+ *
23
+ * - Look at the source code of the current ciphers how they extend Crypt_Base
24
+ * and take one of them as a start up for the new cipher class.
25
+ *
26
+ * - Please read all the other comments/notes/hints here also for each class var/method
27
+ *
28
+ * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
29
+ * of this software and associated documentation files (the "Software"), to deal
30
+ * in the Software without restriction, including without limitation the rights
31
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
32
+ * copies of the Software, and to permit persons to whom the Software is
33
+ * furnished to do so, subject to the following conditions:
34
+ *
35
+ * The above copyright notice and this permission notice shall be included in
36
+ * all copies or substantial portions of the Software.
37
+ *
38
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
39
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
40
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
41
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
42
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
43
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
44
+ * THE SOFTWARE.
45
+ *
46
+ * @category Crypt
47
+ * @package Crypt_Base
48
+ * @author Jim Wigginton <terrafrost@php.net>
49
+ * @author Hans-Juergen Petrich <petrich@tronic-media.com>
50
+ * @copyright 2007 Jim Wigginton
51
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
52
+ * @link http://phpseclib.sourceforge.net
53
+ */
54
+
55
+ /**#@+
56
+ * @access public
57
+ * @see Crypt_Base::encrypt()
58
+ * @see Crypt_Base::decrypt()
59
+ */
60
+ /**
61
+ * Encrypt / decrypt using the Counter mode.
62
+ *
63
+ * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
64
+ *
65
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
66
+ */
67
+ define('CRYPT_MODE_CTR', -1);
68
+ /**
69
+ * Encrypt / decrypt using the Electronic Code Book mode.
70
+ *
71
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
72
+ */
73
+ define('CRYPT_MODE_ECB', 1);
74
+ /**
75
+ * Encrypt / decrypt using the Code Book Chaining mode.
76
+ *
77
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
78
+ */
79
+ define('CRYPT_MODE_CBC', 2);
80
+ /**
81
+ * Encrypt / decrypt using the Cipher Feedback mode.
82
+ *
83
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
84
+ */
85
+ define('CRYPT_MODE_CFB', 3);
86
+ /**
87
+ * Encrypt / decrypt using the Output Feedback mode.
88
+ *
89
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
90
+ */
91
+ define('CRYPT_MODE_OFB', 4);
92
+ /**
93
+ * Encrypt / decrypt using streaming mode.
94
+ */
95
+ define('CRYPT_MODE_STREAM', 5);
96
+ /**#@-*/
97
+
98
+ /**#@+
99
+ * @access private
100
+ * @see Crypt_Base::Crypt_Base()
101
+ * @internal These constants are for internal use only
102
+ */
103
+ /**
104
+ * Base value for the internal implementation $engine switch
105
+ */
106
+ define('CRYPT_ENGINE_INTERNAL', 1);
107
+ /**
108
+ * Base value for the mcrypt implementation $engine switch
109
+ */
110
+ define('CRYPT_ENGINE_MCRYPT', 2);
111
+ /**
112
+ * Base value for the OpenSSL implementation $engine switch
113
+ */
114
+ define('CRYPT_ENGINE_OPENSSL', 3);
115
+ /**#@-*/
116
+
117
+ /**
118
+ * Base Class for all Crypt_* cipher classes
119
+ *
120
+ * @package Crypt_Base
121
+ * @author Jim Wigginton <terrafrost@php.net>
122
+ * @author Hans-Juergen Petrich <petrich@tronic-media.com>
123
+ * @access public
124
+ */
125
+ class Crypt_Base
126
+ {
127
+ /**
128
+ * The Encryption Mode
129
+ *
130
+ * @see Crypt_Base::Crypt_Base()
131
+ * @var int
132
+ * @access private
133
+ */
134
+ var $mode;
135
+
136
+ /**
137
+ * The Block Length of the block cipher
138
+ *
139
+ * @var int
140
+ * @access private
141
+ */
142
+ var $block_size = 16;
143
+
144
+ /**
145
+ * The Key
146
+ *
147
+ * @see Crypt_Base::setKey()
148
+ * @var string
149
+ * @access private
150
+ */
151
+ var $key = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
152
+
153
+ /**
154
+ * The Initialization Vector
155
+ *
156
+ * @see Crypt_Base::setIV()
157
+ * @var string
158
+ * @access private
159
+ */
160
+ var $iv;
161
+
162
+ /**
163
+ * A "sliding" Initialization Vector
164
+ *
165
+ * @see Crypt_Base::enableContinuousBuffer()
166
+ * @see Crypt_Base::_clearBuffers()
167
+ * @var string
168
+ * @access private
169
+ */
170
+ var $encryptIV;
171
+
172
+ /**
173
+ * A "sliding" Initialization Vector
174
+ *
175
+ * @see Crypt_Base::enableContinuousBuffer()
176
+ * @see Crypt_Base::_clearBuffers()
177
+ * @var string
178
+ * @access private
179
+ */
180
+ var $decryptIV;
181
+
182
+ /**
183
+ * Continuous Buffer status
184
+ *
185
+ * @see Crypt_Base::enableContinuousBuffer()
186
+ * @var bool
187
+ * @access private
188
+ */
189
+ var $continuousBuffer = false;
190
+
191
+ /**
192
+ * Encryption buffer for CTR, OFB and CFB modes
193
+ *
194
+ * @see Crypt_Base::encrypt()
195
+ * @see Crypt_Base::_clearBuffers()
196
+ * @var array
197
+ * @access private
198
+ */
199
+ var $enbuffer;
200
+
201
+ /**
202
+ * Decryption buffer for CTR, OFB and CFB modes
203
+ *
204
+ * @see Crypt_Base::decrypt()
205
+ * @see Crypt_Base::_clearBuffers()
206
+ * @var array
207
+ * @access private
208
+ */
209
+ var $debuffer;
210
+
211
+ /**
212
+ * mcrypt resource for encryption
213
+ *
214
+ * The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
215
+ * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
216
+ *
217
+ * @see Crypt_Base::encrypt()
218
+ * @var resource
219
+ * @access private
220
+ */
221
+ var $enmcrypt;
222
+
223
+ /**
224
+ * mcrypt resource for decryption
225
+ *
226
+ * The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
227
+ * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
228
+ *
229
+ * @see Crypt_Base::decrypt()
230
+ * @var resource
231
+ * @access private
232
+ */
233
+ var $demcrypt;
234
+
235
+ /**
236
+ * Does the enmcrypt resource need to be (re)initialized?
237
+ *
238
+ * @see Crypt_Twofish::setKey()
239
+ * @see Crypt_Twofish::setIV()
240
+ * @var bool
241
+ * @access private
242
+ */
243
+ var $enchanged = true;
244
+
245
+ /**
246
+ * Does the demcrypt resource need to be (re)initialized?
247
+ *
248
+ * @see Crypt_Twofish::setKey()
249
+ * @see Crypt_Twofish::setIV()
250
+ * @var bool
251
+ * @access private
252
+ */
253
+ var $dechanged = true;
254
+
255
+ /**
256
+ * mcrypt resource for CFB mode
257
+ *
258
+ * mcrypt's CFB mode, in (and only in) buffered context,
259
+ * is broken, so phpseclib implements the CFB mode by it self,
260
+ * even when the mcrypt php extension is available.
261
+ *
262
+ * In order to do the CFB-mode work (fast) phpseclib
263
+ * use a separate ECB-mode mcrypt resource.
264
+ *
265
+ * @link http://phpseclib.sourceforge.net/cfb-demo.phps
266
+ * @see Crypt_Base::encrypt()
267
+ * @see Crypt_Base::decrypt()
268
+ * @see Crypt_Base::_setupMcrypt()
269
+ * @var resource
270
+ * @access private
271
+ */
272
+ var $ecb;
273
+
274
+ /**
275
+ * Optimizing value while CFB-encrypting
276
+ *
277
+ * Only relevant if $continuousBuffer enabled
278
+ * and $engine == CRYPT_ENGINE_MCRYPT
279
+ *
280
+ * It's faster to re-init $enmcrypt if
281
+ * $buffer bytes > $cfb_init_len than
282
+ * using the $ecb resource furthermore.
283
+ *
284
+ * This value depends of the chosen cipher
285
+ * and the time it would be needed for it's
286
+ * initialization [by mcrypt_generic_init()]
287
+ * which, typically, depends on the complexity
288
+ * on its internaly Key-expanding algorithm.
289
+ *
290
+ * @see Crypt_Base::encrypt()
291
+ * @var int
292
+ * @access private
293
+ */
294
+ var $cfb_init_len = 600;
295
+
296
+ /**
297
+ * Does internal cipher state need to be (re)initialized?
298
+ *
299
+ * @see setKey()
300
+ * @see setIV()
301
+ * @see disableContinuousBuffer()
302
+ * @var bool
303
+ * @access private
304
+ */
305
+ var $changed = true;
306
+
307
+ /**
308
+ * Padding status
309
+ *
310
+ * @see Crypt_Base::enablePadding()
311
+ * @var bool
312
+ * @access private
313
+ */
314
+ var $padding = true;
315
+
316
+ /**
317
+ * Is the mode one that is paddable?
318
+ *
319
+ * @see Crypt_Base::Crypt_Base()
320
+ * @var bool
321
+ * @access private
322
+ */
323
+ var $paddable = false;
324
+
325
+ /**
326
+ * Holds which crypt engine internaly should be use,
327
+ * which will be determined automatically on __construct()
328
+ *
329
+ * Currently available $engines are:
330
+ * - CRYPT_ENGINE_OPENSSL (very fast, php-extension: openssl, extension_loaded('openssl') required)
331
+ * - CRYPT_ENGINE_MCRYPT (fast, php-extension: mcrypt, extension_loaded('mcrypt') required)
332
+ * - CRYPT_ENGINE_INTERNAL (slower, pure php-engine, no php-extension required)
333
+ *
334
+ * @see Crypt_Base::_setEngine()
335
+ * @see Crypt_Base::encrypt()
336
+ * @see Crypt_Base::decrypt()
337
+ * @var int
338
+ * @access private
339
+ */
340
+ var $engine;
341
+
342
+ /**
343
+ * Holds the preferred crypt engine
344
+ *
345
+ * @see Crypt_Base::_setEngine()
346
+ * @see Crypt_Base::setPreferredEngine()
347
+ * @var int
348
+ * @access private
349
+ */
350
+ var $preferredEngine;
351
+
352
+ /**
353
+ * The mcrypt specific name of the cipher
354
+ *
355
+ * Only used if $engine == CRYPT_ENGINE_MCRYPT
356
+ *
357
+ * @link http://www.php.net/mcrypt_module_open
358
+ * @link http://www.php.net/mcrypt_list_algorithms
359
+ * @see Crypt_Base::_setupMcrypt()
360
+ * @var string
361
+ * @access private
362
+ */
363
+ var $cipher_name_mcrypt;
364
+
365
+ /**
366
+ * The openssl specific name of the cipher
367
+ *
368
+ * Only used if $engine == CRYPT_ENGINE_OPENSSL
369
+ *
370
+ * @link http://www.php.net/openssl-get-cipher-methods
371
+ * @var string
372
+ * @access private
373
+ */
374
+ var $cipher_name_openssl;
375
+
376
+ /**
377
+ * The openssl specific name of the cipher in ECB mode
378
+ *
379
+ * If OpenSSL does not support the mode we're trying to use (CTR)
380
+ * it can still be emulated with ECB mode.
381
+ *
382
+ * @link http://www.php.net/openssl-get-cipher-methods
383
+ * @var string
384
+ * @access private
385
+ */
386
+ var $cipher_name_openssl_ecb;
387
+
388
+ /**
389
+ * The default salt used by setPassword()
390
+ *
391
+ * @see Crypt_Base::setPassword()
392
+ * @var string
393
+ * @access private
394
+ */
395
+ var $password_default_salt = 'phpseclib/salt';
396
+
397
+ /**
398
+ * The namespace used by the cipher for its constants.
399
+ *
400
+ * ie: AES.php is using CRYPT_AES_MODE_* for its constants
401
+ * so $const_namespace is AES
402
+ *
403
+ * DES.php is using CRYPT_DES_MODE_* for its constants
404
+ * so $const_namespace is DES... and so on
405
+ *
406
+ * All CRYPT_<$const_namespace>_MODE_* are aliases of
407
+ * the generic CRYPT_MODE_* constants, so both could be used
408
+ * for each cipher.
409
+ *
410
+ * Example:
411
+ * $aes = new Crypt_AES(CRYPT_AES_MODE_CFB); // $aes will operate in cfb mode
412
+ * $aes = new Crypt_AES(CRYPT_MODE_CFB); // identical
413
+ *
414
+ * @see Crypt_Base::Crypt_Base()
415
+ * @var string
416
+ * @access private
417
+ */
418
+ var $const_namespace;
419
+
420
+ /**
421
+ * The name of the performance-optimized callback function
422
+ *
423
+ * Used by encrypt() / decrypt()
424
+ * only if $engine == CRYPT_ENGINE_INTERNAL
425
+ *
426
+ * @see Crypt_Base::encrypt()
427
+ * @see Crypt_Base::decrypt()
428
+ * @see Crypt_Base::_setupInlineCrypt()
429
+ * @see Crypt_Base::$use_inline_crypt
430
+ * @var Callback
431
+ * @access private
432
+ */
433
+ var $inline_crypt;
434
+
435
+ /**
436
+ * Holds whether performance-optimized $inline_crypt() can/should be used.
437
+ *
438
+ * @see Crypt_Base::encrypt()
439
+ * @see Crypt_Base::decrypt()
440
+ * @see Crypt_Base::inline_crypt
441
+ * @var mixed
442
+ * @access private
443
+ */
444
+ var $use_inline_crypt;
445
+
446
+ /**
447
+ * If OpenSSL can be used in ECB but not in CTR we can emulate CTR
448
+ *
449
+ * @see Crypt_Base::_openssl_ctr_process()
450
+ * @var bool
451
+ * @access private
452
+ */
453
+ var $openssl_emulate_ctr = false;
454
+
455
+ /**
456
+ * Determines what options are passed to openssl_encrypt/decrypt
457
+ *
458
+ * @see Crypt_Base::isValidEngine()
459
+ * @var mixed
460
+ * @access private
461
+ */
462
+ var $openssl_options;
463
+
464
+ /**
465
+ * Has the key length explicitly been set or should it be derived from the key, itself?
466
+ *
467
+ * @see self::setKeyLength()
468
+ * @var bool
469
+ * @access private
470
+ */
471
+ var $explicit_key_length = false;
472
+
473
+ /**
474
+ * Don't truncate / null pad key
475
+ *
476
+ * @see self::_clearBuffers()
477
+ * @var bool
478
+ * @access private
479
+ */
480
+ var $skip_key_adjustment = false;
481
+
482
+ /**
483
+ * Default Constructor.
484
+ *
485
+ * Determines whether or not the mcrypt extension should be used.
486
+ *
487
+ * $mode could be:
488
+ *
489
+ * - CRYPT_MODE_ECB
490
+ *
491
+ * - CRYPT_MODE_CBC
492
+ *
493
+ * - CRYPT_MODE_CTR
494
+ *
495
+ * - CRYPT_MODE_CFB
496
+ *
497
+ * - CRYPT_MODE_OFB
498
+ *
499
+ * (or the alias constants of the chosen cipher, for example for AES: CRYPT_AES_MODE_ECB or CRYPT_AES_MODE_CBC ...)
500
+ *
501
+ * If not explicitly set, CRYPT_MODE_CBC will be used.
502
+ *
503
+ * @param int $mode
504
+ * @access public
505
+ */
506
+ function Crypt_Base($mode = CRYPT_MODE_CBC)
507
+ {
508
+ // $mode dependent settings
509
+ switch ($mode) {
510
+ case CRYPT_MODE_ECB:
511
+ $this->paddable = true;
512
+ $this->mode = CRYPT_MODE_ECB;
513
+ break;
514
+ case CRYPT_MODE_CTR:
515
+ case CRYPT_MODE_CFB:
516
+ case CRYPT_MODE_OFB:
517
+ case CRYPT_MODE_STREAM:
518
+ $this->mode = $mode;
519
+ break;
520
+ case CRYPT_MODE_CBC:
521
+ default:
522
+ $this->paddable = true;
523
+ $this->mode = CRYPT_MODE_CBC;
524
+ }
525
+
526
+ $this->_setEngine();
527
+
528
+ // Determining whether inline crypting can be used by the cipher
529
+ if ($this->use_inline_crypt !== false && function_exists('create_function')) {
530
+ $this->use_inline_crypt = true;
531
+ }
532
+ }
533
+
534
+ /**
535
+ * Sets the initialization vector. (optional)
536
+ *
537
+ * SetIV is not required when CRYPT_MODE_ECB (or ie for AES: CRYPT_AES_MODE_ECB) is being used. If not explicitly set, it'll be assumed
538
+ * to be all zero's.
539
+ *
540
+ * @access public
541
+ * @param string $iv
542
+ * @internal Can be overwritten by a sub class, but does not have to be
543
+ */
544
+ function setIV($iv)
545
+ {
546
+ if ($this->mode == CRYPT_MODE_ECB) {
547
+ return;
548
+ }
549
+
550
+ $this->iv = $iv;
551
+ $this->changed = true;
552
+ }
553
+
554
+ /**
555
+ * Sets the key length.
556
+ *
557
+ * Keys with explicitly set lengths need to be treated accordingly
558
+ *
559
+ * @access public
560
+ * @param int $length
561
+ */
562
+ function setKeyLength($length)
563
+ {
564
+ $this->explicit_key_length = true;
565
+ $this->changed = true;
566
+ $this->_setEngine();
567
+ }
568
+
569
+ /**
570
+ * Returns the current key length in bits
571
+ *
572
+ * @access public
573
+ * @return int
574
+ */
575
+ function getKeyLength()
576
+ {
577
+ return $this->key_length << 3;
578
+ }
579
+
580
+ /**
581
+ * Returns the current block length in bits
582
+ *
583
+ * @access public
584
+ * @return int
585
+ */
586
+ function getBlockLength()
587
+ {
588
+ return $this->block_size << 3;
589
+ }
590
+
591
+ /**
592
+ * Sets the key.
593
+ *
594
+ * The min/max length(s) of the key depends on the cipher which is used.
595
+ * If the key not fits the length(s) of the cipher it will paded with null bytes
596
+ * up to the closest valid key length. If the key is more than max length,
597
+ * we trim the excess bits.
598
+ *
599
+ * If the key is not explicitly set, it'll be assumed to be all null bytes.
600
+ *
601
+ * @access public
602
+ * @param string $key
603
+ * @internal Could, but not must, extend by the child Crypt_* class
604
+ */
605
+ function setKey($key)
606
+ {
607
+ if (!$this->explicit_key_length) {
608
+ $this->setKeyLength(strlen($key) << 3);
609
+ $this->explicit_key_length = false;
610
+ }
611
+
612
+ $this->key = $key;
613
+ $this->changed = true;
614
+ $this->_setEngine();
615
+ }
616
+
617
+ /**
618
+ * Sets the password.
619
+ *
620
+ * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows:
621
+ * {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2} or pbkdf1:
622
+ * $hash, $salt, $count, $dkLen
623
+ *
624
+ * Where $hash (default = sha1) currently supports the following hashes: see: Crypt/Hash.php
625
+ *
626
+ * @see Crypt/Hash.php
627
+ * @param string $password
628
+ * @param string $method
629
+ * @return bool
630
+ * @access public
631
+ * @internal Could, but not must, extend by the child Crypt_* class
632
+ */
633
+ function setPassword($password, $method = 'pbkdf2')
634
+ {
635
+ $key = '';
636
+
637
+ switch ($method) {
638
+ default: // 'pbkdf2' or 'pbkdf1'
639
+ $func_args = func_get_args();
640
+
641
+ // Hash function
642
+ $hash = isset($func_args[2]) ? $func_args[2] : 'sha1';
643
+
644
+ // WPA and WPA2 use the SSID as the salt
645
+ $salt = isset($func_args[3]) ? $func_args[3] : $this->password_default_salt;
646
+
647
+ // RFC2898#section-4.2 uses 1,000 iterations by default
648
+ // WPA and WPA2 use 4,096.
649
+ $count = isset($func_args[4]) ? $func_args[4] : 1000;
650
+
651
+ // Keylength
652
+ if (isset($func_args[5])) {
653
+ $dkLen = $func_args[5];
654
+ } else {
655
+ $dkLen = $method == 'pbkdf1' ? 2 * $this->key_length : $this->key_length;
656
+ }
657
+
658
+ switch (true) {
659
+ case $method == 'pbkdf1':
660
+ if (!class_exists('Crypt_Hash')) {
661
+ include_once 'Crypt/Hash.php';
662
+ }
663
+ $hashObj = new Crypt_Hash();
664
+ $hashObj->setHash($hash);
665
+ if ($dkLen > $hashObj->getLength()) {
666
+ user_error('Derived key too long');
667
+ return false;
668
+ }
669
+ $t = $password . $salt;
670
+ for ($i = 0; $i < $count; ++$i) {
671
+ $t = $hashObj->hash($t);
672
+ }
673
+ $key = substr($t, 0, $dkLen);
674
+
675
+ $this->setKey(substr($key, 0, $dkLen >> 1));
676
+ $this->setIV(substr($key, $dkLen >> 1));
677
+
678
+ return true;
679
+ // Determining if php[>=5.5.0]'s hash_pbkdf2() function avail- and useable
680
+ case !function_exists('hash_pbkdf2'):
681
+ case !function_exists('hash_algos'):
682
+ case !in_array($hash, hash_algos()):
683
+ if (!class_exists('Crypt_Hash')) {
684
+ include_once 'Crypt/Hash.php';
685
+ }
686
+ $i = 1;
687
+ while (strlen($key) < $dkLen) {
688
+ $hmac = new Crypt_Hash();
689
+ $hmac->setHash($hash);
690
+ $hmac->setKey($password);
691
+ $f = $u = $hmac->hash($salt . pack('N', $i++));
692
+ for ($j = 2; $j <= $count; ++$j) {
693
+ $u = $hmac->hash($u);
694
+ $f^= $u;
695
+ }
696
+ $key.= $f;
697
+ }
698
+ $key = substr($key, 0, $dkLen);
699
+ break;
700
+ default:
701
+ $key = hash_pbkdf2($hash, $password, $salt, $count, $dkLen, true);
702
+ }
703
+ }
704
+
705
+ $this->setKey($key);
706
+
707
+ return true;
708
+ }
709
+
710
+ /**
711
+ * Encrypts a message.
712
+ *
713
+ * $plaintext will be padded with additional bytes such that it's length is a multiple of the block size. Other cipher
714
+ * implementations may or may not pad in the same manner. Other common approaches to padding and the reasons why it's
715
+ * necessary are discussed in the following
716
+ * URL:
717
+ *
718
+ * {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html}
719
+ *
720
+ * An alternative to padding is to, separately, send the length of the file. This is what SSH, in fact, does.
721
+ * strlen($plaintext) will still need to be a multiple of the block size, however, arbitrary values can be added to make it that
722
+ * length.
723
+ *
724
+ * @see Crypt_Base::decrypt()
725
+ * @access public
726
+ * @param string $plaintext
727
+ * @return string $ciphertext
728
+ * @internal Could, but not must, extend by the child Crypt_* class
729
+ */
730
+ function encrypt($plaintext)
731
+ {
732
+ if ($this->paddable) {
733
+ $plaintext = $this->_pad($plaintext);
734
+ }
735
+
736
+ if ($this->engine === CRYPT_ENGINE_OPENSSL) {
737
+ if ($this->changed) {
738
+ $this->_clearBuffers();
739
+ $this->changed = false;
740
+ }
741
+ switch ($this->mode) {
742
+ case CRYPT_MODE_STREAM:
743
+ return openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options);
744
+ case CRYPT_MODE_ECB:
745
+ $result = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options);
746
+ return !defined('OPENSSL_RAW_DATA') ? substr($result, 0, -$this->block_size) : $result;
747
+ case CRYPT_MODE_CBC:
748
+ $result = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $this->encryptIV);
749
+ if ($this->continuousBuffer) {
750
+ $this->encryptIV = substr($result, -$this->block_size);
751
+ }
752
+ return !defined('OPENSSL_RAW_DATA') ? substr($result, 0, -$this->block_size) : $result;
753
+ case CRYPT_MODE_CTR:
754
+ return $this->_openssl_ctr_process($plaintext, $this->encryptIV, $this->enbuffer);
755
+ case CRYPT_MODE_CFB:
756
+ // cfb loosely routines inspired by openssl's:
757
+ // {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1}
758
+ $ciphertext = '';
759
+ if ($this->continuousBuffer) {
760
+ $iv = &$this->encryptIV;
761
+ $pos = &$this->enbuffer['pos'];
762
+ } else {
763
+ $iv = $this->encryptIV;
764
+ $pos = 0;
765
+ }
766
+ $len = strlen($plaintext);
767
+ $i = 0;
768
+ if ($pos) {
769
+ $orig_pos = $pos;
770
+ $max = $this->block_size - $pos;
771
+ if ($len >= $max) {
772
+ $i = $max;
773
+ $len-= $max;
774
+ $pos = 0;
775
+ } else {
776
+ $i = $len;
777
+ $pos+= $len;
778
+ $len = 0;
779
+ }
780
+ // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
781
+ $ciphertext = substr($iv, $orig_pos) ^ $plaintext;
782
+ $iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
783
+ $plaintext = substr($plaintext, $i);
784
+ }
785
+
786
+ $overflow = $len % $this->block_size;
787
+
788
+ if ($overflow) {
789
+ $ciphertext.= openssl_encrypt(substr($plaintext, 0, -$overflow) . str_repeat("\0", $this->block_size), $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv);
790
+ $iv = $this->_string_pop($ciphertext, $this->block_size);
791
+
792
+ $size = $len - $overflow;
793
+ $block = $iv ^ substr($plaintext, -$overflow);
794
+ $iv = substr_replace($iv, $block, 0, $overflow);
795
+ $ciphertext.= $block;
796
+ $pos = $overflow;
797
+ } elseif ($len) {
798
+ $ciphertext = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv);
799
+ $iv = substr($ciphertext, -$this->block_size);
800
+ }
801
+
802
+ return $ciphertext;
803
+ case CRYPT_MODE_OFB:
804
+ return $this->_openssl_ofb_process($plaintext, $this->encryptIV, $this->enbuffer);
805
+ }
806
+ }
807
+
808
+ if ($this->engine === CRYPT_ENGINE_MCRYPT) {
809
+ if ($this->changed) {
810
+ $this->_setupMcrypt();
811
+ $this->changed = false;
812
+ }
813
+ if ($this->enchanged) {
814
+ mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
815
+ $this->enchanged = false;
816
+ }
817
+
818
+ // re: {@link http://phpseclib.sourceforge.net/cfb-demo.phps}
819
+ // using mcrypt's default handing of CFB the above would output two different things. using phpseclib's
820
+ // rewritten CFB implementation the above outputs the same thing twice.
821
+ if ($this->mode == CRYPT_MODE_CFB && $this->continuousBuffer) {
822
+ $block_size = $this->block_size;
823
+ $iv = &$this->encryptIV;
824
+ $pos = &$this->enbuffer['pos'];
825
+ $len = strlen($plaintext);
826
+ $ciphertext = '';
827
+ $i = 0;
828
+ if ($pos) {
829
+ $orig_pos = $pos;
830
+ $max = $block_size - $pos;
831
+ if ($len >= $max) {
832
+ $i = $max;
833
+ $len-= $max;
834
+ $pos = 0;
835
+ } else {
836
+ $i = $len;
837
+ $pos+= $len;
838
+ $len = 0;
839
+ }
840
+ $ciphertext = substr($iv, $orig_pos) ^ $plaintext;
841
+ $iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
842
+ $this->enbuffer['enmcrypt_init'] = true;
843
+ }
844
+ if ($len >= $block_size) {
845
+ if ($this->enbuffer['enmcrypt_init'] === false || $len > $this->cfb_init_len) {
846
+ if ($this->enbuffer['enmcrypt_init'] === true) {
847
+ mcrypt_generic_init($this->enmcrypt, $this->key, $iv);
848
+ $this->enbuffer['enmcrypt_init'] = false;
849
+ }
850
+ $ciphertext.= mcrypt_generic($this->enmcrypt, substr($plaintext, $i, $len - $len % $block_size));
851
+ $iv = substr($ciphertext, -$block_size);
852
+ $len%= $block_size;
853
+ } else {
854
+ while ($len >= $block_size) {
855
+ $iv = mcrypt_generic($this->ecb, $iv) ^ substr($plaintext, $i, $block_size);
856
+ $ciphertext.= $iv;
857
+ $len-= $block_size;
858
+ $i+= $block_size;
859
+ }
860
+ }
861
+ }
862
+
863
+ if ($len) {
864
+ $iv = mcrypt_generic($this->ecb, $iv);
865
+ $block = $iv ^ substr($plaintext, -$len);
866
+ $iv = substr_replace($iv, $block, 0, $len);
867
+ $ciphertext.= $block;
868
+ $pos = $len;
869
+ }
870
+
871
+ return $ciphertext;
872
+ }
873
+
874
+ $ciphertext = mcrypt_generic($this->enmcrypt, $plaintext);
875
+
876
+ if (!$this->continuousBuffer) {
877
+ mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
878
+ }
879
+
880
+ return $ciphertext;
881
+ }
882
+
883
+ if ($this->changed) {
884
+ $this->_setup();
885
+ $this->changed = false;
886
+ }
887
+ if ($this->use_inline_crypt) {
888
+ $inline = $this->inline_crypt;
889
+ return $inline('encrypt', $this, $plaintext);
890
+ }
891
+
892
+ $buffer = &$this->enbuffer;
893
+ $block_size = $this->block_size;
894
+ $ciphertext = '';
895
+ switch ($this->mode) {
896
+ case CRYPT_MODE_ECB:
897
+ for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
898
+ $ciphertext.= $this->_encryptBlock(substr($plaintext, $i, $block_size));
899
+ }
900
+ break;
901
+ case CRYPT_MODE_CBC:
902
+ $xor = $this->encryptIV;
903
+ for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
904
+ $block = substr($plaintext, $i, $block_size);
905
+ $block = $this->_encryptBlock($block ^ $xor);
906
+ $xor = $block;
907
+ $ciphertext.= $block;
908
+ }
909
+ if ($this->continuousBuffer) {
910
+ $this->encryptIV = $xor;
911
+ }
912
+ break;
913
+ case CRYPT_MODE_CTR:
914
+ $xor = $this->encryptIV;
915
+ if (strlen($buffer['ciphertext'])) {
916
+ for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
917
+ $block = substr($plaintext, $i, $block_size);
918
+ if (strlen($block) > strlen($buffer['ciphertext'])) {
919
+ $buffer['ciphertext'].= $this->_encryptBlock($xor);
920
+ }
921
+ $this->_increment_str($xor);
922
+ $key = $this->_string_shift($buffer['ciphertext'], $block_size);
923
+ $ciphertext.= $block ^ $key;
924
+ }
925
+ } else {
926
+ for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
927
+ $block = substr($plaintext, $i, $block_size);
928
+ $key = $this->_encryptBlock($xor);
929
+ $this->_increment_str($xor);
930
+ $ciphertext.= $block ^ $key;
931
+ }
932
+ }
933
+ if ($this->continuousBuffer) {
934
+ $this->encryptIV = $xor;
935
+ if ($start = strlen($plaintext) % $block_size) {
936
+ $buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext'];
937
+ }
938
+ }
939
+ break;
940
+ case CRYPT_MODE_CFB:
941
+ // cfb loosely routines inspired by openssl's:
942
+ // {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1}
943
+ if ($this->continuousBuffer) {
944
+ $iv = &$this->encryptIV;
945
+ $pos = &$buffer['pos'];
946
+ } else {
947
+ $iv = $this->encryptIV;
948
+ $pos = 0;
949
+ }
950
+ $len = strlen($plaintext);
951
+ $i = 0;
952
+ if ($pos) {
953
+ $orig_pos = $pos;
954
+ $max = $block_size - $pos;
955
+ if ($len >= $max) {
956
+ $i = $max;
957
+ $len-= $max;
958
+ $pos = 0;
959
+ } else {
960
+ $i = $len;
961
+ $pos+= $len;
962
+ $len = 0;
963
+ }
964
+ // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
965
+ $ciphertext = substr($iv, $orig_pos) ^ $plaintext;
966
+ $iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
967
+ }
968
+ while ($len >= $block_size) {
969
+ $iv = $this->_encryptBlock($iv) ^ substr($plaintext, $i, $block_size);
970
+ $ciphertext.= $iv;
971
+ $len-= $block_size;
972
+ $i+= $block_size;
973
+ }
974
+ if ($len) {
975
+ $iv = $this->_encryptBlock($iv);
976
+ $block = $iv ^ substr($plaintext, $i);
977
+ $iv = substr_replace($iv, $block, 0, $len);
978
+ $ciphertext.= $block;
979
+ $pos = $len;
980
+ }
981
+ break;
982
+ case CRYPT_MODE_OFB:
983
+ $xor = $this->encryptIV;
984
+ if (strlen($buffer['xor'])) {
985
+ for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
986
+ $block = substr($plaintext, $i, $block_size);
987
+ if (strlen($block) > strlen($buffer['xor'])) {
988
+ $xor = $this->_encryptBlock($xor);
989
+ $buffer['xor'].= $xor;
990
+ }
991
+ $key = $this->_string_shift($buffer['xor'], $block_size);
992
+ $ciphertext.= $block ^ $key;
993
+ }
994
+ } else {
995
+ for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
996
+ $xor = $this->_encryptBlock($xor);
997
+ $ciphertext.= substr($plaintext, $i, $block_size) ^ $xor;
998
+ }
999
+ $key = $xor;
1000
+ }
1001
+ if ($this->continuousBuffer) {
1002
+ $this->encryptIV = $xor;
1003
+ if ($start = strlen($plaintext) % $block_size) {
1004
+ $buffer['xor'] = substr($key, $start) . $buffer['xor'];
1005
+ }
1006
+ }
1007
+ break;
1008
+ case CRYPT_MODE_STREAM:
1009
+ $ciphertext = $this->_encryptBlock($plaintext);
1010
+ break;
1011
+ }
1012
+
1013
+ return $ciphertext;
1014
+ }
1015
+
1016
+ /**
1017
+ * Decrypts a message.
1018
+ *
1019
+ * If strlen($ciphertext) is not a multiple of the block size, null bytes will be added to the end of the string until
1020
+ * it is.
1021
+ *
1022
+ * @see Crypt_Base::encrypt()
1023
+ * @access public
1024
+ * @param string $ciphertext
1025
+ * @return string $plaintext
1026
+ * @internal Could, but not must, extend by the child Crypt_* class
1027
+ */
1028
+ function decrypt($ciphertext)
1029
+ {
1030
+ if ($this->paddable) {
1031
+ // we pad with chr(0) since that's what mcrypt_generic does. to quote from {@link http://www.php.net/function.mcrypt-generic}:
1032
+ // "The data is padded with "\0" to make sure the length of the data is n * blocksize."
1033
+ $ciphertext = str_pad($ciphertext, strlen($ciphertext) + ($this->block_size - strlen($ciphertext) % $this->block_size) % $this->block_size, chr(0));
1034
+ }
1035
+
1036
+ if ($this->engine === CRYPT_ENGINE_OPENSSL) {
1037
+ if ($this->changed) {
1038
+ $this->_clearBuffers();
1039
+ $this->changed = false;
1040
+ }
1041
+ switch ($this->mode) {
1042
+ case CRYPT_MODE_STREAM:
1043
+ $plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options);
1044
+ break;
1045
+ case CRYPT_MODE_ECB:
1046
+ if (!defined('OPENSSL_RAW_DATA')) {
1047
+ $ciphertext.= openssl_encrypt('', $this->cipher_name_openssl_ecb, $this->key, true);
1048
+ }
1049
+ $plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options);
1050
+ break;
1051
+ case CRYPT_MODE_CBC:
1052
+ if (!defined('OPENSSL_RAW_DATA')) {
1053
+ $padding = str_repeat(chr($this->block_size), $this->block_size) ^ substr($ciphertext, -$this->block_size);
1054
+ $ciphertext.= substr(openssl_encrypt($padding, $this->cipher_name_openssl_ecb, $this->key, true), 0, $this->block_size);
1055
+ }
1056
+ $plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $this->decryptIV);
1057
+ if ($this->continuousBuffer) {
1058
+ $this->decryptIV = substr($ciphertext, -$this->block_size);
1059
+ }
1060
+ break;
1061
+ case CRYPT_MODE_CTR:
1062
+ $plaintext = $this->_openssl_ctr_process($ciphertext, $this->decryptIV, $this->debuffer);
1063
+ break;
1064
+ case CRYPT_MODE_CFB:
1065
+ // cfb loosely routines inspired by openssl's:
1066
+ // {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1}
1067
+ $plaintext = '';
1068
+ if ($this->continuousBuffer) {
1069
+ $iv = &$this->decryptIV;
1070
+ $pos = &$this->buffer['pos'];
1071
+ } else {
1072
+ $iv = $this->decryptIV;
1073
+ $pos = 0;
1074
+ }
1075
+ $len = strlen($ciphertext);
1076
+ $i = 0;
1077
+ if ($pos) {
1078
+ $orig_pos = $pos;
1079
+ $max = $this->block_size - $pos;
1080
+ if ($len >= $max) {
1081
+ $i = $max;
1082
+ $len-= $max;
1083
+ $pos = 0;
1084
+ } else {
1085
+ $i = $len;
1086
+ $pos+= $len;
1087
+ $len = 0;
1088
+ }
1089
+ // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $this->blocksize
1090
+ $plaintext = substr($iv, $orig_pos) ^ $ciphertext;
1091
+ $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
1092
+ $ciphertext = substr($ciphertext, $i);
1093
+ }
1094
+ $overflow = $len % $this->block_size;
1095
+ if ($overflow) {
1096
+ $plaintext.= openssl_decrypt(substr($ciphertext, 0, -$overflow), $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv);
1097
+ if ($len - $overflow) {
1098
+ $iv = substr($ciphertext, -$overflow - $this->block_size, -$overflow);
1099
+ }
1100
+ $iv = openssl_encrypt(str_repeat("\0", $this->block_size), $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv);
1101
+ $plaintext.= $iv ^ substr($ciphertext, -$overflow);
1102
+ $iv = substr_replace($iv, substr($ciphertext, -$overflow), 0, $overflow);
1103
+ $pos = $overflow;
1104
+ } elseif ($len) {
1105
+ $plaintext.= openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv);
1106
+ $iv = substr($ciphertext, -$this->block_size);
1107
+ }
1108
+ break;
1109
+ case CRYPT_MODE_OFB:
1110
+ $plaintext = $this->_openssl_ofb_process($ciphertext, $this->decryptIV, $this->debuffer);
1111
+ }
1112
+
1113
+ return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
1114
+ }
1115
+
1116
+ if ($this->engine === CRYPT_ENGINE_MCRYPT) {
1117
+ $block_size = $this->block_size;
1118
+ if ($this->changed) {
1119
+ $this->_setupMcrypt();
1120
+ $this->changed = false;
1121
+ }
1122
+ if ($this->dechanged) {
1123
+ mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
1124
+ $this->dechanged = false;
1125
+ }
1126
+
1127
+ if ($this->mode == CRYPT_MODE_CFB && $this->continuousBuffer) {
1128
+ $iv = &$this->decryptIV;
1129
+ $pos = &$this->debuffer['pos'];
1130
+ $len = strlen($ciphertext);
1131
+ $plaintext = '';
1132
+ $i = 0;
1133
+ if ($pos) {
1134
+ $orig_pos = $pos;
1135
+ $max = $block_size - $pos;
1136
+ if ($len >= $max) {
1137
+ $i = $max;
1138
+ $len-= $max;
1139
+ $pos = 0;
1140
+ } else {
1141
+ $i = $len;
1142
+ $pos+= $len;
1143
+ $len = 0;
1144
+ }
1145
+ // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
1146
+ $plaintext = substr($iv, $orig_pos) ^ $ciphertext;
1147
+ $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
1148
+ }
1149
+ if ($len >= $block_size) {
1150
+ $cb = substr($ciphertext, $i, $len - $len % $block_size);
1151
+ $plaintext.= mcrypt_generic($this->ecb, $iv . $cb) ^ $cb;
1152
+ $iv = substr($cb, -$block_size);
1153
+ $len%= $block_size;
1154
+ }
1155
+ if ($len) {
1156
+ $iv = mcrypt_generic($this->ecb, $iv);
1157
+ $plaintext.= $iv ^ substr($ciphertext, -$len);
1158
+ $iv = substr_replace($iv, substr($ciphertext, -$len), 0, $len);
1159
+ $pos = $len;
1160
+ }
1161
+
1162
+ return $plaintext;
1163
+ }
1164
+
1165
+ $plaintext = mdecrypt_generic($this->demcrypt, $ciphertext);
1166
+
1167
+ if (!$this->continuousBuffer) {
1168
+ mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
1169
+ }
1170
+
1171
+ return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
1172
+ }
1173
+
1174
+ if ($this->changed) {
1175
+ $this->_setup();
1176
+ $this->changed = false;
1177
+ }
1178
+ if ($this->use_inline_crypt) {
1179
+ $inline = $this->inline_crypt;
1180
+ return $inline('decrypt', $this, $ciphertext);
1181
+ }
1182
+
1183
+ $block_size = $this->block_size;
1184
+
1185
+ $buffer = &$this->debuffer;
1186
+ $plaintext = '';
1187
+ switch ($this->mode) {
1188
+ case CRYPT_MODE_ECB:
1189
+ for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
1190
+ $plaintext.= $this->_decryptBlock(substr($ciphertext, $i, $block_size));
1191
+ }
1192
+ break;
1193
+ case CRYPT_MODE_CBC:
1194
+ $xor = $this->decryptIV;
1195
+ for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
1196
+ $block = substr($ciphertext, $i, $block_size);
1197
+ $plaintext.= $this->_decryptBlock($block) ^ $xor;
1198
+ $xor = $block;
1199
+ }
1200
+ if ($this->continuousBuffer) {
1201
+ $this->decryptIV = $xor;
1202
+ }
1203
+ break;
1204
+ case CRYPT_MODE_CTR:
1205
+ $xor = $this->decryptIV;
1206
+ if (strlen($buffer['ciphertext'])) {
1207
+ for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
1208
+ $block = substr($ciphertext, $i, $block_size);
1209
+ if (strlen($block) > strlen($buffer['ciphertext'])) {
1210
+ $buffer['ciphertext'].= $this->_encryptBlock($xor);
1211
+ $this->_increment_str($xor);
1212
+ }
1213
+ $key = $this->_string_shift($buffer['ciphertext'], $block_size);
1214
+ $plaintext.= $block ^ $key;
1215
+ }
1216
+ } else {
1217
+ for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
1218
+ $block = substr($ciphertext, $i, $block_size);
1219
+ $key = $this->_encryptBlock($xor);
1220
+ $this->_increment_str($xor);
1221
+ $plaintext.= $block ^ $key;
1222
+ }
1223
+ }
1224
+ if ($this->continuousBuffer) {
1225
+ $this->decryptIV = $xor;
1226
+ if ($start = strlen($ciphertext) % $block_size) {
1227
+ $buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext'];
1228
+ }
1229
+ }
1230
+ break;
1231
+ case CRYPT_MODE_CFB:
1232
+ if ($this->continuousBuffer) {
1233
+ $iv = &$this->decryptIV;
1234
+ $pos = &$buffer['pos'];
1235
+ } else {
1236
+ $iv = $this->decryptIV;
1237
+ $pos = 0;
1238
+ }
1239
+ $len = strlen($ciphertext);
1240
+ $i = 0;
1241
+ if ($pos) {
1242
+ $orig_pos = $pos;
1243
+ $max = $block_size - $pos;
1244
+ if ($len >= $max) {
1245
+ $i = $max;
1246
+ $len-= $max;
1247
+ $pos = 0;
1248
+ } else {
1249
+ $i = $len;
1250
+ $pos+= $len;
1251
+ $len = 0;
1252
+ }
1253
+ // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
1254
+ $plaintext = substr($iv, $orig_pos) ^ $ciphertext;
1255
+ $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
1256
+ }
1257
+ while ($len >= $block_size) {
1258
+ $iv = $this->_encryptBlock($iv);
1259
+ $cb = substr($ciphertext, $i, $block_size);
1260
+ $plaintext.= $iv ^ $cb;
1261
+ $iv = $cb;
1262
+ $len-= $block_size;
1263
+ $i+= $block_size;
1264
+ }
1265
+ if ($len) {
1266
+ $iv = $this->_encryptBlock($iv);
1267
+ $plaintext.= $iv ^ substr($ciphertext, $i);
1268
+ $iv = substr_replace($iv, substr($ciphertext, $i), 0, $len);
1269
+ $pos = $len;
1270
+ }
1271
+ break;
1272
+ case CRYPT_MODE_OFB:
1273
+ $xor = $this->decryptIV;
1274
+ if (strlen($buffer['xor'])) {
1275
+ for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
1276
+ $block = substr($ciphertext, $i, $block_size);
1277
+ if (strlen($block) > strlen($buffer['xor'])) {
1278
+ $xor = $this->_encryptBlock($xor);
1279
+ $buffer['xor'].= $xor;
1280
+ }
1281
+ $key = $this->_string_shift($buffer['xor'], $block_size);
1282
+ $plaintext.= $block ^ $key;
1283
+ }
1284
+ } else {
1285
+ for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
1286
+ $xor = $this->_encryptBlock($xor);
1287
+ $plaintext.= substr($ciphertext, $i, $block_size) ^ $xor;
1288
+ }
1289
+ $key = $xor;
1290
+ }
1291
+ if ($this->continuousBuffer) {
1292
+ $this->decryptIV = $xor;
1293
+ if ($start = strlen($ciphertext) % $block_size) {
1294
+ $buffer['xor'] = substr($key, $start) . $buffer['xor'];
1295
+ }
1296
+ }
1297
+ break;
1298
+ case CRYPT_MODE_STREAM:
1299
+ $plaintext = $this->_decryptBlock($ciphertext);
1300
+ break;
1301
+ }
1302
+ return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
1303
+ }
1304
+
1305
+ /**
1306
+ * OpenSSL CTR Processor
1307
+ *
1308
+ * PHP's OpenSSL bindings do not operate in continuous mode so we'll wrap around it. Since the keystream
1309
+ * for CTR is the same for both encrypting and decrypting this function is re-used by both Crypt_Base::encrypt()
1310
+ * and Crypt_Base::decrypt(). Also, OpenSSL doesn't implement CTR for all of it's symmetric ciphers so this
1311
+ * function will emulate CTR with ECB when necesary.
1312
+ *
1313
+ * @see Crypt_Base::encrypt()
1314
+ * @see Crypt_Base::decrypt()
1315
+ * @param string $plaintext
1316
+ * @param string $encryptIV
1317
+ * @param array $buffer
1318
+ * @return string
1319
+ * @access private
1320
+ */
1321
+ function _openssl_ctr_process($plaintext, &$encryptIV, &$buffer)
1322
+ {
1323
+ $ciphertext = '';
1324
+
1325
+ $block_size = $this->block_size;
1326
+ $key = $this->key;
1327
+
1328
+ if ($this->openssl_emulate_ctr) {
1329
+ $xor = $encryptIV;
1330
+ if (strlen($buffer['ciphertext'])) {
1331
+ for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
1332
+ $block = substr($plaintext, $i, $block_size);
1333
+ if (strlen($block) > strlen($buffer['ciphertext'])) {
1334
+ $result = openssl_encrypt($xor, $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
1335
+ $result = !defined('OPENSSL_RAW_DATA') ? substr($result, 0, -$this->block_size) : $result;
1336
+ $buffer['ciphertext'].= $result;
1337
+ }
1338
+ $this->_increment_str($xor);
1339
+ $otp = $this->_string_shift($buffer['ciphertext'], $block_size);
1340
+ $ciphertext.= $block ^ $otp;
1341
+ }
1342
+ } else {
1343
+ for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
1344
+ $block = substr($plaintext, $i, $block_size);
1345
+ $otp = openssl_encrypt($xor, $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
1346
+ $otp = !defined('OPENSSL_RAW_DATA') ? substr($otp, 0, -$this->block_size) : $otp;
1347
+ $this->_increment_str($xor);
1348
+ $ciphertext.= $block ^ $otp;
1349
+ }
1350
+ }
1351
+ if ($this->continuousBuffer) {
1352
+ $encryptIV = $xor;
1353
+ if ($start = strlen($plaintext) % $block_size) {
1354
+ $buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext'];
1355
+ }
1356
+ }
1357
+
1358
+ return $ciphertext;
1359
+ }
1360
+
1361
+ if (strlen($buffer['ciphertext'])) {
1362
+ $ciphertext = $plaintext ^ $this->_string_shift($buffer['ciphertext'], strlen($plaintext));
1363
+ $plaintext = substr($plaintext, strlen($ciphertext));
1364
+
1365
+ if (!strlen($plaintext)) {
1366
+ return $ciphertext;
1367
+ }
1368
+ }
1369
+
1370
+ $overflow = strlen($plaintext) % $block_size;
1371
+ if ($overflow) {
1372
+ $plaintext2 = $this->_string_pop($plaintext, $overflow); // ie. trim $plaintext to a multiple of $block_size and put rest of $plaintext in $plaintext2
1373
+ $encrypted = openssl_encrypt($plaintext . str_repeat("\0", $block_size), $this->cipher_name_openssl, $key, $this->openssl_options, $encryptIV);
1374
+ $temp = $this->_string_pop($encrypted, $block_size);
1375
+ $ciphertext.= $encrypted . ($plaintext2 ^ $temp);
1376
+ if ($this->continuousBuffer) {
1377
+ $buffer['ciphertext'] = substr($temp, $overflow);
1378
+ $encryptIV = $temp;
1379
+ }
1380
+ } elseif (!strlen($buffer['ciphertext'])) {
1381
+ $ciphertext.= openssl_encrypt($plaintext . str_repeat("\0", $block_size), $this->cipher_name_openssl, $key, $this->openssl_options, $encryptIV);
1382
+ $temp = $this->_string_pop($ciphertext, $block_size);
1383
+ if ($this->continuousBuffer) {
1384
+ $encryptIV = $temp;
1385
+ }
1386
+ }
1387
+ if ($this->continuousBuffer) {
1388
+ if (!defined('OPENSSL_RAW_DATA')) {
1389
+ $encryptIV.= openssl_encrypt('', $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
1390
+ }
1391
+ $encryptIV = openssl_decrypt($encryptIV, $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
1392
+ if ($overflow) {
1393
+ $this->_increment_str($encryptIV);
1394
+ }
1395
+ }
1396
+
1397
+ return $ciphertext;
1398
+ }
1399
+
1400
+ /**
1401
+ * OpenSSL OFB Processor
1402
+ *
1403
+ * PHP's OpenSSL bindings do not operate in continuous mode so we'll wrap around it. Since the keystream
1404
+ * for OFB is the same for both encrypting and decrypting this function is re-used by both Crypt_Base::encrypt()
1405
+ * and Crypt_Base::decrypt().
1406
+ *
1407
+ * @see Crypt_Base::encrypt()
1408
+ * @see Crypt_Base::decrypt()
1409
+ * @param string $plaintext
1410
+ * @param string $encryptIV
1411
+ * @param array $buffer
1412
+ * @return string
1413
+ * @access private
1414
+ */
1415
+ function _openssl_ofb_process($plaintext, &$encryptIV, &$buffer)
1416
+ {
1417
+ if (strlen($buffer['xor'])) {
1418
+ $ciphertext = $plaintext ^ $buffer['xor'];
1419
+ $buffer['xor'] = substr($buffer['xor'], strlen($ciphertext));
1420
+ $plaintext = substr($plaintext, strlen($ciphertext));
1421
+ } else {
1422
+ $ciphertext = '';
1423
+ }
1424
+
1425
+ $block_size = $this->block_size;
1426
+
1427
+ $len = strlen($plaintext);
1428
+ $key = $this->key;
1429
+ $overflow = $len % $block_size;
1430
+
1431
+ if (strlen($plaintext)) {
1432
+ if ($overflow) {
1433
+ $ciphertext.= openssl_encrypt(substr($plaintext, 0, -$overflow) . str_repeat("\0", $block_size), $this->cipher_name_openssl, $key, $this->openssl_options, $encryptIV);
1434
+ $xor = $this->_string_pop($ciphertext, $block_size);
1435
+ if ($this->continuousBuffer) {
1436
+ $encryptIV = $xor;
1437
+ }
1438
+ $ciphertext.= $this->_string_shift($xor, $overflow) ^ substr($plaintext, -$overflow);
1439
+ if ($this->continuousBuffer) {
1440
+ $buffer['xor'] = $xor;
1441
+ }
1442
+ } else {
1443
+ $ciphertext = openssl_encrypt($plaintext, $this->cipher_name_openssl, $key, $this->openssl_options, $encryptIV);
1444
+ if ($this->continuousBuffer) {
1445
+ $encryptIV = substr($ciphertext, -$block_size) ^ substr($plaintext, -$block_size);
1446
+ }
1447
+ }
1448
+ }
1449
+
1450
+ return $ciphertext;
1451
+ }
1452
+
1453
+ /**
1454
+ * phpseclib <-> OpenSSL Mode Mapper
1455
+ *
1456
+ * May need to be overwritten by classes extending this one in some cases
1457
+ *
1458
+ * @return int
1459
+ * @access private
1460
+ */
1461
+ function _openssl_translate_mode()
1462
+ {
1463
+ switch ($this->mode) {
1464
+ case CRYPT_MODE_ECB:
1465
+ return 'ecb';
1466
+ case CRYPT_MODE_CBC:
1467
+ return 'cbc';
1468
+ case CRYPT_MODE_CTR:
1469
+ return 'ctr';
1470
+ case CRYPT_MODE_CFB:
1471
+ return 'cfb';
1472
+ case CRYPT_MODE_OFB:
1473
+ return 'ofb';
1474
+ }
1475
+ }
1476
+
1477
+ /**
1478
+ * Pad "packets".
1479
+ *
1480
+ * Block ciphers working by encrypting between their specified [$this->]block_size at a time
1481
+ * If you ever need to encrypt or decrypt something that isn't of the proper length, it becomes necessary to
1482
+ * pad the input so that it is of the proper length.
1483
+ *
1484
+ * Padding is enabled by default. Sometimes, however, it is undesirable to pad strings. Such is the case in SSH,
1485
+ * where "packets" are padded with random bytes before being encrypted. Unpad these packets and you risk stripping
1486
+ * away characters that shouldn't be stripped away. (SSH knows how many bytes are added because the length is
1487
+ * transmitted separately)
1488
+ *
1489
+ * @see Crypt_Base::disablePadding()
1490
+ * @access public
1491
+ */
1492
+ function enablePadding()
1493
+ {
1494
+ $this->padding = true;
1495
+ }
1496
+
1497
+ /**
1498
+ * Do not pad packets.
1499
+ *
1500
+ * @see Crypt_Base::enablePadding()
1501
+ * @access public
1502
+ */
1503
+ function disablePadding()
1504
+ {
1505
+ $this->padding = false;
1506
+ }
1507
+
1508
+ /**
1509
+ * Treat consecutive "packets" as if they are a continuous buffer.
1510
+ *
1511
+ * Say you have a 32-byte plaintext $plaintext. Using the default behavior, the two following code snippets
1512
+ * will yield different outputs:
1513
+ *
1514
+ * <code>
1515
+ * echo $rijndael->encrypt(substr($plaintext, 0, 16));
1516
+ * echo $rijndael->encrypt(substr($plaintext, 16, 16));
1517
+ * </code>
1518
+ * <code>
1519
+ * echo $rijndael->encrypt($plaintext);
1520
+ * </code>
1521
+ *
1522
+ * The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates
1523
+ * another, as demonstrated with the following:
1524
+ *
1525
+ * <code>
1526
+ * $rijndael->encrypt(substr($plaintext, 0, 16));
1527
+ * echo $rijndael->decrypt($rijndael->encrypt(substr($plaintext, 16, 16)));
1528
+ * </code>
1529
+ * <code>
1530
+ * echo $rijndael->decrypt($rijndael->encrypt(substr($plaintext, 16, 16)));
1531
+ * </code>
1532
+ *
1533
+ * With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different
1534
+ * outputs. The reason is due to the fact that the initialization vector's change after every encryption /
1535
+ * decryption round when the continuous buffer is enabled. When it's disabled, they remain constant.
1536
+ *
1537
+ * Put another way, when the continuous buffer is enabled, the state of the Crypt_*() object changes after each
1538
+ * encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that
1539
+ * continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them),
1540
+ * however, they are also less intuitive and more likely to cause you problems.
1541
+ *
1542
+ * @see Crypt_Base::disableContinuousBuffer()
1543
+ * @access public
1544
+ * @internal Could, but not must, extend by the child Crypt_* class
1545
+ */
1546
+ function enableContinuousBuffer()
1547
+ {
1548
+ if ($this->mode == CRYPT_MODE_ECB) {
1549
+ return;
1550
+ }
1551
+
1552
+ $this->continuousBuffer = true;
1553
+
1554
+ $this->_setEngine();
1555
+ }
1556
+
1557
+ /**
1558
+ * Treat consecutive packets as if they are a discontinuous buffer.
1559
+ *
1560
+ * The default behavior.
1561
+ *
1562
+ * @see Crypt_Base::enableContinuousBuffer()
1563
+ * @access public
1564
+ * @internal Could, but not must, extend by the child Crypt_* class
1565
+ */
1566
+ function disableContinuousBuffer()
1567
+ {
1568
+ if ($this->mode == CRYPT_MODE_ECB) {
1569
+ return;
1570
+ }
1571
+ if (!$this->continuousBuffer) {
1572
+ return;
1573
+ }
1574
+
1575
+ $this->continuousBuffer = false;
1576
+ $this->changed = true;
1577
+
1578
+ $this->_setEngine();
1579
+ }
1580
+
1581
+ /**
1582
+ * Test for engine validity
1583
+ *
1584
+ * @see Crypt_Base::Crypt_Base()
1585
+ * @param int $engine
1586
+ * @access public
1587
+ * @return bool
1588
+ */
1589
+ function isValidEngine($engine)
1590
+ {
1591
+ switch ($engine) {
1592
+ case CRYPT_ENGINE_OPENSSL:
1593
+ if ($this->mode == CRYPT_MODE_STREAM && $this->continuousBuffer) {
1594
+ return false;
1595
+ }
1596
+ $this->openssl_emulate_ctr = false;
1597
+ $result = $this->cipher_name_openssl &&
1598
+ extension_loaded('openssl') &&
1599
+ // PHP 5.3.0 - 5.3.2 did not let you set IV's
1600
+ version_compare(PHP_VERSION, '5.3.3', '>=');
1601
+ if (!$result) {
1602
+ return false;
1603
+ }
1604
+
1605
+ // prior to PHP 5.4.0 OPENSSL_RAW_DATA and OPENSSL_ZERO_PADDING were not defined. instead of expecting an integer
1606
+ // $options openssl_encrypt expected a boolean $raw_data.
1607
+ if (!defined('OPENSSL_RAW_DATA')) {
1608
+ $this->openssl_options = true;
1609
+ } else {
1610
+ $this->openssl_options = OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING;
1611
+ }
1612
+
1613
+ $methods = openssl_get_cipher_methods();
1614
+ if (in_array($this->cipher_name_openssl, $methods)) {
1615
+ return true;
1616
+ }
1617
+ // not all of openssl's symmetric cipher's support ctr. for those
1618
+ // that don't we'll emulate it
1619
+ switch ($this->mode) {
1620
+ case CRYPT_MODE_CTR:
1621
+ if (in_array($this->cipher_name_openssl_ecb, $methods)) {
1622
+ $this->openssl_emulate_ctr = true;
1623
+ return true;
1624
+ }
1625
+ }
1626
+ return false;
1627
+ case CRYPT_ENGINE_MCRYPT:
1628
+ return $this->cipher_name_mcrypt &&
1629
+ extension_loaded('mcrypt') &&
1630
+ in_array($this->cipher_name_mcrypt, mcrypt_list_algorithms());
1631
+ case CRYPT_ENGINE_INTERNAL:
1632
+ return true;
1633
+ }
1634
+
1635
+ return false;
1636
+ }
1637
+
1638
+ /**
1639
+ * Sets the preferred crypt engine
1640
+ *
1641
+ * Currently, $engine could be:
1642
+ *
1643
+ * - CRYPT_ENGINE_OPENSSL [very fast]
1644
+ *
1645
+ * - CRYPT_ENGINE_MCRYPT [fast]
1646
+ *
1647
+ * - CRYPT_ENGINE_INTERNAL [slow]
1648
+ *
1649
+ * If the preferred crypt engine is not available the fastest available one will be used
1650
+ *
1651
+ * @see Crypt_Base::Crypt_Base()
1652
+ * @param int $engine
1653
+ * @access public
1654
+ */
1655
+ function setPreferredEngine($engine)
1656
+ {
1657
+ switch ($engine) {
1658
+ //case CRYPT_ENGINE_OPENSSL:
1659
+ case CRYPT_ENGINE_MCRYPT:
1660
+ case CRYPT_ENGINE_INTERNAL:
1661
+ $this->preferredEngine = $engine;
1662
+ break;
1663
+ default:
1664
+ $this->preferredEngine = CRYPT_ENGINE_OPENSSL;
1665
+ }
1666
+
1667
+ $this->_setEngine();
1668
+ }
1669
+
1670
+ /**
1671
+ * Returns the engine currently being utilized
1672
+ *
1673
+ * @see Crypt_Base::_setEngine()
1674
+ * @access public
1675
+ */
1676
+ function getEngine()
1677
+ {
1678
+ return $this->engine;
1679
+ }
1680
+
1681
+ /**
1682
+ * Sets the engine as appropriate
1683
+ *
1684
+ * @see Crypt_Base::Crypt_Base()
1685
+ * @access private
1686
+ */
1687
+ function _setEngine()
1688
+ {
1689
+ $this->engine = null;
1690
+
1691
+ $candidateEngines = array(
1692
+ $this->preferredEngine,
1693
+ CRYPT_ENGINE_OPENSSL,
1694
+ CRYPT_ENGINE_MCRYPT
1695
+ );
1696
+ foreach ($candidateEngines as $engine) {
1697
+ if ($this->isValidEngine($engine)) {
1698
+ $this->engine = $engine;
1699
+ break;
1700
+ }
1701
+ }
1702
+ if (!$this->engine) {
1703
+ $this->engine = CRYPT_ENGINE_INTERNAL;
1704
+ }
1705
+
1706
+ if ($this->engine != CRYPT_ENGINE_MCRYPT && $this->enmcrypt) {
1707
+ // Closing the current mcrypt resource(s). _mcryptSetup() will, if needed,
1708
+ // (re)open them with the module named in $this->cipher_name_mcrypt
1709
+ mcrypt_module_close($this->enmcrypt);
1710
+ mcrypt_module_close($this->demcrypt);
1711
+ $this->enmcrypt = null;
1712
+ $this->demcrypt = null;
1713
+
1714
+ if ($this->ecb) {
1715
+ mcrypt_module_close($this->ecb);
1716
+ $this->ecb = null;
1717
+ }
1718
+ }
1719
+
1720
+ $this->changed = true;
1721
+ }
1722
+
1723
+ /**
1724
+ * Encrypts a block
1725
+ *
1726
+ * @access private
1727
+ * @param string $in
1728
+ * @return string
1729
+ * @internal Must be extended by the child Crypt_* class
1730
+ */
1731
+ function _encryptBlock($in)
1732
+ {
1733
+ user_error((version_compare(PHP_VERSION, '5.0.0', '>=') ? __METHOD__ : __FUNCTION__) . '() must extend by class ' . get_class($this), E_USER_ERROR);
1734
+ }
1735
+
1736
+ /**
1737
+ * Decrypts a block
1738
+ *
1739
+ * @access private
1740
+ * @param string $in
1741
+ * @return string
1742
+ * @internal Must be extended by the child Crypt_* class
1743
+ */
1744
+ function _decryptBlock($in)
1745
+ {
1746
+ user_error((version_compare(PHP_VERSION, '5.0.0', '>=') ? __METHOD__ : __FUNCTION__) . '() must extend by class ' . get_class($this), E_USER_ERROR);
1747
+ }
1748
+
1749
+ /**
1750
+ * Setup the key (expansion)
1751
+ *
1752
+ * Only used if $engine == CRYPT_ENGINE_INTERNAL
1753
+ *
1754
+ * @see Crypt_Base::_setup()
1755
+ * @access private
1756
+ * @internal Must be extended by the child Crypt_* class
1757
+ */
1758
+ function _setupKey()
1759
+ {
1760
+ user_error((version_compare(PHP_VERSION, '5.0.0', '>=') ? __METHOD__ : __FUNCTION__) . '() must extend by class ' . get_class($this), E_USER_ERROR);
1761
+ }
1762
+
1763
+ /**
1764
+ * Setup the CRYPT_ENGINE_INTERNAL $engine
1765
+ *
1766
+ * (re)init, if necessary, the internal cipher $engine and flush all $buffers
1767
+ * Used (only) if $engine == CRYPT_ENGINE_INTERNAL
1768
+ *
1769
+ * _setup() will be called each time if $changed === true
1770
+ * typically this happens when using one or more of following public methods:
1771
+ *
1772
+ * - setKey()
1773
+ *
1774
+ * - setIV()
1775
+ *
1776
+ * - disableContinuousBuffer()
1777
+ *
1778
+ * - First run of encrypt() / decrypt() with no init-settings
1779
+ *
1780
+ * @see setKey()
1781
+ * @see setIV()
1782
+ * @see disableContinuousBuffer()
1783
+ * @access private
1784
+ * @internal _setup() is always called before en/decryption.
1785
+ * @internal Could, but not must, extend by the child Crypt_* class
1786
+ */
1787
+ function _setup()
1788
+ {
1789
+ $this->_clearBuffers();
1790
+ $this->_setupKey();
1791
+
1792
+ if ($this->use_inline_crypt) {
1793
+ $this->_setupInlineCrypt();
1794
+ }
1795
+ }
1796
+
1797
+ /**
1798
+ * Setup the CRYPT_ENGINE_MCRYPT $engine
1799
+ *
1800
+ * (re)init, if necessary, the (ext)mcrypt resources and flush all $buffers
1801
+ * Used (only) if $engine = CRYPT_ENGINE_MCRYPT
1802
+ *
1803
+ * _setupMcrypt() will be called each time if $changed === true
1804
+ * typically this happens when using one or more of following public methods:
1805
+ *
1806
+ * - setKey()
1807
+ *
1808
+ * - setIV()
1809
+ *
1810
+ * - disableContinuousBuffer()
1811
+ *
1812
+ * - First run of encrypt() / decrypt()
1813
+ *
1814
+ * @see setKey()
1815
+ * @see setIV()
1816
+ * @see disableContinuousBuffer()
1817
+ * @access private
1818
+ * @internal Could, but not must, extend by the child Crypt_* class
1819
+ */
1820
+ function _setupMcrypt()
1821
+ {
1822
+ $this->_clearBuffers();
1823
+ $this->enchanged = $this->dechanged = true;
1824
+
1825
+ if (!isset($this->enmcrypt)) {
1826
+ static $mcrypt_modes = array(
1827
+ CRYPT_MODE_CTR => 'ctr',
1828
+ CRYPT_MODE_ECB => MCRYPT_MODE_ECB,
1829
+ CRYPT_MODE_CBC => MCRYPT_MODE_CBC,
1830
+ CRYPT_MODE_CFB => 'ncfb',
1831
+ CRYPT_MODE_OFB => MCRYPT_MODE_NOFB,
1832
+ CRYPT_MODE_STREAM => MCRYPT_MODE_STREAM,
1833
+ );
1834
+
1835
+ $this->demcrypt = mcrypt_module_open($this->cipher_name_mcrypt, '', $mcrypt_modes[$this->mode], '');
1836
+ $this->enmcrypt = mcrypt_module_open($this->cipher_name_mcrypt, '', $mcrypt_modes[$this->mode], '');
1837
+
1838
+ // we need the $ecb mcrypt resource (only) in MODE_CFB with enableContinuousBuffer()
1839
+ // to workaround mcrypt's broken ncfb implementation in buffered mode
1840
+ // see: {@link http://phpseclib.sourceforge.net/cfb-demo.phps}
1841
+ if ($this->mode == CRYPT_MODE_CFB) {
1842
+ $this->ecb = mcrypt_module_open($this->cipher_name_mcrypt, '', MCRYPT_MODE_ECB, '');
1843
+ }
1844
+ } // else should mcrypt_generic_deinit be called?
1845
+
1846
+ if ($this->mode == CRYPT_MODE_CFB) {
1847
+ mcrypt_generic_init($this->ecb, $this->key, str_repeat("\0", $this->block_size));
1848
+ }
1849
+ }
1850
+
1851
+ /**
1852
+ * Pads a string
1853
+ *
1854
+ * Pads a string using the RSA PKCS padding standards so that its length is a multiple of the blocksize.
1855
+ * $this->block_size - (strlen($text) % $this->block_size) bytes are added, each of which is equal to
1856
+ * chr($this->block_size - (strlen($text) % $this->block_size)
1857
+ *
1858
+ * If padding is disabled and $text is not a multiple of the blocksize, the string will be padded regardless
1859
+ * and padding will, hence forth, be enabled.
1860
+ *
1861
+ * @see Crypt_Base::_unpad()
1862
+ * @param string $text
1863
+ * @access private
1864
+ * @return string
1865
+ */
1866
+ function _pad($text)
1867
+ {
1868
+ $length = strlen($text);
1869
+
1870
+ if (!$this->padding) {
1871
+ if ($length % $this->block_size == 0) {
1872
+ return $text;
1873
+ } else {
1874
+ user_error("The plaintext's length ($length) is not a multiple of the block size ({$this->block_size})");
1875
+ $this->padding = true;
1876
+ }
1877
+ }
1878
+
1879
+ $pad = $this->block_size - ($length % $this->block_size);
1880
+
1881
+ return str_pad($text, $length + $pad, chr($pad));
1882
+ }
1883
+
1884
+ /**
1885
+ * Unpads a string.
1886
+ *
1887
+ * If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong
1888
+ * and false will be returned.
1889
+ *
1890
+ * @see Crypt_Base::_pad()
1891
+ * @param string $text
1892
+ * @access private
1893
+ * @return string
1894
+ */
1895
+ function _unpad($text)
1896
+ {
1897
+ if (!$this->padding) {
1898
+ return $text;
1899
+ }
1900
+
1901
+ $length = ord($text[strlen($text) - 1]);
1902
+
1903
+ if (!$length || $length > $this->block_size) {
1904
+ return false;
1905
+ }
1906
+
1907
+ return substr($text, 0, -$length);
1908
+ }
1909
+
1910
+ /**
1911
+ * Clears internal buffers
1912
+ *
1913
+ * Clearing/resetting the internal buffers is done everytime
1914
+ * after disableContinuousBuffer() or on cipher $engine (re)init
1915
+ * ie after setKey() or setIV()
1916
+ *
1917
+ * @access public
1918
+ * @internal Could, but not must, extend by the child Crypt_* class
1919
+ */
1920
+ function _clearBuffers()
1921
+ {
1922
+ $this->enbuffer = $this->debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true);
1923
+
1924
+ // mcrypt's handling of invalid's $iv:
1925
+ // $this->encryptIV = $this->decryptIV = strlen($this->iv) == $this->block_size ? $this->iv : str_repeat("\0", $this->block_size);
1926
+ $this->encryptIV = $this->decryptIV = str_pad(substr($this->iv, 0, $this->block_size), $this->block_size, "\0");
1927
+
1928
+ if (!$this->skip_key_adjustment) {
1929
+ $this->key = str_pad(substr($this->key, 0, $this->key_length), $this->key_length, "\0");
1930
+ }
1931
+ }
1932
+
1933
+ /**
1934
+ * String Shift
1935
+ *
1936
+ * Inspired by array_shift
1937
+ *
1938
+ * @param string $string
1939
+ * @param int $index
1940
+ * @access private
1941
+ * @return string
1942
+ */
1943
+ function _string_shift(&$string, $index = 1)
1944
+ {
1945
+ $substr = substr($string, 0, $index);
1946
+ $string = substr($string, $index);
1947
+ return $substr;
1948
+ }
1949
+
1950
+ /**
1951
+ * String Pop
1952
+ *
1953
+ * Inspired by array_pop
1954
+ *
1955
+ * @param string $string
1956
+ * @param int $index
1957
+ * @access private
1958
+ * @return string
1959
+ */
1960
+ function _string_pop(&$string, $index = 1)
1961
+ {
1962
+ $substr = substr($string, -$index);
1963
+ $string = substr($string, 0, -$index);
1964
+ return $substr;
1965
+ }
1966
+
1967
+ /**
1968
+ * Increment the current string
1969
+ *
1970
+ * @see Crypt_Base::decrypt()
1971
+ * @see Crypt_Base::encrypt()
1972
+ * @param string $var
1973
+ * @access private
1974
+ */
1975
+ function _increment_str(&$var)
1976
+ {
1977
+ for ($i = 4; $i <= strlen($var); $i+= 4) {
1978
+ $temp = substr($var, -$i, 4);
1979
+ switch ($temp) {
1980
+ case "\xFF\xFF\xFF\xFF":
1981
+ $var = substr_replace($var, "\x00\x00\x00\x00", -$i, 4);
1982
+ break;
1983
+ case "\x7F\xFF\xFF\xFF":
1984
+ $var = substr_replace($var, "\x80\x00\x00\x00", -$i, 4);
1985
+ return;
1986
+ default:
1987
+ $temp = unpack('Nnum', $temp);
1988
+ $var = substr_replace($var, pack('N', $temp['num'] + 1), -$i, 4);
1989
+ return;
1990
+ }
1991
+ }
1992
+
1993
+ $remainder = strlen($var) % 4;
1994
+
1995
+ if ($remainder == 0) {
1996
+ return;
1997
+ }
1998
+
1999
+ $temp = unpack('Nnum', str_pad(substr($var, 0, $remainder), 4, "\0", STR_PAD_LEFT));
2000
+ $temp = substr(pack('N', $temp['num'] + 1), -$remainder);
2001
+ $var = substr_replace($var, $temp, 0, $remainder);
2002
+ }
2003
+
2004
+ /**
2005
+ * Setup the performance-optimized function for de/encrypt()
2006
+ *
2007
+ * Stores the created (or existing) callback function-name
2008
+ * in $this->inline_crypt
2009
+ *
2010
+ * Internally for phpseclib developers:
2011
+ *
2012
+ * _setupInlineCrypt() would be called only if:
2013
+ *
2014
+ * - $engine == CRYPT_ENGINE_INTERNAL and
2015
+ *
2016
+ * - $use_inline_crypt === true
2017
+ *
2018
+ * - each time on _setup(), after(!) _setupKey()
2019
+ *
2020
+ *
2021
+ * This ensures that _setupInlineCrypt() has always a
2022
+ * full ready2go initializated internal cipher $engine state
2023
+ * where, for example, the keys allready expanded,
2024
+ * keys/block_size calculated and such.
2025
+ *
2026
+ * It is, each time if called, the responsibility of _setupInlineCrypt():
2027
+ *
2028
+ * - to set $this->inline_crypt to a valid and fully working callback function
2029
+ * as a (faster) replacement for encrypt() / decrypt()
2030
+ *
2031
+ * - NOT to create unlimited callback functions (for memory reasons!)
2032
+ * no matter how often _setupInlineCrypt() would be called. At some
2033
+ * point of amount they must be generic re-useable.
2034
+ *
2035
+ * - the code of _setupInlineCrypt() it self,
2036
+ * and the generated callback code,
2037
+ * must be, in following order:
2038
+ * - 100% safe
2039
+ * - 100% compatible to encrypt()/decrypt()
2040
+ * - using only php5+ features/lang-constructs/php-extensions if
2041
+ * compatibility (down to php4) or fallback is provided
2042
+ * - readable/maintainable/understandable/commented and... not-cryptic-styled-code :-)
2043
+ * - >= 10% faster than encrypt()/decrypt() [which is, by the way,
2044
+ * the reason for the existence of _setupInlineCrypt() :-)]
2045
+ * - memory-nice
2046
+ * - short (as good as possible)
2047
+ *
2048
+ * Note: - _setupInlineCrypt() is using _createInlineCryptFunction() to create the full callback function code.
2049
+ * - In case of using inline crypting, _setupInlineCrypt() must extend by the child Crypt_* class.
2050
+ * - The following variable names are reserved:
2051
+ * - $_* (all variable names prefixed with an underscore)
2052
+ * - $self (object reference to it self. Do not use $this, but $self instead)
2053
+ * - $in (the content of $in has to en/decrypt by the generated code)
2054
+ * - The callback function should not use the 'return' statement, but en/decrypt'ing the content of $in only
2055
+ *
2056
+ *
2057
+ * @see Crypt_Base::_setup()
2058
+ * @see Crypt_Base::_createInlineCryptFunction()
2059
+ * @see Crypt_Base::encrypt()
2060
+ * @see Crypt_Base::decrypt()
2061
+ * @access private
2062
+ * @internal If a Crypt_* class providing inline crypting it must extend _setupInlineCrypt()
2063
+ */
2064
+ function _setupInlineCrypt()
2065
+ {
2066
+ // If, for any reason, an extending Crypt_Base() Crypt_* class
2067
+ // not using inline crypting then it must be ensured that: $this->use_inline_crypt = false
2068
+ // ie in the class var declaration of $use_inline_crypt in general for the Crypt_* class,
2069
+ // in the constructor at object instance-time
2070
+ // or, if it's runtime-specific, at runtime
2071
+
2072
+ $this->use_inline_crypt = false;
2073
+ }
2074
+
2075
+ /**
2076
+ * Creates the performance-optimized function for en/decrypt()
2077
+ *
2078
+ * Internally for phpseclib developers:
2079
+ *
2080
+ * _createInlineCryptFunction():
2081
+ *
2082
+ * - merge the $cipher_code [setup'ed by _setupInlineCrypt()]
2083
+ * with the current [$this->]mode of operation code
2084
+ *
2085
+ * - create the $inline function, which called by encrypt() / decrypt()
2086
+ * as its replacement to speed up the en/decryption operations.
2087
+ *
2088
+ * - return the name of the created $inline callback function
2089
+ *
2090
+ * - used to speed up en/decryption
2091
+ *
2092
+ *
2093
+ *
2094
+ * The main reason why can speed up things [up to 50%] this way are:
2095
+ *
2096
+ * - using variables more effective then regular.
2097
+ * (ie no use of expensive arrays but integers $k_0, $k_1 ...
2098
+ * or even, for example, the pure $key[] values hardcoded)
2099
+ *
2100
+ * - avoiding 1000's of function calls of ie _encryptBlock()
2101
+ * but inlining the crypt operations.
2102
+ * in the mode of operation for() loop.
2103
+ *
2104
+ * - full loop unroll the (sometimes key-dependent) rounds
2105
+ * avoiding this way ++$i counters and runtime-if's etc...
2106
+ *
2107
+ * The basic code architectur of the generated $inline en/decrypt()
2108
+ * lambda function, in pseudo php, is:
2109
+ *
2110
+ * <code>
2111
+ * +----------------------------------------------------------------------------------------------+
2112
+ * | callback $inline = create_function: |
2113
+ * | lambda_function_0001_crypt_ECB($action, $text) |
2114
+ * | { |
2115
+ * | INSERT PHP CODE OF: |
2116
+ * | $cipher_code['init_crypt']; // general init code. |
2117
+ * | // ie: $sbox'es declarations used for |
2118
+ * | // encrypt and decrypt'ing. |
2119
+ * | |
2120
+ * | switch ($action) { |
2121
+ * | case 'encrypt': |
2122
+ * | INSERT PHP CODE OF: |
2123
+ * | $cipher_code['init_encrypt']; // encrypt sepcific init code. |
2124
+ * | ie: specified $key or $box |
2125
+ * | declarations for encrypt'ing. |
2126
+ * | |
2127
+ * | foreach ($ciphertext) { |
2128
+ * | $in = $block_size of $ciphertext; |
2129
+ * | |
2130
+ * | INSERT PHP CODE OF: |
2131
+ * | $cipher_code['encrypt_block']; // encrypt's (string) $in, which is always: |
2132
+ * | // strlen($in) == $this->block_size |
2133
+ * | // here comes the cipher algorithm in action |
2134
+ * | // for encryption. |
2135
+ * | // $cipher_code['encrypt_block'] has to |
2136
+ * | // encrypt the content of the $in variable |
2137
+ * | |
2138
+ * | $plaintext .= $in; |
2139
+ * | } |
2140
+ * | return $plaintext; |
2141
+ * | |
2142
+ * | case 'decrypt': |
2143
+ * | INSERT PHP CODE OF: |
2144
+ * | $cipher_code['init_decrypt']; // decrypt sepcific init code |
2145
+ * | ie: specified $key or $box |
2146
+ * | declarations for decrypt'ing. |
2147
+ * | foreach ($plaintext) { |
2148
+ * | $in = $block_size of $plaintext; |
2149
+ * | |
2150
+ * | INSERT PHP CODE OF: |
2151
+ * | $cipher_code['decrypt_block']; // decrypt's (string) $in, which is always |
2152
+ * | // strlen($in) == $this->block_size |
2153
+ * | // here comes the cipher algorithm in action |
2154
+ * | // for decryption. |
2155
+ * | // $cipher_code['decrypt_block'] has to |
2156
+ * | // decrypt the content of the $in variable |
2157
+ * | $ciphertext .= $in; |
2158
+ * | } |
2159
+ * | return $ciphertext; |
2160
+ * | } |
2161
+ * | } |
2162
+ * +----------------------------------------------------------------------------------------------+
2163
+ * </code>
2164
+ *
2165
+ * See also the Crypt_*::_setupInlineCrypt()'s for
2166
+ * productive inline $cipher_code's how they works.
2167
+ *
2168
+ * Structure of:
2169
+ * <code>
2170
+ * $cipher_code = array(
2171
+ * 'init_crypt' => (string) '', // optional
2172
+ * 'init_encrypt' => (string) '', // optional
2173
+ * 'init_decrypt' => (string) '', // optional
2174
+ * 'encrypt_block' => (string) '', // required
2175
+ * 'decrypt_block' => (string) '' // required
2176
+ * );
2177
+ * </code>
2178
+ *
2179
+ * @see Crypt_Base::_setupInlineCrypt()
2180
+ * @see Crypt_Base::encrypt()
2181
+ * @see Crypt_Base::decrypt()
2182
+ * @param array $cipher_code
2183
+ * @access private
2184
+ * @return string (the name of the created callback function)
2185
+ */
2186
+ function _createInlineCryptFunction($cipher_code)
2187
+ {
2188
+ $block_size = $this->block_size;
2189
+
2190
+ // optional
2191
+ $init_crypt = isset($cipher_code['init_crypt']) ? $cipher_code['init_crypt'] : '';
2192
+ $init_encrypt = isset($cipher_code['init_encrypt']) ? $cipher_code['init_encrypt'] : '';
2193
+ $init_decrypt = isset($cipher_code['init_decrypt']) ? $cipher_code['init_decrypt'] : '';
2194
+ // required
2195
+ $encrypt_block = $cipher_code['encrypt_block'];
2196
+ $decrypt_block = $cipher_code['decrypt_block'];
2197
+
2198
+ // Generating mode of operation inline code,
2199
+ // merged with the $cipher_code algorithm
2200
+ // for encrypt- and decryption.
2201
+ switch ($this->mode) {
2202
+ case CRYPT_MODE_ECB:
2203
+ $encrypt = $init_encrypt . '
2204
+ $_ciphertext = "";
2205
+ $_plaintext_len = strlen($_text);
2206
+
2207
+ for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
2208
+ $in = substr($_text, $_i, '.$block_size.');
2209
+ '.$encrypt_block.'
2210
+ $_ciphertext.= $in;
2211
+ }
2212
+
2213
+ return $_ciphertext;
2214
+ ';
2215
+
2216
+ $decrypt = $init_decrypt . '
2217
+ $_plaintext = "";
2218
+ $_text = str_pad($_text, strlen($_text) + ('.$block_size.' - strlen($_text) % '.$block_size.') % '.$block_size.', chr(0));
2219
+ $_ciphertext_len = strlen($_text);
2220
+
2221
+ for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
2222
+ $in = substr($_text, $_i, '.$block_size.');
2223
+ '.$decrypt_block.'
2224
+ $_plaintext.= $in;
2225
+ }
2226
+
2227
+ return $self->_unpad($_plaintext);
2228
+ ';
2229
+ break;
2230
+ case CRYPT_MODE_CTR:
2231
+ $encrypt = $init_encrypt . '
2232
+ $_ciphertext = "";
2233
+ $_plaintext_len = strlen($_text);
2234
+ $_xor = $self->encryptIV;
2235
+ $_buffer = &$self->enbuffer;
2236
+ if (strlen($_buffer["ciphertext"])) {
2237
+ for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
2238
+ $_block = substr($_text, $_i, '.$block_size.');
2239
+ if (strlen($_block) > strlen($_buffer["ciphertext"])) {
2240
+ $in = $_xor;
2241
+ '.$encrypt_block.'
2242
+ $self->_increment_str($_xor);
2243
+ $_buffer["ciphertext"].= $in;
2244
+ }
2245
+ $_key = $self->_string_shift($_buffer["ciphertext"], '.$block_size.');
2246
+ $_ciphertext.= $_block ^ $_key;
2247
+ }
2248
+ } else {
2249
+ for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
2250
+ $_block = substr($_text, $_i, '.$block_size.');
2251
+ $in = $_xor;
2252
+ '.$encrypt_block.'
2253
+ $self->_increment_str($_xor);
2254
+ $_key = $in;
2255
+ $_ciphertext.= $_block ^ $_key;
2256
+ }
2257
+ }
2258
+ if ($self->continuousBuffer) {
2259
+ $self->encryptIV = $_xor;
2260
+ if ($_start = $_plaintext_len % '.$block_size.') {
2261
+ $_buffer["ciphertext"] = substr($_key, $_start) . $_buffer["ciphertext"];
2262
+ }
2263
+ }
2264
+
2265
+ return $_ciphertext;
2266
+ ';
2267
+
2268
+ $decrypt = $init_encrypt . '
2269
+ $_plaintext = "";
2270
+ $_ciphertext_len = strlen($_text);
2271
+ $_xor = $self->decryptIV;
2272
+ $_buffer = &$self->debuffer;
2273
+
2274
+ if (strlen($_buffer["ciphertext"])) {
2275
+ for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
2276
+ $_block = substr($_text, $_i, '.$block_size.');
2277
+ if (strlen($_block) > strlen($_buffer["ciphertext"])) {
2278
+ $in = $_xor;
2279
+ '.$encrypt_block.'
2280
+ $self->_increment_str($_xor);
2281
+ $_buffer["ciphertext"].= $in;
2282
+ }
2283
+ $_key = $self->_string_shift($_buffer["ciphertext"], '.$block_size.');
2284
+ $_plaintext.= $_block ^ $_key;
2285
+ }
2286
+ } else {
2287
+ for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
2288
+ $_block = substr($_text, $_i, '.$block_size.');
2289
+ $in = $_xor;
2290
+ '.$encrypt_block.'
2291
+ $self->_increment_str($_xor);
2292
+ $_key = $in;
2293
+ $_plaintext.= $_block ^ $_key;
2294
+ }
2295
+ }
2296
+ if ($self->continuousBuffer) {
2297
+ $self->decryptIV = $_xor;
2298
+ if ($_start = $_ciphertext_len % '.$block_size.') {
2299
+ $_buffer["ciphertext"] = substr($_key, $_start) . $_buffer["ciphertext"];
2300
+ }
2301
+ }
2302
+
2303
+ return $_plaintext;
2304
+ ';
2305
+ break;
2306
+ case CRYPT_MODE_CFB:
2307
+ $encrypt = $init_encrypt . '
2308
+ $_ciphertext = "";
2309
+ $_buffer = &$self->enbuffer;
2310
+
2311
+ if ($self->continuousBuffer) {
2312
+ $_iv = &$self->encryptIV;
2313
+ $_pos = &$_buffer["pos"];
2314
+ } else {
2315
+ $_iv = $self->encryptIV;
2316
+ $_pos = 0;
2317
+ }
2318
+ $_len = strlen($_text);
2319
+ $_i = 0;
2320
+ if ($_pos) {
2321
+ $_orig_pos = $_pos;
2322
+ $_max = '.$block_size.' - $_pos;
2323
+ if ($_len >= $_max) {
2324
+ $_i = $_max;
2325
+ $_len-= $_max;
2326
+ $_pos = 0;
2327
+ } else {
2328
+ $_i = $_len;
2329
+ $_pos+= $_len;
2330
+ $_len = 0;
2331
+ }
2332
+ $_ciphertext = substr($_iv, $_orig_pos) ^ $_text;
2333
+ $_iv = substr_replace($_iv, $_ciphertext, $_orig_pos, $_i);
2334
+ }
2335
+ while ($_len >= '.$block_size.') {
2336
+ $in = $_iv;
2337
+ '.$encrypt_block.';
2338
+ $_iv = $in ^ substr($_text, $_i, '.$block_size.');
2339
+ $_ciphertext.= $_iv;
2340
+ $_len-= '.$block_size.';
2341
+ $_i+= '.$block_size.';
2342
+ }
2343
+ if ($_len) {
2344
+ $in = $_iv;
2345
+ '.$encrypt_block.'
2346
+ $_iv = $in;
2347
+ $_block = $_iv ^ substr($_text, $_i);
2348
+ $_iv = substr_replace($_iv, $_block, 0, $_len);
2349
+ $_ciphertext.= $_block;
2350
+ $_pos = $_len;
2351
+ }
2352
+ return $_ciphertext;
2353
+ ';
2354
+
2355
+ $decrypt = $init_encrypt . '
2356
+ $_plaintext = "";
2357
+ $_buffer = &$self->debuffer;
2358
+
2359
+ if ($self->continuousBuffer) {
2360
+ $_iv = &$self->decryptIV;
2361
+ $_pos = &$_buffer["pos"];
2362
+ } else {
2363
+ $_iv = $self->decryptIV;
2364
+ $_pos = 0;
2365
+ }
2366
+ $_len = strlen($_text);
2367
+ $_i = 0;
2368
+ if ($_pos) {
2369
+ $_orig_pos = $_pos;
2370
+ $_max = '.$block_size.' - $_pos;
2371
+ if ($_len >= $_max) {
2372
+ $_i = $_max;
2373
+ $_len-= $_max;
2374
+ $_pos = 0;
2375
+ } else {
2376
+ $_i = $_len;
2377
+ $_pos+= $_len;
2378
+ $_len = 0;
2379
+ }
2380
+ $_plaintext = substr($_iv, $_orig_pos) ^ $_text;
2381
+ $_iv = substr_replace($_iv, substr($_text, 0, $_i), $_orig_pos, $_i);
2382
+ }
2383
+ while ($_len >= '.$block_size.') {
2384
+ $in = $_iv;
2385
+ '.$encrypt_block.'
2386
+ $_iv = $in;
2387
+ $cb = substr($_text, $_i, '.$block_size.');
2388
+ $_plaintext.= $_iv ^ $cb;
2389
+ $_iv = $cb;
2390
+ $_len-= '.$block_size.';
2391
+ $_i+= '.$block_size.';
2392
+ }
2393
+ if ($_len) {
2394
+ $in = $_iv;
2395
+ '.$encrypt_block.'
2396
+ $_iv = $in;
2397
+ $_plaintext.= $_iv ^ substr($_text, $_i);
2398
+ $_iv = substr_replace($_iv, substr($_text, $_i), 0, $_len);
2399
+ $_pos = $_len;
2400
+ }
2401
+
2402
+ return $_plaintext;
2403
+ ';
2404
+ break;
2405
+ case CRYPT_MODE_OFB:
2406
+ $encrypt = $init_encrypt . '
2407
+ $_ciphertext = "";
2408
+ $_plaintext_len = strlen($_text);
2409
+ $_xor = $self->encryptIV;
2410
+ $_buffer = &$self->enbuffer;
2411
+
2412
+ if (strlen($_buffer["xor"])) {
2413
+ for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
2414
+ $_block = substr($_text, $_i, '.$block_size.');
2415
+ if (strlen($_block) > strlen($_buffer["xor"])) {
2416
+ $in = $_xor;
2417
+ '.$encrypt_block.'
2418
+ $_xor = $in;
2419
+ $_buffer["xor"].= $_xor;
2420
+ }
2421
+ $_key = $self->_string_shift($_buffer["xor"], '.$block_size.');
2422
+ $_ciphertext.= $_block ^ $_key;
2423
+ }
2424
+ } else {
2425
+ for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
2426
+ $in = $_xor;
2427
+ '.$encrypt_block.'
2428
+ $_xor = $in;
2429
+ $_ciphertext.= substr($_text, $_i, '.$block_size.') ^ $_xor;
2430
+ }
2431
+ $_key = $_xor;
2432
+ }
2433
+ if ($self->continuousBuffer) {
2434
+ $self->encryptIV = $_xor;
2435
+ if ($_start = $_plaintext_len % '.$block_size.') {
2436
+ $_buffer["xor"] = substr($_key, $_start) . $_buffer["xor"];
2437
+ }
2438
+ }
2439
+ return $_ciphertext;
2440
+ ';
2441
+
2442
+ $decrypt = $init_encrypt . '
2443
+ $_plaintext = "";
2444
+ $_ciphertext_len = strlen($_text);
2445
+ $_xor = $self->decryptIV;
2446
+ $_buffer = &$self->debuffer;
2447
+
2448
+ if (strlen($_buffer["xor"])) {
2449
+ for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
2450
+ $_block = substr($_text, $_i, '.$block_size.');
2451
+ if (strlen($_block) > strlen($_buffer["xor"])) {
2452
+ $in = $_xor;
2453
+ '.$encrypt_block.'
2454
+ $_xor = $in;
2455
+ $_buffer["xor"].= $_xor;
2456
+ }
2457
+ $_key = $self->_string_shift($_buffer["xor"], '.$block_size.');
2458
+ $_plaintext.= $_block ^ $_key;
2459
+ }
2460
+ } else {
2461
+ for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
2462
+ $in = $_xor;
2463
+ '.$encrypt_block.'
2464
+ $_xor = $in;
2465
+ $_plaintext.= substr($_text, $_i, '.$block_size.') ^ $_xor;
2466
+ }
2467
+ $_key = $_xor;
2468
+ }
2469
+ if ($self->continuousBuffer) {
2470
+ $self->decryptIV = $_xor;
2471
+ if ($_start = $_ciphertext_len % '.$block_size.') {
2472
+ $_buffer["xor"] = substr($_key, $_start) . $_buffer["xor"];
2473
+ }
2474
+ }
2475
+ return $_plaintext;
2476
+ ';
2477
+ break;
2478
+ case CRYPT_MODE_STREAM:
2479
+ $encrypt = $init_encrypt . '
2480
+ $_ciphertext = "";
2481
+ '.$encrypt_block.'
2482
+ return $_ciphertext;
2483
+ ';
2484
+ $decrypt = $init_decrypt . '
2485
+ $_plaintext = "";
2486
+ '.$decrypt_block.'
2487
+ return $_plaintext;
2488
+ ';
2489
+ break;
2490
+ // case CRYPT_MODE_CBC:
2491
+ default:
2492
+ $encrypt = $init_encrypt . '
2493
+ $_ciphertext = "";
2494
+ $_plaintext_len = strlen($_text);
2495
+
2496
+ $in = $self->encryptIV;
2497
+
2498
+ for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
2499
+ $in = substr($_text, $_i, '.$block_size.') ^ $in;
2500
+ '.$encrypt_block.'
2501
+ $_ciphertext.= $in;
2502
+ }
2503
+
2504
+ if ($self->continuousBuffer) {
2505
+ $self->encryptIV = $in;
2506
+ }
2507
+
2508
+ return $_ciphertext;
2509
+ ';
2510
+
2511
+ $decrypt = $init_decrypt . '
2512
+ $_plaintext = "";
2513
+ $_text = str_pad($_text, strlen($_text) + ('.$block_size.' - strlen($_text) % '.$block_size.') % '.$block_size.', chr(0));
2514
+ $_ciphertext_len = strlen($_text);
2515
+
2516
+ $_iv = $self->decryptIV;
2517
+
2518
+ for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
2519
+ $in = $_block = substr($_text, $_i, '.$block_size.');
2520
+ '.$decrypt_block.'
2521
+ $_plaintext.= $in ^ $_iv;
2522
+ $_iv = $_block;
2523
+ }
2524
+
2525
+ if ($self->continuousBuffer) {
2526
+ $self->decryptIV = $_iv;
2527
+ }
2528
+
2529
+ return $self->_unpad($_plaintext);
2530
+ ';
2531
+ break;
2532
+ }
2533
+
2534
+ // Create the $inline function and return its name as string. Ready to run!
2535
+ return create_function('$_action, &$self, $_text', $init_crypt . 'if ($_action == "encrypt") { ' . $encrypt . ' } else { ' . $decrypt . ' }');
2536
+ }
2537
+
2538
+ /**
2539
+ * Holds the lambda_functions table (classwide)
2540
+ *
2541
+ * Each name of the lambda function, created from
2542
+ * _setupInlineCrypt() && _createInlineCryptFunction()
2543
+ * is stored, classwide (!), here for reusing.
2544
+ *
2545
+ * The string-based index of $function is a classwide
2546
+ * uniqe value representing, at least, the $mode of
2547
+ * operation (or more... depends of the optimizing level)
2548
+ * for which $mode the lambda function was created.
2549
+ *
2550
+ * @access private
2551
+ * @return array &$functions
2552
+ */
2553
+ function &_getLambdaFunctions()
2554
+ {
2555
+ static $functions = array();
2556
+ return $functions;
2557
+ }
2558
+
2559
+ /**
2560
+ * Generates a digest from $bytes
2561
+ *
2562
+ * @see _setupInlineCrypt()
2563
+ * @access private
2564
+ * @param $bytes
2565
+ * @return string
2566
+ */
2567
+ function _hashInlineCryptFunction($bytes)
2568
+ {
2569
+ if (!defined('CRYPT_BASE_WHIRLPOOL_AVAILABLE')) {
2570
+ define('CRYPT_BASE_WHIRLPOOL_AVAILABLE', (bool)(extension_loaded('hash') && in_array('whirlpool', hash_algos())));
2571
+ }
2572
+
2573
+ $result = '';
2574
+ $hash = $bytes;
2575
+
2576
+ switch (true) {
2577
+ case CRYPT_BASE_WHIRLPOOL_AVAILABLE:
2578
+ foreach (str_split($bytes, 64) as $t) {
2579
+ $hash = hash('whirlpool', $hash, true);
2580
+ $result .= $t ^ $hash;
2581
+ }
2582
+ return $result . hash('whirlpool', $hash, true);
2583
+ default:
2584
+ $len = strlen($bytes);
2585
+ for ($i = 0; $i < $len; $i+=20) {
2586
+ $t = substr($bytes, $i, 20);
2587
+ $hash = pack('H*', sha1($hash));
2588
+ $result .= $t ^ $hash;
2589
+ }
2590
+ return $result . pack('H*', sha1($hash));
2591
+ }
2592
+ }
2593
+ }
lib/phpseclib/LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Copyright 2007-2013 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.
lib/phpseclib/Rijndael.php ADDED
@@ -0,0 +1,1037 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Pure-PHP implementation of Rijndael.
5
+ *
6
+ * Uses mcrypt, if available/possible, and an internal implementation, otherwise.
7
+ *
8
+ * PHP versions 4 and 5
9
+ *
10
+ * If {@link Crypt_Rijndael::setBlockLength() setBlockLength()} isn't called, it'll be assumed to be 128 bits. If
11
+ * {@link Crypt_Rijndael::setKeyLength() setKeyLength()} isn't called, it'll be calculated from
12
+ * {@link Crypt_Rijndael::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 Crypt_Rijndael::setKey() setKey()} is called, again, at which point, it'll be recalculated.
15
+ *
16
+ * Not all Rijndael implementations may support 160-bits or 224-bits as the block length / key length. mcrypt, for example,
17
+ * does not. AES, itself, only supports block lengths of 128 and key lengths of 128, 192, and 256.
18
+ * {@link http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=10 Rijndael-ammended.pdf#page=10} defines the
19
+ * algorithm for block lengths of 192 and 256 but not for block lengths / key lengths of 160 and 224. Indeed, 160 and 224
20
+ * are first defined as valid key / block lengths in
21
+ * {@link http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=44 Rijndael-ammended.pdf#page=44}:
22
+ * Extensions: Other block and Cipher Key lengths.
23
+ * Note: Use of 160/224-bit Keys must be explicitly set by setKeyLength(160) respectively setKeyLength(224).
24
+ *
25
+ * {@internal The variable names are the same as those in
26
+ * {@link http://www.csrc.nist.gov/publications/fips/fips197/fips-197.pdf#page=10 fips-197.pdf#page=10}.}}
27
+ *
28
+ * Here's a short example of how to use this library:
29
+ * <code>
30
+ * <?php
31
+ * include 'Crypt/Rijndael.php';
32
+ *
33
+ * $rijndael = new Crypt_Rijndael();
34
+ *
35
+ * $rijndael->setKey('abcdefghijklmnop');
36
+ *
37
+ * $size = 10 * 1024;
38
+ * $plaintext = '';
39
+ * for ($i = 0; $i < $size; $i++) {
40
+ * $plaintext.= 'a';
41
+ * }
42
+ *
43
+ * echo $rijndael->decrypt($rijndael->encrypt($plaintext));
44
+ * ?>
45
+ * </code>
46
+ *
47
+ * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
48
+ * of this software and associated documentation files (the "Software"), to deal
49
+ * in the Software without restriction, including without limitation the rights
50
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
51
+ * copies of the Software, and to permit persons to whom the Software is
52
+ * furnished to do so, subject to the following conditions:
53
+ *
54
+ * The above copyright notice and this permission notice shall be included in
55
+ * all copies or substantial portions of the Software.
56
+ *
57
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
58
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
59
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
60
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
61
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
62
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
63
+ * THE SOFTWARE.
64
+ *
65
+ * @category Crypt
66
+ * @package Crypt_Rijndael
67
+ * @author Jim Wigginton <terrafrost@php.net>
68
+ * @copyright 2008 Jim Wigginton
69
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
70
+ * @link http://phpseclib.sourceforge.net
71
+ */
72
+
73
+ /**
74
+ * Include Crypt_Base
75
+ *
76
+ * Base cipher class
77
+ */
78
+ if (!class_exists('Crypt_Base')) {
79
+ include_once 'Base.php';
80
+ }
81
+
82
+ /**#@+
83
+ * @access public
84
+ * @see Crypt_Rijndael::encrypt()
85
+ * @see Crypt_Rijndael::decrypt()
86
+ */
87
+ /**
88
+ * Encrypt / decrypt using the Counter mode.
89
+ *
90
+ * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
91
+ *
92
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
93
+ */
94
+ define('CRYPT_RIJNDAEL_MODE_CTR', CRYPT_MODE_CTR);
95
+ /**
96
+ * Encrypt / decrypt using the Electronic Code Book mode.
97
+ *
98
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
99
+ */
100
+ define('CRYPT_RIJNDAEL_MODE_ECB', CRYPT_MODE_ECB);
101
+ /**
102
+ * Encrypt / decrypt using the Code Book Chaining mode.
103
+ *
104
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
105
+ */
106
+ define('CRYPT_RIJNDAEL_MODE_CBC', CRYPT_MODE_CBC);
107
+ /**
108
+ * Encrypt / decrypt using the Cipher Feedback mode.
109
+ *
110
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
111
+ */
112
+ define('CRYPT_RIJNDAEL_MODE_CFB', CRYPT_MODE_CFB);
113
+ /**
114
+ * Encrypt / decrypt using the Cipher Feedback mode.
115
+ *
116
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
117
+ */
118
+ define('CRYPT_RIJNDAEL_MODE_OFB', CRYPT_MODE_OFB);
119
+ /**#@-*/
120
+
121
+ /**
122
+ * Pure-PHP implementation of Rijndael.
123
+ *
124
+ * @package Crypt_Rijndael
125
+ * @author Jim Wigginton <terrafrost@php.net>
126
+ * @access public
127
+ */
128
+ class Crypt_Rijndael extends Crypt_Base
129
+ {
130
+ /**
131
+ * The namespace used by the cipher for its constants.
132
+ *
133
+ * @see Crypt_Base::const_namespace
134
+ * @var string
135
+ * @access private
136
+ */
137
+ var $const_namespace = 'RIJNDAEL';
138
+
139
+ /**
140
+ * The mcrypt specific name of the cipher
141
+ *
142
+ * Mcrypt is useable for 128/192/256-bit $block_size/$key_length. For 160/224 not.
143
+ * Crypt_Rijndael determines automatically whether mcrypt is useable
144
+ * or not for the current $block_size/$key_length.
145
+ * In case of, $cipher_name_mcrypt will be set dynamically at run time accordingly.
146
+ *
147
+ * @see Crypt_Base::cipher_name_mcrypt
148
+ * @see Crypt_Base::engine
149
+ * @see isValidEngine()
150
+ * @var string
151
+ * @access private
152
+ */
153
+ var $cipher_name_mcrypt = 'rijndael-128';
154
+
155
+ /**
156
+ * The default salt used by setPassword()
157
+ *
158
+ * @see Crypt_Base::password_default_salt
159
+ * @see Crypt_Base::setPassword()
160
+ * @var string
161
+ * @access private
162
+ */
163
+ var $password_default_salt = 'phpseclib';
164
+
165
+ /**
166
+ * The Key Schedule
167
+ *
168
+ * @see _setup()
169
+ * @var array
170
+ * @access private
171
+ */
172
+ var $w;
173
+
174
+ /**
175
+ * The Inverse Key Schedule
176
+ *
177
+ * @see _setup()
178
+ * @var array
179
+ * @access private
180
+ */
181
+ var $dw;
182
+
183
+ /**
184
+ * The Block Length divided by 32
185
+ *
186
+ * @see setBlockLength()
187
+ * @var int
188
+ * @access private
189
+ * @internal The max value is 256 / 32 = 8, the min value is 128 / 32 = 4. Exists in conjunction with $block_size
190
+ * because the encryption / decryption / key schedule creation requires this number and not $block_size. We could
191
+ * derive this from $block_size or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu
192
+ * of that, we'll just precompute it once.
193
+ */
194
+ var $Nb = 4;
195
+
196
+ /**
197
+ * The Key Length (in bytes)
198
+ *
199
+ * @see setKeyLength()
200
+ * @var int
201
+ * @access private
202
+ * @internal The max value is 256 / 8 = 32, the min value is 128 / 8 = 16. Exists in conjunction with $Nk
203
+ * because the encryption / decryption / key schedule creation requires this number and not $key_length. We could
204
+ * derive this from $key_length or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu
205
+ * of that, we'll just precompute it once.
206
+ */
207
+ var $key_length = 16;
208
+
209
+ /**
210
+ * The Key Length divided by 32
211
+ *
212
+ * @see setKeyLength()
213
+ * @var int
214
+ * @access private
215
+ * @internal The max value is 256 / 32 = 8, the min value is 128 / 32 = 4
216
+ */
217
+ var $Nk = 4;
218
+
219
+ /**
220
+ * The Number of Rounds
221
+ *
222
+ * @var int
223
+ * @access private
224
+ * @internal The max value is 14, the min value is 10.
225
+ */
226
+ var $Nr;
227
+
228
+ /**
229
+ * Shift offsets
230
+ *
231
+ * @var array
232
+ * @access private
233
+ */
234
+ var $c;
235
+
236
+ /**
237
+ * Holds the last used key- and block_size information
238
+ *
239
+ * @var array
240
+ * @access private
241
+ */
242
+ var $kl;
243
+
244
+ /**
245
+ * Default Constructor.
246
+ *
247
+ * Determines whether or not the mcrypt extension should be used.
248
+ *
249
+ * $mode could be:
250
+ *
251
+ * - CRYPT_RIJNDAEL_MODE_ECB
252
+ *
253
+ * - CRYPT_RIJNDAEL_MODE_CBC
254
+ *
255
+ * - CRYPT_RIJNDAEL_MODE_CTR
256
+ *
257
+ * - CRYPT_RIJNDAEL_MODE_CFB
258
+ *
259
+ * - CRYPT_RIJNDAEL_MODE_OFB
260
+ *
261
+ * If not explictly set, CRYPT_RIJNDAEL_MODE_CBC will be used.
262
+ *
263
+ * @see Crypt_Base::Crypt_Base()
264
+ * @param int $mode
265
+ * @access public
266
+ */
267
+ function Crypt_Rijndael($mode = CRYPT_RIJNDAEL_MODE_CBC)
268
+ {
269
+ parent::Crypt_Base($mode);
270
+ }
271
+
272
+ /**
273
+ * Sets the key length.
274
+ *
275
+ * Valid key lengths are 128, 160, 192, 224, and 256. If the length is less than 128, it will be rounded up to
276
+ * 128. If the length is greater than 128 and invalid, it will be rounded down to the closest valid amount.
277
+ *
278
+ * Note: phpseclib extends Rijndael (and AES) for using 160- and 224-bit keys but they are officially not defined
279
+ * and the most (if not all) implementations are not able using 160/224-bit keys but round/pad them up to
280
+ * 192/256 bits as, for example, mcrypt will do.
281
+ *
282
+ * That said, if you want be compatible with other Rijndael and AES implementations,
283
+ * you should not setKeyLength(160) or setKeyLength(224).
284
+ *
285
+ * Additional: In case of 160- and 224-bit keys, phpseclib will/can, for that reason, not use
286
+ * the mcrypt php extension, even if available.
287
+ * This results then in slower encryption.
288
+ *
289
+ * @access public
290
+ * @param int $length
291
+ */
292
+ function setKeyLength($length)
293
+ {
294
+ switch (true) {
295
+ case $length <= 128:
296
+ $this->key_length = 16;
297
+ break;
298
+ case $length <= 160:
299
+ $this->key_length = 20;
300
+ break;
301
+ case $length <= 192:
302
+ $this->key_length = 24;
303
+ break;
304
+ case $length <= 224:
305
+ $this->key_length = 28;
306
+ break;
307
+ default:
308
+ $this->key_length = 32;
309
+ }
310
+
311
+ parent::setKeyLength($length);
312
+ }
313
+
314
+ /**
315
+ * Sets the block length
316
+ *
317
+ * Valid block lengths are 128, 160, 192, 224, and 256. If the length is less than 128, it will be rounded up to
318
+ * 128. If the length is greater than 128 and invalid, it will be rounded down to the closest valid amount.
319
+ *
320
+ * @access public
321
+ * @param int $length
322
+ */
323
+ function setBlockLength($length)
324
+ {
325
+ $length >>= 5;
326
+ if ($length > 8) {
327
+ $length = 8;
328
+ } elseif ($length < 4) {
329
+ $length = 4;
330
+ }
331
+ $this->Nb = $length;
332
+ $this->block_size = $length << 2;
333
+ $this->changed = true;
334
+ $this->_setEngine();
335
+ }
336
+
337
+ /**
338
+ * Test for engine validity
339
+ *
340
+ * This is mainly just a wrapper to set things up for Crypt_Base::isValidEngine()
341
+ *
342
+ * @see Crypt_Base::Crypt_Base()
343
+ * @param int $engine
344
+ * @access public
345
+ * @return bool
346
+ */
347
+ function isValidEngine($engine)
348
+ {
349
+ switch ($engine) {
350
+ case CRYPT_ENGINE_OPENSSL:
351
+ if ($this->block_size != 16) {
352
+ return false;
353
+ }
354
+ $this->cipher_name_openssl_ecb = 'aes-' . ($this->key_length << 3) . '-ecb';
355
+ $this->cipher_name_openssl = 'aes-' . ($this->key_length << 3) . '-' . $this->_openssl_translate_mode();
356
+ break;
357
+ case CRYPT_ENGINE_MCRYPT:
358
+ $this->cipher_name_mcrypt = 'rijndael-' . ($this->block_size << 3);
359
+ if ($this->key_length % 8) { // is it a 160/224-bit key?
360
+ // mcrypt is not usable for them, only for 128/192/256-bit keys
361
+ return false;
362
+ }
363
+ }
364
+
365
+ return parent::isValidEngine($engine);
366
+ }
367
+
368
+ /**
369
+ * Encrypts a block
370
+ *
371
+ * @access private
372
+ * @param string $in
373
+ * @return string
374
+ */
375
+ function _encryptBlock($in)
376
+ {
377
+ static $tables;
378
+ if (empty($tables)) {
379
+ $tables = &$this->_getTables();
380
+ }
381
+ $t0 = $tables[0];
382
+ $t1 = $tables[1];
383
+ $t2 = $tables[2];
384
+ $t3 = $tables[3];
385
+ $sbox = $tables[4];
386
+
387
+ $state = array();
388
+ $words = unpack('N*', $in);
389
+
390
+ $c = $this->c;
391
+ $w = $this->w;
392
+ $Nb = $this->Nb;
393
+ $Nr = $this->Nr;
394
+
395
+ // addRoundKey
396
+ $wc = $Nb - 1;
397
+ foreach ($words as $word) {
398
+ $state[] = $word ^ $w[++$wc];
399
+ }
400
+
401
+ // fips-197.pdf#page=19, "Figure 5. Pseudo Code for the Cipher", states that this loop has four components -
402
+ // subBytes, shiftRows, mixColumns, and addRoundKey. fips-197.pdf#page=30, "Implementation Suggestions Regarding
403
+ // Various Platforms" suggests that performs enhanced implementations are described in Rijndael-ammended.pdf.
404
+ // Rijndael-ammended.pdf#page=20, "Implementation aspects / 32-bit processor", discusses such an optimization.
405
+ // Unfortunately, the description given there is not quite correct. Per aes.spec.v316.pdf#page=19 [1],
406
+ // equation (7.4.7) is supposed to use addition instead of subtraction, so we'll do that here, as well.
407
+
408
+ // [1] http://fp.gladman.plus.com/cryptography_technology/rijndael/aes.spec.v316.pdf
409
+ $temp = array();
410
+ for ($round = 1; $round < $Nr; ++$round) {
411
+ $i = 0; // $c[0] == 0
412
+ $j = $c[1];
413
+ $k = $c[2];
414
+ $l = $c[3];
415
+
416
+ while ($i < $Nb) {
417
+ $temp[$i] = $t0[$state[$i] >> 24 & 0x000000FF] ^
418
+ $t1[$state[$j] >> 16 & 0x000000FF] ^
419
+ $t2[$state[$k] >> 8 & 0x000000FF] ^
420
+ $t3[$state[$l] & 0x000000FF] ^
421
+ $w[++$wc];
422
+ ++$i;
423
+ $j = ($j + 1) % $Nb;
424
+ $k = ($k + 1) % $Nb;
425
+ $l = ($l + 1) % $Nb;
426
+ }
427
+ $state = $temp;
428
+ }
429
+
430
+ // subWord
431
+ for ($i = 0; $i < $Nb; ++$i) {
432
+ $state[$i] = $sbox[$state[$i] & 0x000000FF] |
433
+ ($sbox[$state[$i] >> 8 & 0x000000FF] << 8) |
434
+ ($sbox[$state[$i] >> 16 & 0x000000FF] << 16) |
435
+ ($sbox[$state[$i] >> 24 & 0x000000FF] << 24);
436
+ }
437
+
438
+ // shiftRows + addRoundKey
439
+ $i = 0; // $c[0] == 0
440
+ $j = $c[1];
441
+ $k = $c[2];
442
+ $l = $c[3];
443
+ while ($i < $Nb) {
444
+ $temp[$i] = ($state[$i] & 0xFF000000) ^
445
+ ($state[$j] & 0x00FF0000) ^
446
+ ($state[$k] & 0x0000FF00) ^
447
+ ($state[$l] & 0x000000FF) ^
448
+ $w[$i];
449
+ ++$i;
450
+ $j = ($j + 1) % $Nb;
451
+ $k = ($k + 1) % $Nb;
452
+ $l = ($l + 1) % $Nb;
453
+ }
454
+
455
+ switch ($Nb) {
456
+ case 8:
457
+ return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6], $temp[7]);
458
+ case 7:
459
+ return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6]);
460
+ case 6:
461
+ return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5]);
462
+ case 5:
463
+ return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4]);
464
+ default:
465
+ return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3]);
466
+ }
467
+ }
468
+
469
+ /**
470
+ * Decrypts a block
471
+ *
472
+ * @access private
473
+ * @param string $in
474
+ * @return string
475
+ */
476
+ function _decryptBlock($in)
477
+ {
478
+ static $invtables;
479
+ if (empty($invtables)) {
480
+ $invtables = &$this->_getInvTables();
481
+ }
482
+ $dt0 = $invtables[0];
483
+ $dt1 = $invtables[1];
484
+ $dt2 = $invtables[2];
485
+ $dt3 = $invtables[3];
486
+ $isbox = $invtables[4];
487
+
488
+ $state = array();
489
+ $words = unpack('N*', $in);
490
+
491
+ $c = $this->c;
492
+ $dw = $this->dw;
493
+ $Nb = $this->Nb;
494
+ $Nr = $this->Nr;
495
+
496
+ // addRoundKey
497
+ $wc = $Nb - 1;
498
+ foreach ($words as $word) {
499
+ $state[] = $word ^ $dw[++$wc];
500
+ }
501
+
502
+ $temp = array();
503
+ for ($round = $Nr - 1; $round > 0; --$round) {
504
+ $i = 0; // $c[0] == 0
505
+ $j = $Nb - $c[1];
506
+ $k = $Nb - $c[2];
507
+ $l = $Nb - $c[3];
508
+
509
+ while ($i < $Nb) {
510
+ $temp[$i] = $dt0[$state[$i] >> 24 & 0x000000FF] ^
511
+ $dt1[$state[$j] >> 16 & 0x000000FF] ^
512
+ $dt2[$state[$k] >> 8 & 0x000000FF] ^
513
+ $dt3[$state[$l] & 0x000000FF] ^
514
+ $dw[++$wc];
515
+ ++$i;
516
+ $j = ($j + 1) % $Nb;
517
+ $k = ($k + 1) % $Nb;
518
+ $l = ($l + 1) % $Nb;
519
+ }
520
+ $state = $temp;
521
+ }
522
+
523
+ // invShiftRows + invSubWord + addRoundKey
524
+ $i = 0; // $c[0] == 0
525
+ $j = $Nb - $c[1];
526
+ $k = $Nb - $c[2];
527
+ $l = $Nb - $c[3];
528
+
529
+ while ($i < $Nb) {
530
+ $word = ($state[$i] & 0xFF000000) |
531
+ ($state[$j] & 0x00FF0000) |
532
+ ($state[$k] & 0x0000FF00) |
533
+ ($state[$l] & 0x000000FF);
534
+
535
+ $temp[$i] = $dw[$i] ^ ($isbox[$word & 0x000000FF] |
536
+ ($isbox[$word >> 8 & 0x000000FF] << 8) |
537
+ ($isbox[$word >> 16 & 0x000000FF] << 16) |
538
+ ($isbox[$word >> 24 & 0x000000FF] << 24));
539
+ ++$i;
540
+ $j = ($j + 1) % $Nb;
541
+ $k = ($k + 1) % $Nb;
542
+ $l = ($l + 1) % $Nb;
543
+ }
544
+
545
+ switch ($Nb) {
546
+ case 8:
547
+ return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6], $temp[7]);
548
+ case 7:
549
+ return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6]);
550
+ case 6:
551
+ return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5]);
552
+ case 5:
553
+ return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4]);
554
+ default:
555
+ return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3]);
556
+ }
557
+ }
558
+
559
+ /**
560
+ * Setup the key (expansion)
561
+ *
562
+ * @see Crypt_Base::_setupKey()
563
+ * @access private
564
+ */
565
+ function _setupKey()
566
+ {
567
+ // Each number in $rcon is equal to the previous number multiplied by two in Rijndael's finite field.
568
+ // See http://en.wikipedia.org/wiki/Finite_field_arithmetic#Multiplicative_inverse
569
+ static $rcon = array(0,
570
+ 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000,
571
+ 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000,
572
+ 0x6C000000, 0xD8000000, 0xAB000000, 0x4D000000, 0x9A000000,
573
+ 0x2F000000, 0x5E000000, 0xBC000000, 0x63000000, 0xC6000000,
574
+ 0x97000000, 0x35000000, 0x6A000000, 0xD4000000, 0xB3000000,
575
+ 0x7D000000, 0xFA000000, 0xEF000000, 0xC5000000, 0x91000000
576
+ );
577
+
578
+ if (isset($this->kl['key']) && $this->key === $this->kl['key'] && $this->key_length === $this->kl['key_length'] && $this->block_size === $this->kl['block_size']) {
579
+ // already expanded
580
+ return;
581
+ }
582
+ $this->kl = array('key' => $this->key, 'key_length' => $this->key_length, 'block_size' => $this->block_size);
583
+
584
+ $this->Nk = $this->key_length >> 2;
585
+ // see Rijndael-ammended.pdf#page=44
586
+ $this->Nr = max($this->Nk, $this->Nb) + 6;
587
+
588
+ // shift offsets for Nb = 5, 7 are defined in Rijndael-ammended.pdf#page=44,
589
+ // "Table 8: Shift offsets in Shiftrow for the alternative block lengths"
590
+ // shift offsets for Nb = 4, 6, 8 are defined in Rijndael-ammended.pdf#page=14,
591
+ // "Table 2: Shift offsets for different block lengths"
592
+ switch ($this->Nb) {
593
+ case 4:
594
+ case 5:
595
+ case 6:
596
+ $this->c = array(0, 1, 2, 3);
597
+ break;
598
+ case 7:
599
+ $this->c = array(0, 1, 2, 4);
600
+ break;
601
+ case 8:
602
+ $this->c = array(0, 1, 3, 4);
603
+ }
604
+
605
+ $w = array_values(unpack('N*words', $this->key));
606
+
607
+ $length = $this->Nb * ($this->Nr + 1);
608
+ for ($i = $this->Nk; $i < $length; $i++) {
609
+ $temp = $w[$i - 1];
610
+ if ($i % $this->Nk == 0) {
611
+ // according to <http://php.net/language.types.integer>, "the size of an integer is platform-dependent".
612
+ // on a 32-bit machine, it's 32-bits, and on a 64-bit machine, it's 64-bits. on a 32-bit machine,
613
+ // 0xFFFFFFFF << 8 == 0xFFFFFF00, but on a 64-bit machine, it equals 0xFFFFFFFF00. as such, doing 'and'
614
+ // with 0xFFFFFFFF (or 0xFFFFFF00) on a 32-bit machine is unnecessary, but on a 64-bit machine, it is.
615
+ $temp = (($temp << 8) & 0xFFFFFF00) | (($temp >> 24) & 0x000000FF); // rotWord
616
+ $temp = $this->_subWord($temp) ^ $rcon[$i / $this->Nk];
617
+ } elseif ($this->Nk > 6 && $i % $this->Nk == 4) {
618
+ $temp = $this->_subWord($temp);
619
+ }
620
+ $w[$i] = $w[$i - $this->Nk] ^ $temp;
621
+ }
622
+
623
+ // convert the key schedule from a vector of $Nb * ($Nr + 1) length to a matrix with $Nr + 1 rows and $Nb columns
624
+ // and generate the inverse key schedule. more specifically,
625
+ // according to <http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=23> (section 5.3.3),
626
+ // "The key expansion for the Inverse Cipher is defined as follows:
627
+ // 1. Apply the Key Expansion.
628
+ // 2. Apply InvMixColumn to all Round Keys except the first and the last one."
629
+ // also, see fips-197.pdf#page=27, "5.3.5 Equivalent Inverse Cipher"
630
+ list($dt0, $dt1, $dt2, $dt3) = $this->_getInvTables();
631
+ $temp = $this->w = $this->dw = array();
632
+ for ($i = $row = $col = 0; $i < $length; $i++, $col++) {
633
+ if ($col == $this->Nb) {
634
+ if ($row == 0) {
635
+ $this->dw[0] = $this->w[0];
636
+ } else {
637
+ // subWord + invMixColumn + invSubWord = invMixColumn
638
+ $j = 0;
639
+ while ($j < $this->Nb) {
640
+ $dw = $this->_subWord($this->w[$row][$j]);
641
+ $temp[$j] = $dt0[$dw >> 24 & 0x000000FF] ^
642
+ $dt1[$dw >> 16 & 0x000000FF] ^
643
+ $dt2[$dw >> 8 & 0x000000FF] ^
644
+ $dt3[$dw & 0x000000FF];
645
+ $j++;
646
+ }
647
+ $this->dw[$row] = $temp;
648
+ }
649
+
650
+ $col = 0;
651
+ $row++;
652
+ }
653
+ $this->w[$row][$col] = $w[$i];
654
+ }
655
+
656
+ $this->dw[$row] = $this->w[$row];
657
+
658
+ // Converting to 1-dim key arrays (both ascending)
659
+ $this->dw = array_reverse($this->dw);
660
+ $w = array_pop($this->w);
661
+ $dw = array_pop($this->dw);
662
+ foreach ($this->w as $r => $wr) {
663
+ foreach ($wr as $c => $wc) {
664
+ $w[] = $wc;
665
+ $dw[] = $this->dw[$r][$c];
666
+ }
667
+ }
668
+ $this->w = $w;
669
+ $this->dw = $dw;
670
+ }
671
+
672
+ /**
673
+ * Performs S-Box substitutions
674
+ *
675
+ * @access private
676
+ * @param int $word
677
+ */
678
+ function _subWord($word)
679
+ {
680
+ static $sbox;
681
+ if (empty($sbox)) {
682
+ list(, , , , $sbox) = $this->_getTables();
683
+ }
684
+
685
+ return $sbox[$word & 0x000000FF] |
686
+ ($sbox[$word >> 8 & 0x000000FF] << 8) |
687
+ ($sbox[$word >> 16 & 0x000000FF] << 16) |
688
+ ($sbox[$word >> 24 & 0x000000FF] << 24);
689
+ }
690
+
691
+ /**
692
+ * Provides the mixColumns and sboxes tables
693
+ *
694
+ * @see Crypt_Rijndael:_encryptBlock()
695
+ * @see Crypt_Rijndael:_setupInlineCrypt()
696
+ * @see Crypt_Rijndael:_subWord()
697
+ * @access private
698
+ * @return array &$tables
699
+ */
700
+ function &_getTables()
701
+ {
702
+ static $tables;
703
+ if (empty($tables)) {
704
+ // according to <http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=19> (section 5.2.1),
705
+ // precomputed tables can be used in the mixColumns phase. in that example, they're assigned t0...t3, so
706
+ // those are the names we'll use.
707
+ $t3 = array_map('intval', array(
708
+ // with array_map('intval', ...) we ensure we have only int's and not
709
+ // some slower floats converted by php automatically on high values
710
+ 0x6363A5C6, 0x7C7C84F8, 0x777799EE, 0x7B7B8DF6, 0xF2F20DFF, 0x6B6BBDD6, 0x6F6FB1DE, 0xC5C55491,
711
+ 0x30305060, 0x01010302, 0x6767A9CE, 0x2B2B7D56, 0xFEFE19E7, 0xD7D762B5, 0xABABE64D, 0x76769AEC,
712
+ 0xCACA458F, 0x82829D1F, 0xC9C94089, 0x7D7D87FA, 0xFAFA15EF, 0x5959EBB2, 0x4747C98E, 0xF0F00BFB,
713
+ 0xADADEC41, 0xD4D467B3, 0xA2A2FD5F, 0xAFAFEA45, 0x9C9CBF23, 0xA4A4F753, 0x727296E4, 0xC0C05B9B,
714
+ 0xB7B7C275, 0xFDFD1CE1, 0x9393AE3D, 0x26266A4C, 0x36365A6C, 0x3F3F417E, 0xF7F702F5, 0xCCCC4F83,
715
+ 0x34345C68, 0xA5A5F451, 0xE5E534D1, 0xF1F108F9, 0x717193E2, 0xD8D873AB, 0x31315362, 0x15153F2A,
716
+ 0x04040C08, 0xC7C75295, 0x23236546, 0xC3C35E9D, 0x18182830, 0x9696A137, 0x05050F0A, 0x9A9AB52F,
717
+ 0x0707090E, 0x12123624, 0x80809B1B, 0xE2E23DDF, 0xEBEB26CD, 0x2727694E, 0xB2B2CD7F, 0x75759FEA,
718
+ 0x09091B12, 0x83839E1D, 0x2C2C7458, 0x1A1A2E34, 0x1B1B2D36, 0x6E6EB2DC, 0x5A5AEEB4, 0xA0A0FB5B,
719
+ 0x5252F6A4, 0x3B3B4D76, 0xD6D661B7, 0xB3B3CE7D, 0x29297B52, 0xE3E33EDD, 0x2F2F715E, 0x84849713,
720
+ 0x5353F5A6, 0xD1D168B9, 0x00000000, 0xEDED2CC1, 0x20206040, 0xFCFC1FE3, 0xB1B1C879, 0x5B5BEDB6,
721
+ 0x6A6ABED4, 0xCBCB468D, 0xBEBED967, 0x39394B72, 0x4A4ADE94, 0x4C4CD498, 0x5858E8B0, 0xCFCF4A85,
722
+ 0xD0D06BBB, 0xEFEF2AC5, 0xAAAAE54F, 0xFBFB16ED, 0x4343C586, 0x4D4DD79A, 0x33335566, 0x85859411,
723
+ 0x4545CF8A, 0xF9F910E9, 0x02020604, 0x7F7F81FE, 0x5050F0A0, 0x3C3C4478, 0x9F9FBA25, 0xA8A8E34B,
724
+ 0x5151F3A2, 0xA3A3FE5D, 0x4040C080, 0x8F8F8A05, 0x9292AD3F, 0x9D9DBC21, 0x38384870, 0xF5F504F1,
725
+ 0xBCBCDF63, 0xB6B6C177, 0xDADA75AF, 0x21216342, 0x10103020, 0xFFFF1AE5, 0xF3F30EFD, 0xD2D26DBF,
726
+ 0xCDCD4C81, 0x0C0C1418, 0x13133526, 0xECEC2FC3, 0x5F5FE1BE, 0x9797A235, 0x4444CC88, 0x1717392E,
727
+ 0xC4C45793, 0xA7A7F255, 0x7E7E82FC, 0x3D3D477A, 0x6464ACC8, 0x5D5DE7BA, 0x19192B32, 0x737395E6,
728
+ 0x6060A0C0, 0x81819819, 0x4F4FD19E, 0xDCDC7FA3, 0x22226644, 0x2A2A7E54, 0x9090AB3B, 0x8888830B,
729
+ 0x4646CA8C, 0xEEEE29C7, 0xB8B8D36B, 0x14143C28, 0xDEDE79A7, 0x5E5EE2BC, 0x0B0B1D16, 0xDBDB76AD,
730
+ 0xE0E03BDB, 0x32325664, 0x3A3A4E74, 0x0A0A1E14, 0x4949DB92, 0x06060A0C, 0x24246C48, 0x5C5CE4B8,
731
+ 0xC2C25D9F, 0xD3D36EBD, 0xACACEF43, 0x6262A6C4, 0x9191A839, 0x9595A431, 0xE4E437D3, 0x79798BF2,
732
+ 0xE7E732D5, 0xC8C8438B, 0x3737596E, 0x6D6DB7DA, 0x8D8D8C01, 0xD5D564B1, 0x4E4ED29C, 0xA9A9E049,
733
+ 0x6C6CB4D8, 0x5656FAAC, 0xF4F407F3, 0xEAEA25CF, 0x6565AFCA, 0x7A7A8EF4, 0xAEAEE947, 0x08081810,
734
+ 0xBABAD56F, 0x787888F0, 0x25256F4A, 0x2E2E725C, 0x1C1C2438, 0xA6A6F157, 0xB4B4C773, 0xC6C65197,
735
+ 0xE8E823CB, 0xDDDD7CA1, 0x74749CE8, 0x1F1F213E, 0x4B4BDD96, 0xBDBDDC61, 0x8B8B860D, 0x8A8A850F,
736
+ 0x707090E0, 0x3E3E427C, 0xB5B5C471, 0x6666AACC, 0x4848D890, 0x03030506, 0xF6F601F7, 0x0E0E121C,
737
+ 0x6161A3C2, 0x35355F6A, 0x5757F9AE, 0xB9B9D069, 0x86869117, 0xC1C15899, 0x1D1D273A, 0x9E9EB927,
738
+ 0xE1E138D9, 0xF8F813EB, 0x9898B32B, 0x11113322, 0x6969BBD2, 0xD9D970A9, 0x8E8E8907, 0x9494A733,
739
+ 0x9B9BB62D, 0x1E1E223C, 0x87879215, 0xE9E920C9, 0xCECE4987, 0x5555FFAA, 0x28287850, 0xDFDF7AA5,
740
+ 0x8C8C8F03, 0xA1A1F859, 0x89898009, 0x0D0D171A, 0xBFBFDA65, 0xE6E631D7, 0x4242C684, 0x6868B8D0,
741
+ 0x4141C382, 0x9999B029, 0x2D2D775A, 0x0F0F111E, 0xB0B0CB7B, 0x5454FCA8, 0xBBBBD66D, 0x16163A2C
742
+ ));
743
+
744
+ foreach ($t3 as $t3i) {
745
+ $t0[] = (($t3i << 24) & 0xFF000000) | (($t3i >> 8) & 0x00FFFFFF);
746
+ $t1[] = (($t3i << 16) & 0xFFFF0000) | (($t3i >> 16) & 0x0000FFFF);
747
+ $t2[] = (($t3i << 8) & 0xFFFFFF00) | (($t3i >> 24) & 0x000000FF);
748
+ }
749
+
750
+ $tables = array(
751
+ // The Precomputed mixColumns tables t0 - t3
752
+ $t0,
753
+ $t1,
754
+ $t2,
755
+ $t3,
756
+ // The SubByte S-Box
757
+ array(
758
+ 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
759
+ 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
760
+ 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
761
+ 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
762
+ 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
763
+ 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
764
+ 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
765
+ 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
766
+ 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
767
+ 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
768
+ 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
769
+ 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
770
+ 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
771
+ 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
772
+ 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
773
+ 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
774
+ )
775
+ );
776
+ }
777
+ return $tables;
778
+ }
779
+
780
+ /**
781
+ * Provides the inverse mixColumns and inverse sboxes tables
782
+ *
783
+ * @see Crypt_Rijndael:_decryptBlock()
784
+ * @see Crypt_Rijndael:_setupInlineCrypt()
785
+ * @see Crypt_Rijndael:_setupKey()
786
+ * @access private
787
+ * @return array &$tables
788
+ */
789
+ function &_getInvTables()
790
+ {
791
+ static $tables;
792
+ if (empty($tables)) {
793
+ $dt3 = array_map('intval', array(
794
+ 0xF4A75051, 0x4165537E, 0x17A4C31A, 0x275E963A, 0xAB6BCB3B, 0x9D45F11F, 0xFA58ABAC, 0xE303934B,
795
+ 0x30FA5520, 0x766DF6AD, 0xCC769188, 0x024C25F5, 0xE5D7FC4F, 0x2ACBD7C5, 0x35448026, 0x62A38FB5,
796
+ 0xB15A49DE, 0xBA1B6725, 0xEA0E9845, 0xFEC0E15D, 0x2F7502C3, 0x4CF01281, 0x4697A38D, 0xD3F9C66B,
797
+ 0x8F5FE703, 0x929C9515, 0x6D7AEBBF, 0x5259DA95, 0xBE832DD4, 0x7421D358, 0xE0692949, 0xC9C8448E,
798
+ 0xC2896A75, 0x8E7978F4, 0x583E6B99, 0xB971DD27, 0xE14FB6BE, 0x88AD17F0, 0x20AC66C9, 0xCE3AB47D,
799
+ 0xDF4A1863, 0x1A3182E5, 0x51336097, 0x537F4562, 0x6477E0B1, 0x6BAE84BB, 0x81A01CFE, 0x082B94F9,
800
+ 0x48685870, 0x45FD198F, 0xDE6C8794, 0x7BF8B752, 0x73D323AB, 0x4B02E272, 0x1F8F57E3, 0x55AB2A66,
801
+ 0xEB2807B2, 0xB5C2032F, 0xC57B9A86, 0x3708A5D3, 0x2887F230, 0xBFA5B223, 0x036ABA02, 0x16825CED,
802
+ 0xCF1C2B8A, 0x79B492A7, 0x07F2F0F3, 0x69E2A14E, 0xDAF4CD65, 0x05BED506, 0x34621FD1, 0xA6FE8AC4,
803
+ 0x2E539D34, 0xF355A0A2, 0x8AE13205, 0xF6EB75A4, 0x83EC390B, 0x60EFAA40, 0x719F065E, 0x6E1051BD,
804
+ 0x218AF93E, 0xDD063D96, 0x3E05AEDD, 0xE6BD464D, 0x548DB591, 0xC45D0571, 0x06D46F04, 0x5015FF60,
805
+ 0x98FB2419, 0xBDE997D6, 0x4043CC89, 0xD99E7767, 0xE842BDB0, 0x898B8807, 0x195B38E7, 0xC8EEDB79,
806
+ 0x7C0A47A1, 0x420FE97C, 0x841EC9F8, 0x00000000, 0x80868309, 0x2BED4832, 0x1170AC1E, 0x5A724E6C,
807
+ 0x0EFFFBFD, 0x8538560F, 0xAED51E3D, 0x2D392736, 0x0FD9640A, 0x5CA62168, 0x5B54D19B, 0x362E3A24,
808
+ 0x0A67B10C, 0x57E70F93, 0xEE96D2B4, 0x9B919E1B, 0xC0C54F80, 0xDC20A261, 0x774B695A, 0x121A161C,
809
+ 0x93BA0AE2, 0xA02AE5C0, 0x22E0433C, 0x1B171D12, 0x090D0B0E, 0x8BC7ADF2, 0xB6A8B92D, 0x1EA9C814,
810
+ 0xF1198557, 0x75074CAF, 0x99DDBBEE, 0x7F60FDA3, 0x01269FF7, 0x72F5BC5C, 0x663BC544, 0xFB7E345B,
811
+ 0x4329768B, 0x23C6DCCB, 0xEDFC68B6, 0xE4F163B8, 0x31DCCAD7, 0x63851042, 0x97224013, 0xC6112084,
812
+ 0x4A247D85, 0xBB3DF8D2, 0xF93211AE, 0x29A16DC7, 0x9E2F4B1D, 0xB230F3DC, 0x8652EC0D, 0xC1E3D077,
813
+ 0xB3166C2B, 0x70B999A9, 0x9448FA11, 0xE9642247, 0xFC8CC4A8, 0xF03F1AA0, 0x7D2CD856, 0x3390EF22,
814
+ 0x494EC787, 0x38D1C1D9, 0xCAA2FE8C, 0xD40B3698, 0xF581CFA6, 0x7ADE28A5, 0xB78E26DA, 0xADBFA43F,
815
+ 0x3A9DE42C, 0x78920D50, 0x5FCC9B6A, 0x7E466254, 0x8D13C2F6, 0xD8B8E890, 0x39F75E2E, 0xC3AFF582,
816
+ 0x5D80BE9F, 0xD0937C69, 0xD52DA96F, 0x2512B3CF, 0xAC993BC8, 0x187DA710, 0x9C636EE8, 0x3BBB7BDB,
817
+ 0x267809CD, 0x5918F46E, 0x9AB701EC, 0x4F9AA883, 0x956E65E6, 0xFFE67EAA, 0xBCCF0821, 0x15E8E6EF,
818
+ 0xE79BD9BA, 0x6F36CE4A, 0x9F09D4EA, 0xB07CD629, 0xA4B2AF31, 0x3F23312A, 0xA59430C6, 0xA266C035,
819
+ 0x4EBC3774, 0x82CAA6FC, 0x90D0B0E0, 0xA7D81533, 0x04984AF1, 0xECDAF741, 0xCD500E7F, 0x91F62F17,
820
+ 0x4DD68D76, 0xEFB04D43, 0xAA4D54CC, 0x9604DFE4, 0xD1B5E39E, 0x6A881B4C, 0x2C1FB8C1, 0x65517F46,
821
+ 0x5EEA049D, 0x8C355D01, 0x877473FA, 0x0B412EFB, 0x671D5AB3, 0xDBD25292, 0x105633E9, 0xD647136D,
822
+ 0xD7618C9A, 0xA10C7A37, 0xF8148E59, 0x133C89EB, 0xA927EECE, 0x61C935B7, 0x1CE5EDE1, 0x47B13C7A,
823
+ 0xD2DF599C, 0xF2733F55, 0x14CE7918, 0xC737BF73, 0xF7CDEA53, 0xFDAA5B5F, 0x3D6F14DF, 0x44DB8678,
824
+ 0xAFF381CA, 0x68C43EB9, 0x24342C38, 0xA3405FC2, 0x1DC37216, 0xE2250CBC, 0x3C498B28, 0x0D9541FF,
825
+ 0xA8017139, 0x0CB3DE08, 0xB4E49CD8, 0x56C19064, 0xCB84617B, 0x32B670D5, 0x6C5C7448, 0xB85742D0
826
+ ));
827
+
828
+ foreach ($dt3 as $dt3i) {
829
+ $dt0[] = (($dt3i << 24) & 0xFF000000) | (($dt3i >> 8) & 0x00FFFFFF);
830
+ $dt1[] = (($dt3i << 16) & 0xFFFF0000) | (($dt3i >> 16) & 0x0000FFFF);
831
+ $dt2[] = (($dt3i << 8) & 0xFFFFFF00) | (($dt3i >> 24) & 0x000000FF);
832
+ };
833
+
834
+ $tables = array(
835
+ // The Precomputed inverse mixColumns tables dt0 - dt3
836
+ $dt0,
837
+ $dt1,
838
+ $dt2,
839
+ $dt3,
840
+ // The inverse SubByte S-Box
841
+ array(
842
+ 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB,
843
+ 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB,
844
+ 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
845
+ 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25,
846
+ 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92,
847
+ 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
848
+ 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06,
849
+ 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B,
850
+ 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
851
+ 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E,
852
+ 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B,
853
+ 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
854
+ 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F,
855
+ 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF,
856
+ 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
857
+ 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D
858
+ )
859
+ );
860
+ }
861
+ return $tables;
862
+ }
863
+
864
+ /**
865
+ * Setup the performance-optimized function for de/encrypt()
866
+ *
867
+ * @see Crypt_Base::_setupInlineCrypt()
868
+ * @access private
869
+ */
870
+ function _setupInlineCrypt()
871
+ {
872
+ // Note: _setupInlineCrypt() will be called only if $this->changed === true
873
+ // So here we are'nt under the same heavy timing-stress as we are in _de/encryptBlock() or de/encrypt().
874
+ // However...the here generated function- $code, stored as php callback in $this->inline_crypt, must work as fast as even possible.
875
+
876
+ $lambda_functions =& Crypt_Rijndael::_getLambdaFunctions();
877
+
878
+ // We create max. 10 hi-optimized code for memory reason. Means: For each $key one ultra fast inline-crypt function.
879
+ // (Currently, for Crypt_Rijndael/AES, one generated $lambda_function cost on php5.5@32bit ~80kb unfreeable mem and ~130kb on php5.5@64bit)
880
+ // After that, we'll still create very fast optimized code but not the hi-ultimative code, for each $mode one.
881
+ $gen_hi_opt_code = (bool)(count($lambda_functions) < 10);
882
+
883
+ // Generation of a uniqe hash for our generated code
884
+ $code_hash = "Crypt_Rijndael, {$this->mode}, {$this->Nr}, {$this->Nb}";
885
+ if ($gen_hi_opt_code) {
886
+ $code_hash = str_pad($code_hash, 32) . $this->_hashInlineCryptFunction($this->key);
887
+ }
888
+
889
+ if (!isset($lambda_functions[$code_hash])) {
890
+ switch (true) {
891
+ case $gen_hi_opt_code:
892
+ // The hi-optimized $lambda_functions will use the key-words hardcoded for better performance.
893
+ $w = $this->w;
894
+ $dw = $this->dw;
895
+ $init_encrypt = '';
896
+ $init_decrypt = '';
897
+ break;
898
+ default:
899
+ for ($i = 0, $cw = count($this->w); $i < $cw; ++$i) {
900
+ $w[] = '$w[' . $i . ']';
901
+ $dw[] = '$dw[' . $i . ']';
902
+ }
903
+ $init_encrypt = '$w = $self->w;';
904
+ $init_decrypt = '$dw = $self->dw;';
905
+ }
906
+
907
+ $Nr = $this->Nr;
908
+ $Nb = $this->Nb;
909
+ $c = $this->c;
910
+
911
+ // Generating encrypt code:
912
+ $init_encrypt.= '
913
+ static $tables;
914
+ if (empty($tables)) {
915
+ $tables = &$self->_getTables();
916
+ }
917
+ $t0 = $tables[0];
918
+ $t1 = $tables[1];
919
+ $t2 = $tables[2];
920
+ $t3 = $tables[3];
921
+ $sbox = $tables[4];
922
+ ';
923
+
924
+ $s = 'e';
925
+ $e = 's';
926
+ $wc = $Nb - 1;
927
+
928
+ // Preround: addRoundKey
929
+ $encrypt_block = '$in = unpack("N*", $in);'."\n";
930
+ for ($i = 0; $i < $Nb; ++$i) {
931
+ $encrypt_block .= '$s'.$i.' = $in['.($i + 1).'] ^ '.$w[++$wc].";\n";
932
+ }
933
+
934
+ // Mainrounds: shiftRows + subWord + mixColumns + addRoundKey
935
+ for ($round = 1; $round < $Nr; ++$round) {
936
+ list($s, $e) = array($e, $s);
937
+ for ($i = 0; $i < $Nb; ++$i) {
938
+ $encrypt_block.=
939
+ '$'.$e.$i.' =
940
+ $t0[($'.$s.$i .' >> 24) & 0xff] ^
941
+ $t1[($'.$s.(($i + $c[1]) % $Nb).' >> 16) & 0xff] ^
942
+ $t2[($'.$s.(($i + $c[2]) % $Nb).' >> 8) & 0xff] ^
943
+ $t3[ $'.$s.(($i + $c[3]) % $Nb).' & 0xff] ^
944
+ '.$w[++$wc].";\n";
945
+ }
946
+ }
947
+
948
+ // Finalround: subWord + shiftRows + addRoundKey
949
+ for ($i = 0; $i < $Nb; ++$i) {
950
+ $encrypt_block.=
951
+ '$'.$e.$i.' =
952
+ $sbox[ $'.$e.$i.' & 0xff] |
953
+ ($sbox[($'.$e.$i.' >> 8) & 0xff] << 8) |
954
+ ($sbox[($'.$e.$i.' >> 16) & 0xff] << 16) |
955
+ ($sbox[($'.$e.$i.' >> 24) & 0xff] << 24);'."\n";
956
+ }
957
+ $encrypt_block .= '$in = pack("N*"'."\n";
958
+ for ($i = 0; $i < $Nb; ++$i) {
959
+ $encrypt_block.= ',
960
+ ($'.$e.$i .' & '.((int)0xFF000000).') ^
961
+ ($'.$e.(($i + $c[1]) % $Nb).' & 0x00FF0000 ) ^
962
+ ($'.$e.(($i + $c[2]) % $Nb).' & 0x0000FF00 ) ^
963
+ ($'.$e.(($i + $c[3]) % $Nb).' & 0x000000FF ) ^
964
+ '.$w[$i]."\n";
965
+ }
966
+ $encrypt_block .= ');';
967
+
968
+ // Generating decrypt code:
969
+ $init_decrypt.= '
970
+ static $invtables;
971
+ if (empty($invtables)) {
972
+ $invtables = &$self->_getInvTables();
973
+ }
974
+ $dt0 = $invtables[0];
975
+ $dt1 = $invtables[1];
976
+ $dt2 = $invtables[2];
977
+ $dt3 = $invtables[3];
978
+ $isbox = $invtables[4];
979
+ ';
980
+
981
+ $s = 'e';
982
+ $e = 's';
983
+ $wc = $Nb - 1;
984
+
985
+ // Preround: addRoundKey
986
+ $decrypt_block = '$in = unpack("N*", $in);'."\n";
987
+ for ($i = 0; $i < $Nb; ++$i) {
988
+ $decrypt_block .= '$s'.$i.' = $in['.($i + 1).'] ^ '.$dw[++$wc].';'."\n";
989
+ }
990
+
991
+ // Mainrounds: shiftRows + subWord + mixColumns + addRoundKey
992
+ for ($round = 1; $round < $Nr; ++$round) {
993
+ list($s, $e) = array($e, $s);
994
+ for ($i = 0; $i < $Nb; ++$i) {
995
+ $decrypt_block.=
996
+ '$'.$e.$i.' =
997
+ $dt0[($'.$s.$i .' >> 24) & 0xff] ^
998
+ $dt1[($'.$s.(($Nb + $i - $c[1]) % $Nb).' >> 16) & 0xff] ^
999
+ $dt2[($'.$s.(($Nb + $i - $c[2]) % $Nb).' >> 8) & 0xff] ^
1000
+ $dt3[ $'.$s.(($Nb + $i - $c[3]) % $Nb).' & 0xff] ^
1001
+ '.$dw[++$wc].";\n";
1002
+ }
1003
+ }
1004
+
1005
+ // Finalround: subWord + shiftRows + addRoundKey
1006
+ for ($i = 0; $i < $Nb; ++$i) {
1007
+ $decrypt_block.=
1008
+ '$'.$e.$i.' =
1009
+ $isbox[ $'.$e.$i.' & 0xff] |
1010
+ ($isbox[($'.$e.$i.' >> 8) & 0xff] << 8) |
1011
+ ($isbox[($'.$e.$i.' >> 16) & 0xff] << 16) |
1012
+ ($isbox[($'.$e.$i.' >> 24) & 0xff] << 24);'."\n";
1013
+ }
1014
+ $decrypt_block .= '$in = pack("N*"'."\n";
1015
+ for ($i = 0; $i < $Nb; ++$i) {
1016
+ $decrypt_block.= ',
1017
+ ($'.$e.$i. ' & '.((int)0xFF000000).') ^
1018
+ ($'.$e.(($Nb + $i - $c[1]) % $Nb).' & 0x00FF0000 ) ^
1019
+ ($'.$e.(($Nb + $i - $c[2]) % $Nb).' & 0x0000FF00 ) ^
1020
+ ($'.$e.(($Nb + $i - $c[3]) % $Nb).' & 0x000000FF ) ^
1021
+ '.$dw[$i]."\n";
1022
+ }
1023
+ $decrypt_block .= ');';
1024
+
1025
+ $lambda_functions[$code_hash] = $this->_createInlineCryptFunction(
1026
+ array(
1027
+ 'init_crypt' => '',
1028
+ 'init_encrypt' => $init_encrypt,
1029
+ 'init_decrypt' => $init_decrypt,
1030
+ 'encrypt_block' => $encrypt_block,
1031
+ 'decrypt_block' => $decrypt_block
1032
+ )
1033
+ );
1034
+ }
1035
+ $this->inline_crypt = $lambda_functions[$code_hash];
1036
+ }
1037
+ }
readme.txt CHANGED
@@ -3,7 +3,7 @@ Contributors: ecwid
3
  Tags: ecwid, shopping cart, ecommerce, wordpress ecommerce, wp e-commerce, paypal, e-commerce, online store, store, shop, cart, online shop, shopping, digital goods, downloadable products, product catalog, ecomerce, products, facebook, f-commerce
4
  Requires at least: 2.8
5
  Tested up to: 4.3
6
- Stable tag: 3.4.2
7
 
8
  Ecwid is a full-featured shopping cart that can be added to any Wordpress site in less than 5 minutes. Start using Ecwid for free today.
9
 
@@ -107,6 +107,14 @@ http://codex.wordpress.org/Managing_Plugins#Installing_Plugins
107
  * [Ecwid site](http://www.ecwid.com/?source=wporg-plugin-site "Ecwid Site")
108
 
109
  == Changelog ==
 
 
 
 
 
 
 
 
110
  = 3.4.2 =
111
  - Fixed option to enable the new categories widget released in the v.3.4 .
112
 
3
  Tags: ecwid, shopping cart, ecommerce, wordpress ecommerce, wp e-commerce, paypal, e-commerce, online store, store, shop, cart, online shop, shopping, digital goods, downloadable products, product catalog, ecomerce, products, facebook, f-commerce
4
  Requires at least: 2.8
5
  Tested up to: 4.3
6
+ Stable tag: 3.4.4
7
 
8
  Ecwid is a full-featured shopping cart that can be added to any Wordpress site in less than 5 minutes. Start using Ecwid for free today.
9
 
107
  * [Ecwid site](http://www.ecwid.com/?source=wporg-plugin-site "Ecwid Site")
108
 
109
  == Changelog ==
110
+ = 3.4.4 =
111
+ - **Added compatibility with the "Add Meta Tags" plugin.** The "Add Meta Tags" plugin is a popular tool to set SEO meta tags on site pages. Previously it rewrote the titles and description that Ecwid generated for search engines on your site. It's now fixed so if you use the plugin, everything should work fine and Google will index your products pages properly.
112
+ - **Fixed a problem in the recently viewed products widget caused by Autoptimize plugin.** Previously, if Autoptimize plugin is used on the site, the recently viewed products widget reset the displayed products when page reloads. We fixed that.
113
+ - **A few internal improvements** to make the plugin more stable and ready for the upcoming cool features. Stay tuned! More updates are coming.
114
+
115
+ = 3.4.3 =
116
+ - Updated Italian and Turkish translations.
117
+
118
  = 3.4.2 =
119
  - Fixed option to enable the new categories widget released in the v.3.4 .
120
 
templates/connect.php CHANGED
@@ -48,5 +48,5 @@
48
  </a>
49
  </div>
50
  </div>
51
- <p><?php echo sprintf(__('Questions? Visit <a %s>Ecwid support center</a>', 'ecwid-shopping-cart'), 'target="_blank" href="http://help.ecwid.com/?source=wporg"'); ?></p>
52
  </div>
48
  </a>
49
  </div>
50
  </div>
51
+ <p><?php echo sprintf(__('Questions? <a %s>Read FAQ</a> or contact support at <a %s>wordpress@ecwid.com</a>', 'ecwid-shopping-cart'), 'target="_blank" href="https://help.ecwid.com/customer/portal/articles/1085017-wordpress-downloadable#FAQ"', 'href="mailto:wordpress@ecwid.com"'); ?></p>
52
  </div>
templates/dashboard.php CHANGED
@@ -54,5 +54,5 @@
54
  </div>
55
 
56
  </div>
57
- <p><?php echo sprintf(__('Questions? Visit <a %s>Ecwid support center</a>', 'ecwid-shopping-cart'), 'target="_blank" href="http://help.ecwid.com/?source=wporg"'); ?></p>
58
  </div>
54
  </div>
55
 
56
  </div>
57
+ <p><?php echo sprintf(__('Questions? <a %s>Read FAQ</a> or contact support at <a %s>wordpress@ecwid.com</a>', 'ecwid-shopping-cart'), 'target="_blank" href="https://help.ecwid.com/customer/portal/articles/1085017-wordpress-downloadable#FAQ"', 'href="mailto:wordpress@ecwid.com"'); ?></p>
58
  </div>
templates/reconnect.php CHANGED
@@ -1,31 +1,51 @@
1
- <div class="wrap ecwid-admin ecwid-connect">
2
  <div class="box">
3
- <h3>
4
- <?php ecwid_embed_svg('ecwid_logo_symbol_RGB');?>
5
- <?php _e( 'Ecwid Shopping Cart', 'ecwid-shopping-cart' ); ?>
6
- <span class="close"></span>
7
- </h3>
8
  <div class="greeting-image">
9
  <img src="<?php echo(esc_attr(ECWID_PLUGIN_URL)); ?>/images/store_inprogress.png" width="142" />
10
  </div>
11
 
12
  <div class="greeting-message mobile-br">
13
- <?php _e( 'Reconnect your store<br /> to this WordPress site', 'ecwid-shopping-cart' ); ?>
14
  </div>
15
 
 
 
 
 
 
 
16
  <div class="connect-button">
17
- <a href="<?php echo esc_attr($ecwid_oauth->get_auth_dialog_url()); ?>"><?php _e( 'Reconnect Ecwid store', 'ecwid-shopping-cart' ); ?></a>
18
  </div>
19
 
20
- <div class="note initial">
21
- <?php _e( 'New features available, reconnect to be in touch with our updates', 'ecwid-shopping-cart' ); ?>
22
- </div>
23
 
24
- <div class="create-account-link">
25
- <a href="">
26
- <?php _e( "Don't have Ecwid account? Create it here", 'ecwid-shopping-cart' ); ?>
27
- </a>
28
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
  </div>
30
- <p><?php _e('Questions? Visit <a href="http://help.ecwid.com/?source=wporg">Ecwid support center</a>', 'ecwid-shopping-cart'); ?></p>
31
  </div>
1
+ <div class="wrap ecwid-admin ecwid-connect ecwid-reconnect">
2
  <div class="box">
3
+ <div class="head"><?php ecwid_embed_svg('ecwid_logo_symbol_RGB');?>
4
+ <h3>
5
+ <?php _e( 'Ecwid Shopping Cart', 'ecwid-shopping-cart' ); ?>
6
+ </h3>
7
+ </div>
8
  <div class="greeting-image">
9
  <img src="<?php echo(esc_attr(ECWID_PLUGIN_URL)); ?>/images/store_inprogress.png" width="142" />
10
  </div>
11
 
12
  <div class="greeting-message mobile-br">
13
+ <?php _e( 'Connect your store<br /> to this WordPress site', 'ecwid-shopping-cart' ); ?>
14
  </div>
15
 
16
+ <?php if ($ecwid_oauth->get_reconnect_message()): ?>
17
+ <div class="note reconnect-message">
18
+ <?php echo $ecwid_oauth->get_reconnect_message(); ?>
19
+ </div>
20
+ <?php endif; ?>
21
+
22
  <div class="connect-button">
23
+ <a href="admin-post.php?action=ecwid_connect&reconnect"><?php _e( 'Connect Ecwid store', 'ecwid-shopping-cart' ); ?></a>
24
  </div>
25
 
26
+ <?php if ($connection_error && $ecwid_oauth->get_error() == 'cancelled'): ?>
 
 
27
 
28
+
29
+ <div class="note auth-error">
30
+ <span>
31
+ <?php _e( 'Connection error - after clicking button you need to login and accept permissions to use our plugin. Please, try again.', 'ecwid-shopping-cart' ); ?>
32
+ </span>
33
+ </div>
34
+
35
+ <?php elseif ($connection_error && $ecwid_oauth->get_error() == 'other'): ?>
36
+
37
+ <div class="note auth-error">
38
+ <span>
39
+ <?php _e( 'Looks like your site does not support remote POST requests that are required for Ecwid API to work. Please, contact your hosting provider to enable cURL.', 'ecwid-shopping-cart' ); ?>
40
+ </span>
41
+ </div>
42
+
43
+ <?php else: ?>
44
+
45
+ <div class="note">
46
+ <?php _e( 'After clicking button you need to login and accept permissions to use our plugin', 'ecwid-shopping-cart' ); ?>
47
+ </div>
48
+ <?php endif; ?>
49
  </div>
50
+ <p><?php echo sprintf(__('Questions? <a %s>Read FAQ</a> or contact support at <a %s>wordpress@ecwid.com</a>', 'ecwid-shopping-cart'), 'target="_blank" href="https://help.ecwid.com/customer/portal/articles/1085017-wordpress-downloadable#FAQ"', 'href="mailto:wordpress@ecwid.com"'); ?></p>
51
  </div>