From 8ae612f6930235aa1768d3a5beeff65a3565d90a Mon Sep 17 00:00:00 2001 From: Bart Visscher Date: Tue, 10 Sep 2013 20:19:42 +0200 Subject: [PATCH 001/181] Move core setup code to controller class --- core/setup.php | 59 ----------------------------- core/setup/controller.php | 79 +++++++++++++++++++++++++++++++++++++++ lib/base.php | 3 +- 3 files changed, 81 insertions(+), 60 deletions(-) delete mode 100644 core/setup.php create mode 100644 core/setup/controller.php diff --git a/core/setup.php b/core/setup.php deleted file mode 100644 index 4758c23b04..0000000000 --- a/core/setup.php +++ /dev/null @@ -1,59 +0,0 @@ - $hasSQLite, - 'hasMySQL' => $hasMySQL, - 'hasPostgreSQL' => $hasPostgreSQL, - 'hasOracle' => $hasOracle, - 'hasMSSQL' => $hasMSSQL, - 'directory' => $datadir, - 'secureRNG' => OC_Util::secureRNGAvailable(), - 'htaccessWorking' => OC_Util::isHtAccessWorking(), - 'vulnerableToNullByte' => $vulnerableToNullByte, - 'errors' => array(), -); - -if(isset($_POST['install']) AND $_POST['install']=='true') { - // We have to launch the installation process : - $e = OC_Setup::install($_POST); - $errors = array('errors' => $e); - - if(count($e) > 0) { - //OC_Template::printGuestPage("", "error", array("errors" => $errors)); - $options = array_merge($_POST, $opts, $errors); - OC_Template::printGuestPage("", "installation", $options); - } - else { - header( 'Location: '.OC_Helper::linkToRoute( 'post_setup_check' )); - exit(); - } -} -else { - OC_Template::printGuestPage("", "installation", $opts); -} diff --git a/core/setup/controller.php b/core/setup/controller.php new file mode 100644 index 0000000000..54bfe14612 --- /dev/null +++ b/core/setup/controller.php @@ -0,0 +1,79 @@ +loadAutoConfig($post); + $opts = $this->getSystemInfo(); + + if(isset($post['install']) AND $post['install']=='true') { + // We have to launch the installation process : + $e = \OC_Setup::install($post); + $errors = array('errors' => $e); + + if(count($e) > 0) { + $options = array_merge($post, $opts, $errors); + $this->display($options); + } + else { + $this->finishSetup(); + } + } + else { + $this->display($opts); + } + } + + public function display($post) { + \OC_Util::addScript('setup'); + \OC_Template::printGuestPage('', 'installation', $post); + } + + public function finishSetup() { + header( 'Location: '.\OC_Helper::linkToRoute( 'post_setup_check' )); + exit(); + } + + public function loadAutoConfig($post) { + $autosetup_file = \OC::$SERVERROOT.'/config/autoconfig.php'; + if( file_exists( $autosetup_file )) { + \OC_Log::write('core', 'Autoconfig file found, setting up owncloud...', \OC_Log::INFO); + include $autosetup_file; + $post['install'] = 'true'; + $post = array_merge ($post, $AUTOCONFIG); + unlink($autosetup_file); + } + return $post; + } + + public function getSystemInfo() { + $hasSQLite = class_exists('SQLite3'); + $hasMySQL = is_callable('mysql_connect'); + $hasPostgreSQL = is_callable('pg_connect'); + $hasOracle = is_callable('oci_connect'); + $hasMSSQL = is_callable('sqlsrv_connect'); + $datadir = \OC_Config::getValue('datadirectory', \OC::$SERVERROOT.'/data'); + $vulnerableToNullByte = false; + if(@file_exists(__FILE__."\0Nullbyte")) { // Check if the used PHP version is vulnerable to the NULL Byte attack (CVE-2006-7243) + $vulnerableToNullByte = true; + } + + // Protect data directory here, so we can test if the protection is working + \OC_Setup::protectDataDirectory(); + + return array( + 'hasSQLite' => $hasSQLite, + 'hasMySQL' => $hasMySQL, + 'hasPostgreSQL' => $hasPostgreSQL, + 'hasOracle' => $hasOracle, + 'hasMSSQL' => $hasMSSQL, + 'directory' => $datadir, + 'secureRNG' => \OC_Util::secureRNGAvailable(), + 'htaccessWorking' => \OC_Util::isHtAccessWorking(), + 'vulnerableToNullByte' => $vulnerableToNullByte, + 'errors' => array(), + ); + } +} diff --git a/lib/base.php b/lib/base.php index ea5adbadc9..aa91176d21 100644 --- a/lib/base.php +++ b/lib/base.php @@ -610,7 +610,8 @@ class OC { // Check if ownCloud is installed or in maintenance (update) mode if (!OC_Config::getValue('installed', false)) { - require_once 'core/setup.php'; + $controller = new OC\Core\Setup\Controller(); + $controller->run($_POST); exit(); } From 65aab3dc8c88f012e063ccea7cacc17f528b7d4d Mon Sep 17 00:00:00 2001 From: Bart Visscher Date: Tue, 10 Sep 2013 22:05:20 +0200 Subject: [PATCH 002/181] Check for failure in creating htaccessWorking testfile --- core/setup/controller.php | 14 ++++++++++++-- lib/util.php | 12 ++++++++---- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/core/setup/controller.php b/core/setup/controller.php index 54bfe14612..8ddcf19bb6 100644 --- a/core/setup/controller.php +++ b/core/setup/controller.php @@ -60,8 +60,18 @@ class Controller { $vulnerableToNullByte = true; } + $errors = array(); + // Protect data directory here, so we can test if the protection is working \OC_Setup::protectDataDirectory(); + try { + $htaccessworking = \OC_Util::isHtAccessWorking(); + } catch (\OC\HintException $e) { + $errors[] = array( + 'error' => $e->getMessage(), + 'hint' => $e->getHint() + ); + } return array( 'hasSQLite' => $hasSQLite, @@ -71,9 +81,9 @@ class Controller { 'hasMSSQL' => $hasMSSQL, 'directory' => $datadir, 'secureRNG' => \OC_Util::secureRNGAvailable(), - 'htaccessWorking' => \OC_Util::isHtAccessWorking(), + 'htaccessWorking' => $htaccessWorking, 'vulnerableToNullByte' => $vulnerableToNullByte, - 'errors' => array(), + 'errors' => $errors, ); } } diff --git a/lib/util.php b/lib/util.php index 0777643a95..e8e3bc37e5 100755 --- a/lib/util.php +++ b/lib/util.php @@ -689,9 +689,13 @@ class OC_Util { return false; } - $fp = @fopen($testfile, 'w'); - @fwrite($fp, $testcontent); - @fclose($fp); + $fp = @fopen($testFile, 'w'); + if (!$fp) { + throw new OC\HintException('Can\'t create test file to check for working .htaccess file.', + 'Make sure it is possible for the webserver to write to '.$testFile); + } + fwrite($fp, $testContent); + fclose($fp); // accessing the file via http $url = OC_Helper::makeURLAbsolute(OC::$WEBROOT.'/data'.$fileName); @@ -700,7 +704,7 @@ class OC_Util { @fclose($fp); // cleanup - @unlink($testfile); + @unlink($testFile); // does it work ? if($content==$testContent) { From 071b8033cb59a3ed51925374e78790ecfa7a2fac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Tue, 24 Sep 2013 00:44:55 +0200 Subject: [PATCH 003/181] fixing typo on $htaccessWorking - testing own code before pushing is appreciated --- core/setup/controller.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/setup/controller.php b/core/setup/controller.php index 8ddcf19bb6..e1ad9d60e8 100644 --- a/core/setup/controller.php +++ b/core/setup/controller.php @@ -64,8 +64,9 @@ class Controller { // Protect data directory here, so we can test if the protection is working \OC_Setup::protectDataDirectory(); + $htaccessWorking = false; try { - $htaccessworking = \OC_Util::isHtAccessWorking(); + $htaccessWorking = \OC_Util::isHtAccessWorking(); } catch (\OC\HintException $e) { $errors[] = array( 'error' => $e->getMessage(), From 5db98aadd30b9f1218dda8f836acca0062ce1d9f Mon Sep 17 00:00:00 2001 From: Bart Visscher Date: Wed, 2 Oct 2013 18:23:47 +0200 Subject: [PATCH 004/181] Copyright and small fix --- core/setup/controller.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/core/setup/controller.php b/core/setup/controller.php index e1ad9d60e8..9b35432f11 100644 --- a/core/setup/controller.php +++ b/core/setup/controller.php @@ -1,4 +1,10 @@ + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ namespace OC\Core\Setup; @@ -43,7 +49,7 @@ class Controller { include $autosetup_file; $post['install'] = 'true'; $post = array_merge ($post, $AUTOCONFIG); - unlink($autosetup_file); + @unlink($autosetup_file); } return $post; } From 39906cefbf0ee6e4d161c4a09c88194175d3d64e Mon Sep 17 00:00:00 2001 From: raghunayyar Date: Sun, 6 Oct 2013 23:28:22 +0530 Subject: [PATCH 005/181] Converts em to px values for styles in Files. --- apps/files/css/files.css | 28 ++++++++++++++-------------- apps/files/css/upload.css | 4 ++-- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/apps/files/css/files.css b/apps/files/css/files.css index e26c1a89b7..546451806e 100644 --- a/apps/files/css/files.css +++ b/apps/files/css/files.css @@ -3,7 +3,7 @@ See the COPYING-README file. */ /* FILE MENU */ -.actions { padding:.3em; height:2em; width: 100%; } +.actions { padding:5px; height:32px; width: 100%; } .actions input, .actions button, .actions .button { margin:0; float:left; } .actions .button a { color: #555; } .actions .button a:hover, .actions .button a:active { color: #333; } @@ -30,9 +30,9 @@ #new>ul { display: none; position: fixed; - min-width: 7em; + min-width: 112px; z-index: 10; - padding: .5em; + padding: 8px; padding-bottom: 0; margin-top: 14px; margin-left: -1px; @@ -43,7 +43,7 @@ border-top-left-radius: 0; box-shadow:0 2px 7px rgba(170,170,170,.4); } -#new>ul>li { height:36px; margin:.3em; padding-left:3em; padding-bottom:0.1em; +#new>ul>li { height:36px; margin:5px; padding-left:48px; padding-bottom:2px; background-repeat:no-repeat; cursor:pointer; } #new>ul>li>p { cursor:pointer; padding-top: 7px; padding-bottom: 7px;} @@ -56,7 +56,7 @@ top: 44px; width: 100%; } -#filestable tbody tr { background-color:#fff; height:2.5em; } +#filestable tbody tr { background-color:#fff; height:40px; } #filestable tbody tr:hover, tbody tr:active { background-color: rgb(240,240,240); } @@ -71,7 +71,7 @@ span.extension, span.uploading, td.date { color:#999; } span.extension { text-transform:lowercase; -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=70)"; filter:alpha(opacity=70); opacity:.7; -webkit-transition:opacity 300ms; -moz-transition:opacity 300ms; -o-transition:opacity 300ms; transition:opacity 300ms; } tr:hover span.extension { -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"; filter:alpha(opacity=100); opacity:1; color:#777; } table tr.mouseOver td { background-color:#eee; } -table th { height:2em; padding:0 .5em; color:#999; } +table th { height:24px; padding:0 8px; color:#999; } table th .name { position: absolute; left: 55px; @@ -94,15 +94,15 @@ table th#headerName { height: 50px; } table th#headerSize, table td.filesize { - min-width: 3em; - padding: 0 1em; + min-width: 48px; + padding: 0 16px; text-align: right; } table th#headerDate, table td.date { -moz-box-sizing: border-box; box-sizing: border-box; position: relative; - min-width: 11em; + min-width: 176px; display: block; height: 51px; } @@ -173,8 +173,8 @@ table td.filename .nametext { text-overflow: ellipsis; max-width: 800px; } -table td.filename .uploadtext { font-weight:normal; margin-left:.5em; } -table td.filename form { font-size:.85em; margin-left:3em; margin-right:3em; } +table td.filename .uploadtext { font-weight:normal; margin-left:8px; } +table td.filename form { font-size:.85em; margin-left:48px; margin-right:48px; } /* File checkboxes */ @@ -247,7 +247,7 @@ table td.filename form { font-size:.85em; margin-left:3em; margin-right:3em; } box-shadow: -5px 0 7px rgba(230,230,230,.9); } -#fileList img.move2trash { display:inline; margin:-.5em 0; padding:1em .5em 1em .5em !important; float:right; } +#fileList img.move2trash { display:inline; margin:-.5em 0; padding:16px 8px 16px 8px !important; float:right; } #fileList a.action.delete { position: absolute; right: 0; @@ -271,13 +271,13 @@ a.action>img { max-height:16px; max-width:16px; vertical-align:text-bottom; } } .selectedActions a img { position:relative; - top:.3em; + top:5px; } #fileList a.action { display: inline; - margin: -.5em 0; + margin: -8px 0; padding: 18px 8px !important; -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; filter: alpha(opacity=0); diff --git a/apps/files/css/upload.css b/apps/files/css/upload.css index ef04356909..ddd2a67b81 100644 --- a/apps/files/css/upload.css +++ b/apps/files/css/upload.css @@ -5,7 +5,7 @@ height: 36px; width: 39px; padding: 0 !important; /* override default control bar button padding */ - margin-left: .2em; + margin-left: 3px; overflow: hidden; vertical-align: top; } @@ -33,7 +33,7 @@ height: 44px; margin: -5px -3px; padding: 0; - font-size: 1em; + font-size: 16px; -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; filter:alpha(opacity=0); opacity:0; z-index: 20; cursor: pointer; From cf84154ee09d9bc706a0343d03600f6ebfbde7a1 Mon Sep 17 00:00:00 2001 From: raghunayyar Date: Sun, 6 Oct 2013 23:38:24 +0530 Subject: [PATCH 006/181] Cleans up Core apps for relative(em) to absolute(px) styles. --- apps/files_external/css/settings.css | 4 ++-- apps/files_sharing/css/public.css | 28 ++++++++++++++-------------- apps/files_versions/css/versions.css | 2 +- apps/user_ldap/css/settings.css | 2 +- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/apps/files_external/css/settings.css b/apps/files_external/css/settings.css index f2f40247b2..4a32ac4153 100644 --- a/apps/files_external/css/settings.css +++ b/apps/files_external/css/settings.css @@ -16,8 +16,8 @@ span.waiting { background: none; } -td.mountPoint, td.backend { width:10em; } -td.remove>img { visibility:hidden; padding-top:0.8em; } +td.mountPoint, td.backend { width:160px; } +td.remove>img { visibility:hidden; padding-top:13px; } tr:hover>td.remove>img { visibility:visible; cursor:pointer; } #addMountPoint>td { border:none; } #addMountPoint>td.applicable { visibility:hidden; } diff --git a/apps/files_sharing/css/public.css b/apps/files_sharing/css/public.css index 3aa4a48304..70345c3577 100644 --- a/apps/files_sharing/css/public.css +++ b/apps/files_sharing/css/public.css @@ -4,14 +4,14 @@ body { #header { background: #1d2d44 url('%webroot%/core/img/noise.png') repeat; - height:2.5em; + height:40px; left:0; - line-height:2.5em; + line-height:40px; position:fixed; right:0; top:0; z-index:100; - padding:.5em; + padding:8px; } #details { @@ -22,7 +22,7 @@ body { #public_upload, #download { font-weight:700; - margin: 0 0.4em 0 0; + margin: 0 6px 0 0; padding: 0 5px; height: 27px; float: left; @@ -30,38 +30,38 @@ body { } .header-right #details { - margin-right: 2em; + margin-right: 32px; } #public_upload { - margin-left: 0.3em; + margin-left: 5px; } #public_upload img, #download img { - padding-left:.1em; - padding-right:.3em; + padding-left:2px; + padding-right:5px; vertical-align:text-bottom; } #preview { background:#eee; border-bottom:1px solid #f8f8f8; - min-height:30em; + min-height:480px; text-align:center; margin:45px auto; } #noPreview { display:none; - padding-top:5em; + padding-top:90px; } p.info { color:#777; text-align:center; - width:22em; - margin:2em auto; + width:352px; + margin:32px auto; } p.info a { @@ -71,8 +71,8 @@ p.info a { #imgframe { height:75%; - padding-bottom:2em; - padding-top:2em; + padding-bottom:32px; + padding-top:32px; width:80%; margin:0 auto; } diff --git a/apps/files_versions/css/versions.css b/apps/files_versions/css/versions.css index c53935711c..8838ea8484 100644 --- a/apps/files_versions/css/versions.css +++ b/apps/files_versions/css/versions.css @@ -1,5 +1,5 @@ #dropdown.drop-versions { - width:24em; + width:384em; } #found_versions li { diff --git a/apps/user_ldap/css/settings.css b/apps/user_ldap/css/settings.css index 6086c7b74e..55ca503adf 100644 --- a/apps/user_ldap/css/settings.css +++ b/apps/user_ldap/css/settings.css @@ -22,6 +22,6 @@ } .ldapwarning { - margin-left: 1.4em; + margin-left: 22px; color: #FF3B3B; } From 4687d2dd0bde3f689eb57c90d0c4341cd00991bd Mon Sep 17 00:00:00 2001 From: raghunayyar Date: Mon, 7 Oct 2013 00:01:29 +0530 Subject: [PATCH 007/181] All Core Styles from em->px, apart from styles.css --- core/css/auth.css | 12 ++++++------ core/css/jquery.multiselect.css | 2 +- core/css/multiselect.css | 20 ++++++++++---------- core/css/share.css | 20 ++++++++++---------- 4 files changed, 27 insertions(+), 27 deletions(-) diff --git a/core/css/auth.css b/core/css/auth.css index 0adc10c77d..70df9f0ae0 100644 --- a/core/css/auth.css +++ b/core/css/auth.css @@ -1,7 +1,7 @@ h2 { - font-size:2em; + font-size:32px; font-weight:700; - margin-bottom:1em; + margin-bottom:16px; white-space:nowrap; } @@ -18,8 +18,8 @@ h2 img { } #oauth { - width:20em; - margin:4em auto 2em; + width:320px; + margin:64px auto 32px; } #allow-auth { @@ -33,7 +33,7 @@ h2 img { background:none; border:0; box-shadow:0 0 0 #fff, 0 0 0 #fff inset; - font-size:1.2em; - margin:.7em; + font-size:19px; + margin:11px; padding:0; } diff --git a/core/css/jquery.multiselect.css b/core/css/jquery.multiselect.css index 898786a615..6b3ae47d6e 100644 --- a/core/css/jquery.multiselect.css +++ b/core/css/jquery.multiselect.css @@ -4,7 +4,7 @@ .ui-multiselect-single .ui-multiselect-checkboxes label { padding:5px !important } .ui-multiselect-header { margin-bottom:3px; padding:3px 0 3px 4px } -.ui-multiselect-header ul { font-size:0.9em } +.ui-multiselect-header ul { font-size:15px } .ui-multiselect-header ul li { float:left; padding:0 10px 0 0 } .ui-multiselect-header a { text-decoration:none } .ui-multiselect-header a:hover { text-decoration:underline } diff --git a/core/css/multiselect.css b/core/css/multiselect.css index c25446808e..a8ec6e88fd 100644 --- a/core/css/multiselect.css +++ b/core/css/multiselect.css @@ -7,7 +7,7 @@ ul.multiselectoptions { border: 1px solid #ddd; border-top: none; box-shadow: 0 1px 1px #ddd; - padding-top: .5em; + padding-top: 8px; position: absolute; max-height: 20em; overflow-y: auto; @@ -15,8 +15,8 @@ ul.multiselectoptions { } ul.multiselectoptions.down { - border-bottom-left-radius: .5em; - border-bottom-right-radius: .5em; + border-bottom-left-radius: 8px; + border-bottom-right-radius: 8px; width: 100%; /* do not cut off group names */ -webkit-box-shadow: 0px 0px 20px rgba(29,45,68,.4); -moz-box-shadow: 0px 0px 20px rgba(29,45,68,.4); @@ -24,8 +24,8 @@ ul.multiselectoptions.down { } ul.multiselectoptions.up { - border-top-left-radius: .5em; - border-top-right-radius: .5em; + border-top-left-radius: 8px; + border-top-right-radius: 8px; } ul.multiselectoptions>li { @@ -52,7 +52,7 @@ div.multiselect { display: inline-block; max-width: 400px; min-width: 150px; - padding-right: .6em; + padding-right: 10px; position: relative; vertical-align: bottom; } @@ -77,7 +77,7 @@ div.multiselect.down { div.multiselect>span:first-child { float: left; - margin-right: 2em; + margin-right: 32px; overflow: hidden; text-overflow: ellipsis; width: 90%; @@ -85,12 +85,12 @@ div.multiselect>span:first-child { div.multiselect>span:last-child { position: absolute; - right: .8em; + right: 13px; } ul.multiselectoptions input.new { - padding-bottom: .2em; - padding-top: .2em; + padding-bottom: 3px; + padding-top: 3px; margin: 0; } diff --git a/core/css/share.css b/core/css/share.css index 2a21dc6edf..ded68349dc 100644 --- a/core/css/share.css +++ b/core/css/share.css @@ -8,21 +8,21 @@ border-bottom-right-radius: 5px; box-shadow:0 1px 1px #777; display:block; - margin-right:7em; + margin-right:112px; position:absolute; right:0; - width:25em; + width:400px; z-index:500; - padding:1em; + padding:16px; } #shareWithList { list-style-type:none; - padding:.5em; + padding:8px; } #shareWithList li { - padding-top:.1em; + padding-top:2px; } #shareWithList li:first-child { @@ -42,7 +42,7 @@ } #dropdown input[type="checkbox"] { - margin:0 .2em 0 .5em; + margin:0 3px 0 8px; } a.showCruds { @@ -54,13 +54,13 @@ a.unshare { display:inline; float:right; opacity:.5; - padding:.3em 0 0 .3em !important; + padding:5px 0 0 5px !important; margin-top:-5px; } #link { border-top:1px solid #ddd; - padding-top:.5em; + padding-top:8px; } #dropdown input[type="text"],#dropdown input[type="password"] { @@ -78,12 +78,12 @@ a.unshare { } #link #showPassword img { - padding-left:.3em; + padding-left:5px; width:12px; } .reshare,#link label,#expiration label { - padding-left:.5em; + padding-left:8px; } a.showCruds:hover,a.unshare:hover { From 09d2ba017e603fe6ac237da7830d86d74b2da61c Mon Sep 17 00:00:00 2001 From: Morris Jobke Date: Mon, 7 Oct 2013 00:36:42 +0200 Subject: [PATCH 008/181] fix undefined $htaccessWorking --- core/setup/controller.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/setup/controller.php b/core/setup/controller.php index 9b35432f11..679efee81b 100644 --- a/core/setup/controller.php +++ b/core/setup/controller.php @@ -70,7 +70,6 @@ class Controller { // Protect data directory here, so we can test if the protection is working \OC_Setup::protectDataDirectory(); - $htaccessWorking = false; try { $htaccessWorking = \OC_Util::isHtAccessWorking(); } catch (\OC\HintException $e) { @@ -78,6 +77,7 @@ class Controller { 'error' => $e->getMessage(), 'hint' => $e->getHint() ); + $htaccessWorking = false; } return array( From be0197a29ae6355f2be5e015faf50cfc16e304be Mon Sep 17 00:00:00 2001 From: zombiehugs Date: Wed, 4 Dec 2013 11:27:24 -0600 Subject: [PATCH 009/181] #6051 [ux][files] Move File Spinner Added spinner to file icon when moving to new folder or out of folder. Commit is related to #6051 --- apps/files/js/files.js | 42 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/apps/files/js/files.js b/apps/files/js/files.js index fdaa3aa334..beda86d009 100644 --- a/apps/files/js/files.js +++ b/apps/files/js/files.js @@ -493,7 +493,7 @@ var createDragShadow = function(event) { var dir=$('#dir').val(); $(selectedFiles).each(function(i,elem) { - var newtr = $('').attr('data-dir', dir).attr('data-filename', elem.name); + var newtr = $('').attr('data-dir', dir).attr('data-filename', elem.name).attr('data-origin', elem.origin); newtr.append($('').addClass('filename').text(elem.name)); newtr.append($('').addClass('size').text(humanFileSize(elem.size))); tbody.append(newtr); @@ -511,13 +511,30 @@ var createDragShadow = function(event) { }; //options for file drag/drop +//start&stop handlers needs some cleaning up var dragOptions={ revert: 'invalid', revertDuration: 300, opacity: 0.7, zIndex: 100, appendTo: 'body', cursorAt: { left: 24, top: 18 }, helper: createDragShadow, cursor: 'move', - stop: function(event, ui) { - $('#fileList tr td.filename').addClass('ui-draggable'); - } + start: function(event, ui){ + var $selectedFiles = $('td.filename input:checkbox:checked'); + if($selectedFiles.length > 1){ + $selectedFiles.parents('tr').fadeTo(250, 0.2); + } + else{ + $(this).fadeTo(250, 0.2); + } + }, + stop: function(event, ui) { + var $selectedFiles = $('td.filename input:checkbox:checked'); + if($selectedFiles.length > 1){ + $selectedFiles.parents('tr').fadeTo(250, 1); + } + else{ + $(this).fadeTo(250, 1); + } + $('#fileList tr td.filename').addClass('ui-draggable'); + } }; // sane browsers support using the distance option if ( $('html.ie').length === 0) { @@ -525,6 +542,7 @@ if ( $('html.ie').length === 0) { } var folderDropOptions={ + hoverClass: "canDrop", drop: function( event, ui ) { //don't allow moving a file into a selected folder if ($(event.target).parents('tr').find('td input:first').prop('checked') === true) { @@ -537,6 +555,11 @@ var folderDropOptions={ $(files).each(function(i,row) { var dir = $(row).data('dir'); var file = $(row).data('filename'); + //slapdash selector, tracking down our original element that the clone budded off of. + var origin = $('tr[data-id=' + $(row).data('origin') + ']'); + var td = origin.children('td.filename'); + var oldBackgroundImage = td.css('background-image'); + td.css('background-image', 'url('+ OC.imagePath('core', 'loading.gif') + ')'); $.post(OC.filePath('files', 'ajax', 'move.php'), { dir: dir, file: file, target: dir+'/'+target }, function(result) { if (result) { if (result.status === 'success') { @@ -557,6 +580,7 @@ var folderDropOptions={ } else { OC.dialogs.alert(t('files', 'Error moving file'), t('files', 'Error')); } + td.css('background-image', oldBackgroundImage); }); }); }, @@ -581,6 +605,11 @@ var crumbDropOptions={ $(files).each(function(i,row) { var dir = $(row).data('dir'); var file = $(row).data('filename'); + //slapdash selector, tracking down our original element that the clone budded off of. + var origin = $('tr[data-id=' + $(row).data('origin') + ']'); + var td = origin.children('td.filename'); + var oldBackgroundImage = td.css('background-image'); + td.css('background-image', 'url('+ OC.imagePath('core', 'loading.gif') + ')'); $.post(OC.filePath('files', 'ajax', 'move.php'), { dir: dir, file: file, target: target }, function(result) { if (result) { if (result.status === 'success') { @@ -595,6 +624,7 @@ var crumbDropOptions={ } else { OC.dialogs.alert(t('files', 'Error moving file'), t('files', 'Error')); } + td.css('background-image', oldBackgroundImage); }); }); }, @@ -660,7 +690,8 @@ function getSelectedFilesTrash(property) { mime:$(element).data('mime'), type:$(element).data('type'), size:$(element).data('size'), - etag:$(element).data('etag') + etag:$(element).data('etag'), + origin: $(element).data('id') }; if (property) { files.push(file[property]); @@ -780,3 +811,4 @@ function onClickBreadcrumb(e) { FileList.changeDirectory(decodeURIComponent($targetDir)); } } + From 8fb4ab097dd7cd8ae1ab8fc15ae48021f8d9c28e Mon Sep 17 00:00:00 2001 From: zombiehugs Date: Wed, 4 Dec 2013 12:30:06 -0600 Subject: [PATCH 010/181] Fixed indention. As per @kabum request, indention on line 694 has been fixed. --- apps/files/js/files.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/files/js/files.js b/apps/files/js/files.js index beda86d009..89334070fc 100644 --- a/apps/files/js/files.js +++ b/apps/files/js/files.js @@ -691,7 +691,7 @@ function getSelectedFilesTrash(property) { type:$(element).data('type'), size:$(element).data('size'), etag:$(element).data('etag'), - origin: $(element).data('id') + origin: $(element).data('id') }; if (property) { files.push(file[property]); From 44a55056e7b6dc505af7f8a0a6f7b33bd0dcacb8 Mon Sep 17 00:00:00 2001 From: Morris Jobke Date: Sat, 7 Dec 2013 17:33:27 +0100 Subject: [PATCH 011/181] change mail address by pressing enter - fixes #6179 --- settings/js/personal.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/settings/js/personal.js b/settings/js/personal.js index 2934677f25..7b9268ca81 100644 --- a/settings/js/personal.js +++ b/settings/js/personal.js @@ -171,6 +171,18 @@ $(document).ready(function(){ } }); + $('#email').keypress(function(event){ + // check for enter key and non empyt email + if (event.keyCode === 13 && $('#email').val() !== '' ){ + event.preventDefault() + // clear timeout of previous keyup event - prevents duplicate changeEmailAddress call + if(typeof timeout !== 'undefined'){ + clearTimeout(timeout); + } + changeEmailAddress(); + } + }); + $("#languageinput").change( function(){ // Serialize the data var post = $( "#languageinput" ).serialize(); From 69f2bde324cd491937a90948a23b06a06c2f2400 Mon Sep 17 00:00:00 2001 From: Pellaeon Lin Date: Sun, 8 Dec 2013 15:41:20 +0800 Subject: [PATCH 012/181] Change misleading message when file size exceeds upload limit --- apps/files/js/file-upload.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/files/js/file-upload.js b/apps/files/js/file-upload.js index e9663353f7..979bb74b13 100644 --- a/apps/files/js/file-upload.js +++ b/apps/files/js/file-upload.js @@ -235,8 +235,8 @@ $(document).ready(function() { //check max upload size if (selection.totalBytes > $('#max_upload').val()) { - data.textStatus = 'notenoughspace'; - data.errorThrown = t('files', 'Not enough space available'); + data.textStatus = 'sizeexceedlimit'; + data.errorThrown = t('files', 'File size exceeds upload limit'); } // end upload for whole selection on error From fc607e6bce76e9e2f6f52421bdddece951f629cd Mon Sep 17 00:00:00 2001 From: Pellaeon Lin Date: Sun, 8 Dec 2013 22:59:46 +0800 Subject: [PATCH 013/181] Separate PHP upload limit and free space --- lib/private/helper.php | 42 +++++++++++++++++++++++++++++------------- lib/public/util.php | 19 +++++++++++++++++++ 2 files changed, 48 insertions(+), 13 deletions(-) diff --git a/lib/private/helper.php b/lib/private/helper.php index c82d3bd4ef..0bef427c6c 100644 --- a/lib/private/helper.php +++ b/lib/private/helper.php @@ -828,23 +828,39 @@ class OC_Helper { * @return number of bytes representing */ public static function maxUploadFilesize($dir) { - $upload_max_filesize = OCP\Util::computerFileSize(ini_get('upload_max_filesize')); - $post_max_size = OCP\Util::computerFileSize(ini_get('post_max_size')); - $freeSpace = \OC\Files\Filesystem::free_space($dir); - if ((int)$upload_max_filesize === 0 and (int)$post_max_size === 0) { - $maxUploadFilesize = \OC\Files\SPACE_UNLIMITED; - } elseif ((int)$upload_max_filesize === 0 or (int)$post_max_size === 0) { - $maxUploadFilesize = max($upload_max_filesize, $post_max_size); //only the non 0 value counts - } else { - $maxUploadFilesize = min($upload_max_filesize, $post_max_size); - } + return min(self::freeSpace($dir), self::uploadLimit()); + } + /** + * Calculate free space left within user quota + * + * @param $dir the current folder where the user currently operates + * @return number of bytes representing + */ + public static function freeSpace($dir) { + $freeSpace = \OC\Files\Filesystem::free_space($dir); if ($freeSpace !== \OC\Files\SPACE_UNKNOWN) { $freeSpace = max($freeSpace, 0); - - return min($maxUploadFilesize, $freeSpace); + return $freeSpace; } else { - return $maxUploadFilesize; + return INF; + } + } + + /** + * Calculate PHP upload limit + * + * @return PHP upload file size limit + */ + public static function uploadLimit() { + $upload_max_filesize = OCP\Util::computerFileSize(ini_get('upload_max_filesize')); + $post_max_size = OCP\Util::computerFileSize(ini_get('post_max_size')); + if ((int)$upload_max_filesize === 0 and (int)$post_max_size === 0) { + return INF; + } elseif ((int)$upload_max_filesize === 0 or (int)$post_max_size === 0) { + return max($upload_max_filesize, $post_max_size); //only the non 0 value counts + } else { + return min($upload_max_filesize, $post_max_size); } } diff --git a/lib/public/util.php b/lib/public/util.php index 1d76fd1e1f..cf7ac63ba5 100644 --- a/lib/public/util.php +++ b/lib/public/util.php @@ -458,4 +458,23 @@ class Util { public static function maxUploadFilesize($dir) { return \OC_Helper::maxUploadFilesize($dir); } + + /** + * Calculate free space left within user quota + * + * @param $dir the current folder where the user currently operates + * @return number of bytes representing + */ + public static function freeSpace($dir) { + return \OC_Helper::freeSpace($dir); + } + + /** + * Calculate PHP upload limit + * + * @return number of bytes representing + */ + public static function uploadLimit() { + return \OC_Helper::uploadLimit(); + } } From 64bf0fa47fe4c623672cf86e831f66974e7f650c Mon Sep 17 00:00:00 2001 From: Pellaeon Lin Date: Sun, 8 Dec 2013 23:17:35 +0800 Subject: [PATCH 014/181] Display different messages for uploadLimit and freeSpace --- apps/files/index.php | 4 ++++ apps/files/js/file-upload.js | 10 ++++++++-- apps/files/templates/index.php | 5 +++-- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/apps/files/index.php b/apps/files/index.php index 8f6838aa0d..4ea0f9f249 100644 --- a/apps/files/index.php +++ b/apps/files/index.php @@ -103,6 +103,8 @@ if ($needUpgrade) { } else { // information about storage capacities $storageInfo=OC_Helper::getStorageInfo($dir); + $freeSpace=OCP\Util::freeSpace($dir); + $uploadLimit=OCP\Util::uploadLimit(); $maxUploadFilesize=OCP\Util::maxUploadFilesize($dir); $publicUploadEnabled = \OC_Appconfig::getValue('core', 'shareapi_allow_public_upload', 'yes'); // if the encryption app is disabled, than everything is fine (INIT_SUCCESSFUL status code) @@ -136,6 +138,8 @@ if ($needUpgrade) { $tmpl->assign('trashEmpty', $trashEmpty); $tmpl->assign('uploadMaxFilesize', $maxUploadFilesize); $tmpl->assign('uploadMaxHumanFilesize', OCP\Util::humanFileSize($maxUploadFilesize)); + $tmpl->assign('freeSpace', $freeSpace); + $tmpl->assign('uploadLimit', $uploadLimit); $tmpl->assign('allowZipDownload', intval(OCP\Config::getSystemValue('allowZipDownload', true))); $tmpl->assign('usedSpacePercent', (int)$storageInfo['relative']); $tmpl->assign('isPublic', false); diff --git a/apps/files/js/file-upload.js b/apps/files/js/file-upload.js index 979bb74b13..7bd0eb81f5 100644 --- a/apps/files/js/file-upload.js +++ b/apps/files/js/file-upload.js @@ -233,11 +233,17 @@ $(document).ready(function() { // add size selection.totalBytes += file.size; - //check max upload size - if (selection.totalBytes > $('#max_upload').val()) { + // check PHP upload limit + if (selection.totalBytes > $('#upload_limit').val()) { data.textStatus = 'sizeexceedlimit'; data.errorThrown = t('files', 'File size exceeds upload limit'); } + + // check free space + if (selection.totalBytes > $('#free_space').val()) { + data.textStatus = 'notenoughspace'; + data.errorThrown = t('files', 'Not enough free space'); + } // end upload for whole selection on error if (data.errorThrown) { diff --git a/apps/files/templates/index.php b/apps/files/templates/index.php index 00ec109621..3d8a7f78e4 100644 --- a/apps/files/templates/index.php +++ b/apps/files/templates/index.php @@ -15,9 +15,10 @@
= 0):?> - + + + From bc23f46198168c80cc1aab3ae386687b4ce1ec49 Mon Sep 17 00:00:00 2001 From: Morris Jobke Date: Mon, 9 Dec 2013 16:05:10 +0100 Subject: [PATCH 015/181] fix typo --- settings/js/personal.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings/js/personal.js b/settings/js/personal.js index 7b9268ca81..010f0fc0a7 100644 --- a/settings/js/personal.js +++ b/settings/js/personal.js @@ -172,7 +172,7 @@ $(document).ready(function(){ }); $('#email').keypress(function(event){ - // check for enter key and non empyt email + // check for enter key and non empty email if (event.keyCode === 13 && $('#email').val() !== '' ){ event.preventDefault() // clear timeout of previous keyup event - prevents duplicate changeEmailAddress call From 0aa38165a4659fedd98f752bdd99bf174ed98a76 Mon Sep 17 00:00:00 2001 From: Pellaeon Lin Date: Wed, 11 Dec 2013 12:17:28 +0800 Subject: [PATCH 016/181] Update #free_space on getstoragestats AJAX call --- apps/files/js/files.js | 1 + apps/files/lib/helper.php | 2 ++ 2 files changed, 3 insertions(+) diff --git a/apps/files/js/files.js b/apps/files/js/files.js index fdaa3aa334..0a2f1aef01 100644 --- a/apps/files/js/files.js +++ b/apps/files/js/files.js @@ -41,6 +41,7 @@ Files={ } if (response.data !== undefined && response.data.uploadMaxFilesize !== undefined) { $('#max_upload').val(response.data.uploadMaxFilesize); + $('#free_space').val(response.data.freeSpace); $('#upload.button').attr('original-title', response.data.maxHumanFilesize); $('#usedSpacePercent').val(response.data.usedSpacePercent); Files.displayStorageWarnings(); diff --git a/apps/files/lib/helper.php b/apps/files/lib/helper.php index eaff28178e..2f4a979066 100644 --- a/apps/files/lib/helper.php +++ b/apps/files/lib/helper.php @@ -6,6 +6,7 @@ class Helper { public static function buildFileStorageStatistics($dir) { $l = new \OC_L10N('files'); + $freeSpace=OCP\Util::freeSpace($dir); $maxUploadFilesize = \OCP\Util::maxUploadFilesize($dir); $maxHumanFilesize = \OCP\Util::humanFileSize($maxUploadFilesize); $maxHumanFilesize = $l->t('Upload') . ' max. ' . $maxHumanFilesize; @@ -15,6 +16,7 @@ class Helper return array('uploadMaxFilesize' => $maxUploadFilesize, 'maxHumanFilesize' => $maxHumanFilesize, + 'freeSpace' => $freeSpace, 'usedSpacePercent' => (int)$storageInfo['relative']); } From 4b081be9569ed831c8f0fb7448bf798f004b8816 Mon Sep 17 00:00:00 2001 From: Pellaeon Lin Date: Wed, 11 Dec 2013 12:09:48 +0800 Subject: [PATCH 017/181] #max_upload is needed after all --- apps/files/templates/index.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/files/templates/index.php b/apps/files/templates/index.php index 3d8a7f78e4..f20a3f1d07 100644 --- a/apps/files/templates/index.php +++ b/apps/files/templates/index.php @@ -15,7 +15,7 @@
= 0):?> - + From 5ddd85ff9cb64c10974804e810f8f68f275114a3 Mon Sep 17 00:00:00 2001 From: Pellaeon Lin Date: Wed, 11 Dec 2013 15:40:58 +0800 Subject: [PATCH 018/181] Contextual upload error message --- apps/files/js/file-upload.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/files/js/file-upload.js b/apps/files/js/file-upload.js index 7bd0eb81f5..1a36a58053 100644 --- a/apps/files/js/file-upload.js +++ b/apps/files/js/file-upload.js @@ -236,13 +236,13 @@ $(document).ready(function() { // check PHP upload limit if (selection.totalBytes > $('#upload_limit').val()) { data.textStatus = 'sizeexceedlimit'; - data.errorThrown = t('files', 'File size exceeds upload limit'); + data.errorThrown = t('files', 'Total file size {size1} exceeds upload limit {size2}').replace('{size1}', humanFileSize(selection.totalBytes)).replace('{size2}', humanFileSize($('#upload_limit').val())); } // check free space if (selection.totalBytes > $('#free_space').val()) { data.textStatus = 'notenoughspace'; - data.errorThrown = t('files', 'Not enough free space'); + data.errorThrown = t('files', 'Not enough free space, you are uploading {size1} but only {size2} is left').replace('{size1}', humanFileSize(selection.totalBytes)).replace('{size2}', humanFileSize($('#free_space').val())); } // end upload for whole selection on error From 059c3c8708c9b94df80d43ab8cac0cfc9b867cb8 Mon Sep 17 00:00:00 2001 From: Georg Ehrke Date: Mon, 16 Dec 2013 15:38:12 +0100 Subject: [PATCH 019/181] fix issue with logging non utf8 chars --- lib/private/image.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/private/image.php b/lib/private/image.php index 7761a3c773..314a4216b8 100644 --- a/lib/private/image.php +++ b/lib/private/image.php @@ -416,7 +416,7 @@ class OC_Image { // exif_imagetype throws "read error!" if file is less than 12 byte if(!@is_file($imagePath) || !file_exists($imagePath) || filesize($imagePath) < 12 || !is_readable($imagePath)) { // Debug output disabled because this method is tried before loadFromBase64? - OC_Log::write('core', 'OC_Image->loadFromFile, couldn\'t load: '.$imagePath, OC_Log::DEBUG); + OC_Log::write('core', 'OC_Image->loadFromFile, couldn\'t load: ' . (string) $imagePath, OC_Log::DEBUG); return false; } $iType = exif_imagetype($imagePath); From 3c21fd5bfcaedf05a6028a4585f56e4afaddf33a Mon Sep 17 00:00:00 2001 From: Jan-Christoph Borchardt Date: Wed, 18 Dec 2013 14:59:57 +0100 Subject: [PATCH 020/181] do not show 'Add app' and 'More apps' for themed ownCloud --- settings/templates/apps.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/settings/templates/apps.php b/settings/templates/apps.php index 0b76f775fe..bf2f178ca1 100644 --- a/settings/templates/apps.php +++ b/settings/templates/apps.php @@ -9,9 +9,11 @@
From 1df1b55b66f0bcc696a1ee9aeb8362dee9889100 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Mon, 6 Jan 2014 12:55:56 +0100 Subject: [PATCH 021/181] expose memory cache in public api --- lib/private/server.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/lib/private/server.php b/lib/private/server.php index bee70dec2d..84ee8cadf0 100644 --- a/lib/private/server.php +++ b/lib/private/server.php @@ -136,6 +136,10 @@ class Server extends SimpleContainer implements IServerContainer { $this->registerService('UserCache', function($c) { return new UserCache(); }); + $this->registerService('MemCache', function ($c) { + $factory = new \OC\Memcache\Factory(); + return $factory->create(); + }); $this->registerService('ActivityManager', function($c) { return new ActivityManager(); }); @@ -295,6 +299,15 @@ class Server extends SimpleContainer implements IServerContainer { return $this->query('UserCache'); } + /** + * Returns an ICache instance + * + * @return \OCP\ICache + */ + function getMemCache() { + return $this->query('MemCache'); + } + /** * Returns the current session * From cd147bb37ae247082442f87b3cdd7d3d752e2d37 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Mon, 6 Jan 2014 12:58:43 +0100 Subject: [PATCH 022/181] Use APCIterator for Memcache\APC::clear() --- lib/private/memcache/apc.php | 27 ++++++++------------------- lib/private/memcache/apcu.php | 7 ------- 2 files changed, 8 insertions(+), 26 deletions(-) diff --git a/lib/private/memcache/apc.php b/lib/private/memcache/apc.php index 575ee4427d..d5bc1498d6 100644 --- a/lib/private/memcache/apc.php +++ b/lib/private/memcache/apc.php @@ -9,15 +9,8 @@ namespace OC\Memcache; class APC extends Cache { - /** - * entries in APC gets namespaced to prevent collisions between owncloud instances and users - */ - protected function getNameSpace() { - return $this->prefix; - } - public function get($key) { - $result = apc_fetch($this->getNamespace() . $key, $success); + $result = apc_fetch($this->getPrefix() . $key, $success); if (!$success) { return null; } @@ -25,26 +18,22 @@ class APC extends Cache { } public function set($key, $value, $ttl = 0) { - return apc_store($this->getNamespace() . $key, $value, $ttl); + return apc_store($this->getPrefix() . $key, $value, $ttl); } public function hasKey($key) { - return apc_exists($this->getNamespace() . $key); + return apc_exists($this->getPrefix() . $key); } public function remove($key) { - return apc_delete($this->getNamespace() . $key); + return apc_delete($this->getPrefix() . $key); } public function clear($prefix = '') { - $ns = $this->getNamespace() . $prefix; - $cache = apc_cache_info('user'); - foreach ($cache['cache_list'] as $entry) { - if (strpos($entry['info'], $ns) === 0) { - apc_delete($entry['info']); - } - } - return true; + $ns = $this->getPrefix() . $prefix; + $ns = preg_quote($ns, '/'); + $iter = new \APCIterator('user', '/^' . $ns . '/'); + return apc_delete($iter); } static public function isAvailable() { diff --git a/lib/private/memcache/apcu.php b/lib/private/memcache/apcu.php index dac0f5f208..7f780f3271 100644 --- a/lib/private/memcache/apcu.php +++ b/lib/private/memcache/apcu.php @@ -9,13 +9,6 @@ namespace OC\Memcache; class APCu extends APC { - public function clear($prefix = '') { - $ns = $this->getNamespace() . $prefix; - $ns = preg_quote($ns, '/'); - $iter = new \APCIterator('user', '/^'.$ns.'/'); - return apc_delete($iter); - } - static public function isAvailable() { if (!extension_loaded('apcu')) { return false; From 4d65a8089284e4dde09181b56fb45b86c50d6fb5 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Mon, 6 Jan 2014 13:11:38 +0100 Subject: [PATCH 023/181] Remove the static dependency on OC_Util from Memcache --- lib/private/memcache/cache.php | 2 +- lib/private/memcache/factory.php | 13 +++++++++++++ lib/private/server.php | 3 ++- lib/public/iservercontainer.php | 7 +++++++ 4 files changed, 23 insertions(+), 2 deletions(-) diff --git a/lib/private/memcache/cache.php b/lib/private/memcache/cache.php index 0ad1cc7ec0..03671b3f24 100644 --- a/lib/private/memcache/cache.php +++ b/lib/private/memcache/cache.php @@ -18,7 +18,7 @@ abstract class Cache implements \ArrayAccess { * @param string $prefix */ public function __construct($prefix = '') { - $this->prefix = \OC_Util::getInstanceId() . '/' . $prefix; + $this->prefix = $prefix; } public function getPrefix() { diff --git a/lib/private/memcache/factory.php b/lib/private/memcache/factory.php index fde7d94756..48c97b5955 100644 --- a/lib/private/memcache/factory.php +++ b/lib/private/memcache/factory.php @@ -9,6 +9,18 @@ namespace OC\Memcache; class Factory { + /** + * @var string $globalPrefix + */ + private $globalPrefix; + + /** + * @param string $globalPrefix + */ + public function __construct($globalPrefix) { + $this->globalPrefix = $globalPrefix; + } + /** * get a cache instance, will return null if no backend is available * @@ -16,6 +28,7 @@ class Factory { * @return \OC\Memcache\Cache */ function create($prefix = '') { + $prefix = $this->globalPrefix . '/' . $prefix; if (XCache::isAvailable()) { return new XCache($prefix); } elseif (APCu::isAvailable()) { diff --git a/lib/private/server.php b/lib/private/server.php index 84ee8cadf0..6b242bddd0 100644 --- a/lib/private/server.php +++ b/lib/private/server.php @@ -137,7 +137,8 @@ class Server extends SimpleContainer implements IServerContainer { return new UserCache(); }); $this->registerService('MemCache', function ($c) { - $factory = new \OC\Memcache\Factory(); + $instanceId = \OC_Util::getInstanceId(); + $factory = new \OC\Memcache\Factory($instanceId); return $factory->create(); }); $this->registerService('ActivityManager', function($c) { diff --git a/lib/public/iservercontainer.php b/lib/public/iservercontainer.php index b958d2d03f..7ac5049ef2 100644 --- a/lib/public/iservercontainer.php +++ b/lib/public/iservercontainer.php @@ -141,6 +141,13 @@ interface IServerContainer { */ function getCache(); + /** + * Returns an ICache instance + * + * @return \OCP\ICache + */ + function getMemCache(); + /** * Returns the current session * From be7837402d55abc9a6dc801c943c9b642e821dd0 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Wed, 8 Jan 2014 15:18:12 +0100 Subject: [PATCH 024/181] get the memorycache factory from OCP\Server instead of a cache instance this allows apps to specify a prefix to use --- lib/private/server.php | 11 +++++------ lib/public/cachefactory.php | 17 +++++++++++++++++ 2 files changed, 22 insertions(+), 6 deletions(-) create mode 100644 lib/public/cachefactory.php diff --git a/lib/private/server.php b/lib/private/server.php index 6b242bddd0..b5fa914862 100644 --- a/lib/private/server.php +++ b/lib/private/server.php @@ -136,10 +136,9 @@ class Server extends SimpleContainer implements IServerContainer { $this->registerService('UserCache', function($c) { return new UserCache(); }); - $this->registerService('MemCache', function ($c) { + $this->registerService('MemCacheFactory', function ($c) { $instanceId = \OC_Util::getInstanceId(); - $factory = new \OC\Memcache\Factory($instanceId); - return $factory->create(); + return new \OC\Memcache\Factory($instanceId); }); $this->registerService('ActivityManager', function($c) { return new ActivityManager(); @@ -303,10 +302,10 @@ class Server extends SimpleContainer implements IServerContainer { /** * Returns an ICache instance * - * @return \OCP\ICache + * @return \OCP\CacheFactory */ - function getMemCache() { - return $this->query('MemCache'); + function getMemCacheFactory() { + return $this->query('MemCacheFactory'); } /** diff --git a/lib/public/cachefactory.php b/lib/public/cachefactory.php new file mode 100644 index 0000000000..bb49aea7f3 --- /dev/null +++ b/lib/public/cachefactory.php @@ -0,0 +1,17 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OCP; + +interface CacheFactory{ + /** + * @param string $prefix + * @return $return \OCP\ICache + */ + public function create($prefix = ''); +} From 5a2a0426a6c01cffe88c80e0529931a323c699d9 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Wed, 8 Jan 2014 15:51:40 +0100 Subject: [PATCH 025/181] Also update the OCP\IServerContainer --- lib/private/server.php | 2 +- lib/public/iservercontainer.php | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/private/server.php b/lib/private/server.php index b5fa914862..6b034a5be9 100644 --- a/lib/private/server.php +++ b/lib/private/server.php @@ -300,7 +300,7 @@ class Server extends SimpleContainer implements IServerContainer { } /** - * Returns an ICache instance + * Returns an \OCP\CacheFactory instance * * @return \OCP\CacheFactory */ diff --git a/lib/public/iservercontainer.php b/lib/public/iservercontainer.php index 7ac5049ef2..67884bdc3e 100644 --- a/lib/public/iservercontainer.php +++ b/lib/public/iservercontainer.php @@ -142,11 +142,11 @@ interface IServerContainer { function getCache(); /** - * Returns an ICache instance + * Returns an \OCP\CacheFactory instance * - * @return \OCP\ICache + * @return \OCP\CacheFactory */ - function getMemCache(); + function getMemCacheFactory(); /** * Returns the current session From d50c7391d8e78c9555b073fb9ccc6a91d5da34bc Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Thu, 9 Jan 2014 13:54:50 +0100 Subject: [PATCH 026/181] Use $server->getMemCacheFactory() in ldap connection --- apps/user_ldap/lib/connection.php | 2 +- lib/public/cachefactory.php | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/apps/user_ldap/lib/connection.php b/apps/user_ldap/lib/connection.php index 14dfaa1174..92168a09ff 100644 --- a/apps/user_ldap/lib/connection.php +++ b/apps/user_ldap/lib/connection.php @@ -51,7 +51,7 @@ class Connection extends LDAPUtility { $this->configPrefix = $configPrefix; $this->configID = $configID; $this->configuration = new Configuration($configPrefix); - $memcache = new \OC\Memcache\Factory(); + $memcache = \OC::$server->getMemCacheFactory(); if($memcache->isAvailable()) { $this->cache = $memcache->create(); } else { diff --git a/lib/public/cachefactory.php b/lib/public/cachefactory.php index bb49aea7f3..1bb0ea3dd5 100644 --- a/lib/public/cachefactory.php +++ b/lib/public/cachefactory.php @@ -10,8 +10,17 @@ namespace OCP; interface CacheFactory{ /** + * Get a memory cache instance + * * @param string $prefix * @return $return \OCP\ICache */ public function create($prefix = ''); + + /** + * Check if a memory cache backend is available + * + * @return bool + */ + public function isAvailable(); } From 320353c237fbee2d9a8f12dd474feb3a0f6ddec6 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Mon, 9 Dec 2013 01:34:31 +0100 Subject: [PATCH 027/181] Add support for multiple memcached servers. --- config/config.sample.php | 10 ++++++++-- lib/private/memcache/memcached.php | 4 ++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/config/config.sample.php b/config/config.sample.php index 1070ef72ed..67152accc3 100755 --- a/config/config.sample.php +++ b/config/config.sample.php @@ -114,8 +114,14 @@ $CONFIG = array( /* Password to use for sendmail mail, depends on mail_smtpauth if this is used */ "mail_smtppassword" => "", -/* memcached hostname and port (Only used when xCache, APC and APCu are absent.) */ -"memcached_server" => array('localhost', 11211), +/* memcached servers (Only used when xCache, APC and APCu are absent.) */ +"memcached_servers" => array( + // hostname, port and optional weight. Also see: + // http://www.php.net/manual/en/memcached.addservers.php + // http://www.php.net/manual/en/memcached.addserver.php + array('localhost', 11211), + //array('other.host.local', 11211), +), /* How long should ownCloud keep deleted files in the trash bin, default value: 30 days */ 'trashbin_retention_obligation' => 30, diff --git a/lib/private/memcache/memcached.php b/lib/private/memcache/memcached.php index 978e6c2eff..13b1867231 100644 --- a/lib/private/memcache/memcached.php +++ b/lib/private/memcache/memcached.php @@ -18,8 +18,8 @@ class Memcached extends Cache { parent::__construct($prefix); if (is_null(self::$cache)) { self::$cache = new \Memcached(); - list($host, $port) = \OC_Config::getValue('memcached_server', array('localhost', 11211)); - self::$cache->addServer($host, $port); + $servers = \OC_Config::getValue('memcached_servers', array(array('localhost', 11211))); + self::$cache->addServers($servers); } } From acd81f6c694373a18a0ee9ba29075b9924603c25 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Fri, 10 Jan 2014 00:57:40 +0100 Subject: [PATCH 028/181] Readd support for memcached_server config variable. --- lib/private/memcache/memcached.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/private/memcache/memcached.php b/lib/private/memcache/memcached.php index 13b1867231..075828eeba 100644 --- a/lib/private/memcache/memcached.php +++ b/lib/private/memcache/memcached.php @@ -18,7 +18,15 @@ class Memcached extends Cache { parent::__construct($prefix); if (is_null(self::$cache)) { self::$cache = new \Memcached(); - $servers = \OC_Config::getValue('memcached_servers', array(array('localhost', 11211))); + $servers = \OC_Config::getValue('memcached_servers'); + if (!$servers) { + $server = \OC_Config::getValue('memcached_server'); + if ($server) { + $servers = array($server); + } else { + $servers = array(array('localhost', 11211)); + } + } self::$cache->addServers($servers); } } From 3ae17d0785e27528ce221e9c906df3127daa35fa Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Tue, 10 Dec 2013 01:45:15 +0100 Subject: [PATCH 029/181] Fix unallowed child elements --- core/templates/layout.user.php | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/core/templates/layout.user.php b/core/templates/layout.user.php index 89987625d6..dd2b209244 100644 --- a/core/templates/layout.user.php +++ b/core/templates/layout.user.php @@ -48,15 +48,16 @@ <?php p($theme->getName()); ?> - +
From d95cab632b167c597c10da59d3b44715a9e6c2b4 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Tue, 10 Dec 2013 01:58:19 +0100 Subject: [PATCH 030/181] Extend margin to avoid displaying a scrollbar --- core/css/styles.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/css/styles.css b/core/css/styles.css index df01456708..ea98fbadb6 100644 --- a/core/css/styles.css +++ b/core/css/styles.css @@ -671,7 +671,7 @@ label.infield { cursor:text !important; top:1.05em; left:.85em; } /* Apps management as sticky footer, less obtrusive in the list */ #navigation .wrapper { min-height: 100%; - margin: 0 auto -72px; + margin: 0 auto -82px 0; } #apps-management, #navigation .push { height: 72px; From 17c00f34d38d5d51f03ae1cf35d042df8eda8820 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Tue, 10 Dec 2013 01:46:20 +0100 Subject: [PATCH 031/181] Add alt attribute for img elements --- core/templates/layout.user.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/templates/layout.user.php b/core/templates/layout.user.php index dd2b209244..bc1c700402 100644 --- a/core/templates/layout.user.php +++ b/core/templates/layout.user.php @@ -51,7 +51,7 @@
- +
@@ -91,7 +91,7 @@
  • class="active"> - + @@ -110,7 +110,7 @@
  • class="active"> - + t('Apps')); ?> From 0802b662be298fac5787576007233f8ce456581c Mon Sep 17 00:00:00 2001 From: Myles McNamara Date: Fri, 10 Jan 2014 12:20:31 -0500 Subject: [PATCH 032/181] fix upload button layout --- apps/files_sharing/templates/public.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/apps/files_sharing/templates/public.php b/apps/files_sharing/templates/public.php index 1d527dca8e..a427e3d8f2 100644 --- a/apps/files_sharing/templates/public.php +++ b/apps/files_sharing/templates/public.php @@ -24,9 +24,10 @@ - Download" - />t('Download'))?> + + Download" /> + t('Download'))?> + @@ -43,9 +44,10 @@ -
    + From 9ebffd663532bb74075e6858559eb6506004a7c5 Mon Sep 17 00:00:00 2001 From: Myles McNamara Date: Fri, 10 Jan 2014 14:03:55 -0500 Subject: [PATCH 033/181] remove extra upload controls --- apps/files_sharing/templates/public.php | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/apps/files_sharing/templates/public.php b/apps/files_sharing/templates/public.php index a427e3d8f2..8b5e097641 100644 --- a/apps/files_sharing/templates/public.php +++ b/apps/files_sharing/templates/public.php @@ -53,20 +53,8 @@
  • - -
    From 97be32e2e8291f3c5412bc9cbbdeda38552bbb81 Mon Sep 17 00:00:00 2001 From: Myles McNamara Date: Fri, 10 Jan 2014 14:07:20 -0500 Subject: [PATCH 034/181] modify js to move upload wrapper, modify css to match core values --- apps/files_sharing/css/public.css | 17 ++++++++++------- apps/files_sharing/js/public.js | 3 ++- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/apps/files_sharing/css/public.css b/apps/files_sharing/css/public.css index 060d4dfedc..be53a7d8a8 100644 --- a/apps/files_sharing/css/public.css +++ b/apps/files_sharing/css/public.css @@ -141,10 +141,13 @@ thead{ .directLink { margin-bottom: 20px; } - .directLink label { - font-weight: normal; - } - .directLink input { - margin-left: 10px; - width: 300px; - } +.directLink label { + font-weight: normal; +} +.directLink input { + margin-left: 10px; + width: 300px; +} +.public_actions { + padding: 0.3em; +} diff --git a/apps/files_sharing/js/public.js b/apps/files_sharing/js/public.js index eacd4096ed..88dbac9c88 100644 --- a/apps/files_sharing/js/public.js +++ b/apps/files_sharing/js/public.js @@ -59,7 +59,8 @@ $(document).ready(function() { }); // Add Uploadprogress Wrapper to controls bar - $('#controls').append($('#additional_controls div#uploadprogresswrapper')); + $('#controls').append($('#controls .actions div#uploadprogresswrapper')); + $('#uploadprogresswrapper').addClass('public_actions'); // Cancel upload trigger $('#cancel_upload_button').click(function() { From 6f21da12e8c953bebdbd444460b07160821ba7a8 Mon Sep 17 00:00:00 2001 From: Georg Ehrke Date: Sat, 11 Jan 2014 12:07:28 +0100 Subject: [PATCH 035/181] encode imagePath and fix documentation of loadFromFile --- lib/private/image.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/private/image.php b/lib/private/image.php index 314a4216b8..91a9f91e1d 100644 --- a/lib/private/image.php +++ b/lib/private/image.php @@ -409,14 +409,14 @@ class OC_Image { /** * @brief Loads an image from a local file. - * @param $imageref The path to a local file. + * @param $imagePath The path to a local file. * @returns An image resource or false on error */ public function loadFromFile($imagePath=false) { // exif_imagetype throws "read error!" if file is less than 12 byte if(!@is_file($imagePath) || !file_exists($imagePath) || filesize($imagePath) < 12 || !is_readable($imagePath)) { // Debug output disabled because this method is tried before loadFromBase64? - OC_Log::write('core', 'OC_Image->loadFromFile, couldn\'t load: ' . (string) $imagePath, OC_Log::DEBUG); + OC_Log::write('core', 'OC_Image->loadFromFile, couldn\'t load: ' . (string) urlencode($imagePath), OC_Log::DEBUG); return false; } $iType = exif_imagetype($imagePath); From 2bdd014f83979d3a332775b39bb139c567c34e64 Mon Sep 17 00:00:00 2001 From: Jan-Christoph Borchardt Date: Tue, 14 Jan 2014 22:14:06 +0100 Subject: [PATCH 036/181] first mobile style rules, hide extra columns in files view and scroll header --- apps/files_sharing/css/mobile.css | 18 ++++++++++++++++++ apps/files_sharing/public.php | 1 + 2 files changed, 19 insertions(+) create mode 100644 apps/files_sharing/css/mobile.css diff --git a/apps/files_sharing/css/mobile.css b/apps/files_sharing/css/mobile.css new file mode 100644 index 0000000000..55d244ff1e --- /dev/null +++ b/apps/files_sharing/css/mobile.css @@ -0,0 +1,18 @@ +@media only screen and (max-width: 600px) { + +/* make header and controls bar scroll up for more view of content on small screens */ +#header, +#controls { + position: absolute; +} + +/* hide size and date columns */ +table th#headerSize, +table td.filesize, +table th#headerDate, +table td.date { + display: none; +} + + +} diff --git a/apps/files_sharing/public.php b/apps/files_sharing/public.php index f4042f6524..ae0a62f103 100644 --- a/apps/files_sharing/public.php +++ b/apps/files_sharing/public.php @@ -136,6 +136,7 @@ if (isset($path)) { } else { OCP\Util::addScript('files', 'file-upload'); OCP\Util::addStyle('files_sharing', 'public'); + OCP\Util::addStyle('files_sharing', 'mobile'); OCP\Util::addScript('files_sharing', 'public'); OCP\Util::addScript('files', 'fileactions'); OCP\Util::addScript('files', 'jquery.iframe-transport'); From 072ef7f010ca9f48119bc2397a82fdd0aac76beb Mon Sep 17 00:00:00 2001 From: Jan-Christoph Borchardt Date: Tue, 14 Jan 2014 22:14:46 +0100 Subject: [PATCH 037/181] remove min-width rule to fix mobile views --- apps/files/css/files.css | 3 --- 1 file changed, 3 deletions(-) diff --git a/apps/files/css/files.css b/apps/files/css/files.css index 2fc86ca537..74320aba32 100644 --- a/apps/files/css/files.css +++ b/apps/files/css/files.css @@ -65,9 +65,6 @@ top: 44px; width: 100%; } -#filestable, #controls { - min-width: 680px; -} #filestable tbody tr { background-color:#fff; height:2.5em; } #filestable tbody tr:hover, tbody tr:active { background-color: rgb(240,240,240); From dbbbfee7deb4778e4a6c0a96a50d022a414584ae Mon Sep 17 00:00:00 2001 From: Pellaeon Lin Date: Wed, 15 Jan 2014 12:36:27 +0800 Subject: [PATCH 038/181] Fix namespace --- apps/files/lib/helper.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/files/lib/helper.php b/apps/files/lib/helper.php index 2f4a979066..e2f545e9e3 100644 --- a/apps/files/lib/helper.php +++ b/apps/files/lib/helper.php @@ -6,7 +6,7 @@ class Helper { public static function buildFileStorageStatistics($dir) { $l = new \OC_L10N('files'); - $freeSpace=OCP\Util::freeSpace($dir); + $freeSpace=\OCP\Util::freeSpace($dir); $maxUploadFilesize = \OCP\Util::maxUploadFilesize($dir); $maxHumanFilesize = \OCP\Util::humanFileSize($maxUploadFilesize); $maxHumanFilesize = $l->t('Upload') . ' max. ' . $maxHumanFilesize; From 807b885a0e83841b51b694afbb4b377e39215b0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Wed, 15 Jan 2014 14:36:18 +0100 Subject: [PATCH 039/181] reuse file upload as used within files app - remove public upload button --- apps/files/templates/index.php | 8 +++- apps/files_sharing/public.php | 3 +- apps/files_sharing/templates/public.php | 54 +------------------------ 3 files changed, 10 insertions(+), 55 deletions(-) diff --git a/apps/files/templates/index.php b/apps/files/templates/index.php index 00ec109621..d7f479b504 100644 --- a/apps/files/templates/index.php +++ b/apps/files/templates/index.php @@ -18,6 +18,10 @@ + + + + @@ -26,7 +30,7 @@
    - > + >
    @@ -44,7 +48,7 @@
    class="hidden">t('Nothing in here. Upload something!'))?>
    - + diff --git a/apps/files_sharing/public.php b/apps/files_sharing/public.php index ae0a62f103..e3d6895543 100644 --- a/apps/files_sharing/public.php +++ b/apps/files_sharing/public.php @@ -225,7 +225,8 @@ if (isset($path)) { $folder->assign('fileList', $list->fetchPage()); $folder->assign('breadcrumb', $breadcrumbNav->fetchPage()); $folder->assign('dir', $getPath); - $folder->assign('isCreatable', false); + $folder->assign('isCreatable', $allowPublicUploadEnabled); + $folder->assign('dirToken', $linkItem['token']); $folder->assign('permissions', OCP\PERMISSION_READ); $folder->assign('isPublic',true); $folder->assign('publicUploadEnabled', 'no'); diff --git a/apps/files_sharing/templates/public.php b/apps/files_sharing/templates/public.php index 1d527dca8e..d82e567182 100644 --- a/apps/files_sharing/templates/public.php +++ b/apps/files_sharing/templates/public.php @@ -14,57 +14,7 @@ src="" alt="getName()); ?>" />
    - - t('%s shared the folder %s with you', - array($_['displayName'], $_['filename']))) ?> - - t('%s shared the file %s with you', - array($_['displayName'], $_['filename']))) ?> - - - - - Download" - />t('Download'))?> - - - - - - - - - - - = 0):?> - - - - - - -
    - -
    @@ -96,7 +46,7 @@ - +
    From 6c76b4ba1253a37316f7de964494b05099c66e21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Wed, 15 Jan 2014 15:07:24 +0100 Subject: [PATCH 040/181] fixing preview generation --- apps/files/js/files.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/files/js/files.js b/apps/files/js/files.js index fdaa3aa334..d5e8450f41 100644 --- a/apps/files/js/files.js +++ b/apps/files/js/files.js @@ -717,7 +717,7 @@ Files.lazyLoadPreview = function(path, mime, ready, width, height, etag) { console.warn('Files.lazyLoadPreview(): missing etag argument'); } - if ( $('#publicUploadButtonMock').length ) { + if ( $('#isPublic').length ) { urlSpec.t = $('#dirToken').val(); previewURL = OC.Router.generate('core_ajax_public_preview', urlSpec); } else { From ce231c406dfafdedbe97baa5a3c3612b4428b79d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Wed, 15 Jan 2014 15:07:52 +0100 Subject: [PATCH 041/181] no new menu on public upload --- apps/files/templates/index.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/files/templates/index.php b/apps/files/templates/index.php index d7f479b504..a69407805d 100644 --- a/apps/files/templates/index.php +++ b/apps/files/templates/index.php @@ -1,6 +1,7 @@
    +
    t('New'));?>
      @@ -12,6 +13,7 @@ data-type='web'>

      t('From link'));?>

    +
    = 0):?> From b3a668378484ad65c601964d84a0b70e7f93318e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Wed, 15 Jan 2014 15:22:40 +0100 Subject: [PATCH 042/181] remove unused js code and css rules --- apps/files_sharing/css/public.css | 49 ------------------------------- apps/files_sharing/js/public.js | 11 ------- 2 files changed, 60 deletions(-) diff --git a/apps/files_sharing/css/public.css b/apps/files_sharing/css/public.css index 060d4dfedc..16d115f6e9 100644 --- a/apps/files_sharing/css/public.css +++ b/apps/files_sharing/css/public.css @@ -19,16 +19,6 @@ body { float: left; } -#public_upload, -#download { - font-weight:700; - margin: 0 0 0 .4em; - padding: 0 5px; - height: 32px; - float: left; - -} - .header-right #details { margin-right: 28px; } @@ -38,17 +28,6 @@ body { height: 32px; } -#public_upload { - margin-left: 0.3em; -} - -#public_upload img, -#download img { - padding-left:.1em; - padding-right:.3em; - vertical-align:text-bottom; -} - #controls { left: 0; } @@ -110,34 +89,6 @@ thead{ margin: 0; } -#file_upload_start { - -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; - filter: alpha(opacity=0); - opacity: 0; - z-index: 20; - position: absolute !important; - top: 0; - left: 0; - width: 100% !important; -} - -#publicUploadButtonMock { - position:relative; - display:block; - width:100%; - height:32px; - cursor:pointer; - z-index:10; - background-image:url('%webroot%/core/img/actions/upload.svg'); - background-repeat:no-repeat; - background-position:7px 8px; -} - -#publicUploadButtonMock span { - margin: 0 5px 0 28px; - color: #555; -} - .directLink { margin-bottom: 20px; } diff --git a/apps/files_sharing/js/public.js b/apps/files_sharing/js/public.js index eacd4096ed..63e1ccaadf 100644 --- a/apps/files_sharing/js/public.js +++ b/apps/files_sharing/js/public.js @@ -9,8 +9,6 @@ function fileDownloadPath(dir, file) { $(document).ready(function() { - $('#data-upload-form').tipsy({gravity:'ne', fade:true}); - if (typeof FileActions !== 'undefined') { var mimetype = $('#mimetype').val(); // Show file preview if previewer is available, images are already handled by the template @@ -58,15 +56,6 @@ $(document).ready(function() { }; }); - // Add Uploadprogress Wrapper to controls bar - $('#controls').append($('#additional_controls div#uploadprogresswrapper')); - - // Cancel upload trigger - $('#cancel_upload_button').click(function() { - OC.Upload.cancelUploads(); - procesSelection(); - }); - $('#directLink').focus(); }); From 50ae2ab14c1ae852ff98cee9ae10a4b9218bd1db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Wed, 15 Jan 2014 15:31:27 +0100 Subject: [PATCH 043/181] add download button on single file share page --- apps/files_sharing/templates/public.php | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/apps/files_sharing/templates/public.php b/apps/files_sharing/templates/public.php index d82e567182..e181e8a328 100644 --- a/apps/files_sharing/templates/public.php +++ b/apps/files_sharing/templates/public.php @@ -40,13 +40,19 @@ - + +
    From db837bf696951e3c866205a2d690bf3c014babeb Mon Sep 17 00:00:00 2001 From: Jan-Christoph Borchardt Date: Wed, 15 Jan 2014 14:45:10 +0100 Subject: [PATCH 044/181] improvements to public files mobile view --- apps/files/css/files.css | 2 +- apps/files_sharing/css/mobile.css | 15 ++++++++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/apps/files/css/files.css b/apps/files/css/files.css index 74320aba32..4beb01a4e6 100644 --- a/apps/files/css/files.css +++ b/apps/files/css/files.css @@ -234,7 +234,7 @@ table td.filename form { font-size:.85em; margin-left:3em; margin-right:3em; } #fileList tr td.filename a.name label { position: absolute; - width: 100%; + width: 80%; height: 50px; } diff --git a/apps/files_sharing/css/mobile.css b/apps/files_sharing/css/mobile.css index 55d244ff1e..3578aff17f 100644 --- a/apps/files_sharing/css/mobile.css +++ b/apps/files_sharing/css/mobile.css @@ -1,10 +1,5 @@ @media only screen and (max-width: 600px) { -/* make header and controls bar scroll up for more view of content on small screens */ -#header, -#controls { - position: absolute; -} /* hide size and date columns */ table th#headerSize, @@ -14,5 +9,15 @@ table td.date { display: none; } +/* restrict length of displayed filename to prevent overflow */ +table td.filename .nametext { + max-width: 80% !important; +} +/* and to make room for download button on hover */ +table tr:hover td.filename .nametext, +table tr:focus td.filename .nametext { + max-width: 60% !important; +} + } From 5f95356592b12c81b8c2e0f32c890cdbd069e82c Mon Sep 17 00:00:00 2001 From: Jan-Christoph Borchardt Date: Wed, 15 Jan 2014 14:49:41 +0100 Subject: [PATCH 045/181] remove unused log icon --- settings/img/log Icon License | 2 -- settings/img/log.png | Bin 342 -> 0 bytes settings/img/log.svg | 10 ---------- 3 files changed, 12 deletions(-) delete mode 100644 settings/img/log Icon License delete mode 100644 settings/img/log.png delete mode 100644 settings/img/log.svg diff --git a/settings/img/log Icon License b/settings/img/log Icon License deleted file mode 100644 index b5c3167d73..0000000000 --- a/settings/img/log Icon License +++ /dev/null @@ -1,2 +0,0 @@ -CC BY 3.0 -http://thenounproject.com/en-us/noun/printer/#icon-No109 \ No newline at end of file diff --git a/settings/img/log.png b/settings/img/log.png deleted file mode 100644 index b34a58f844cdcb1005b58cd488da2701802ca0b2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 342 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|*pj^6T^Rm@ z;DWu&Cj&(|3p^r=f!eQwFr$;k>5cfkM|jT^vI!PA4Zg zFxA!7d3PM-*})L!nRI1BD#NVL(*z%~Zjg$PzyH(W&T$5nf6O1{75=#?)o~wTKfuP| zJLjl_62nWzmrK_%D%e|ESZrW;nUy1 b%D`|k;$e?l%+6atA2N8l`njxgN@xNA=P-B4 diff --git a/settings/img/log.svg b/settings/img/log.svg deleted file mode 100644 index a3939b7309..0000000000 --- a/settings/img/log.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - From 3e7cf4110dc5bce2241830ed8ab0ddb57791442a Mon Sep 17 00:00:00 2001 From: Jan-Christoph Borchardt Date: Wed, 15 Jan 2014 15:34:14 +0100 Subject: [PATCH 046/181] tweak color and position of username in public share --- apps/files_sharing/css/public.css | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/apps/files_sharing/css/public.css b/apps/files_sharing/css/public.css index 16d115f6e9..54a25d0ce3 100644 --- a/apps/files_sharing/css/public.css +++ b/apps/files_sharing/css/public.css @@ -14,20 +14,19 @@ body { padding:7px; } -#details { - color:#fff; - float: left; -} - -.header-right #details { - margin-right: 28px; -} - .header-right { padding: 0; height: 32px; } +#details { + color:#fff; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=50)"; + filter: alpha(opacity=50); + opacity: .5; + padding-right: 5px; +} + #controls { left: 0; } From 62040fe2d2cacafb3b534ff7de2cded7ca64daf4 Mon Sep 17 00:00:00 2001 From: Myles McNamara Date: Wed, 15 Jan 2014 17:06:48 -0500 Subject: [PATCH 047/181] change em to px --- apps/files_sharing/css/public.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/files_sharing/css/public.css b/apps/files_sharing/css/public.css index be53a7d8a8..f4121430b9 100644 --- a/apps/files_sharing/css/public.css +++ b/apps/files_sharing/css/public.css @@ -149,5 +149,5 @@ thead{ width: 300px; } .public_actions { - padding: 0.3em; + padding: 4px; } From f975fd54996fd994f0fa9628d4eba42d92406792 Mon Sep 17 00:00:00 2001 From: raghunayyar Date: Thu, 16 Jan 2014 14:23:39 +0530 Subject: [PATCH 048/181] Fixes Trashbin and Files Style Conflicts, more em to px conversions post rebase --- apps/files/css/files.css | 12 ++++++------ apps/files_trashbin/css/trash.css | 2 ++ apps/files_trashbin/templates/index.php | 4 ++-- core/css/styles.css | 3 ++- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/apps/files/css/files.css b/apps/files/css/files.css index 9c689c05ec..8edca4cd3c 100644 --- a/apps/files/css/files.css +++ b/apps/files/css/files.css @@ -144,7 +144,7 @@ table.multiselect #headerName { position: relative; width: 100%; } -table td.selection, table th.selection, table td.fileaction { width:2em; text-align:center; } +table td.selection, table th.selection, table td.fileaction { width:32px; text-align:center; } table td.filename a.name { position:relative; /* Firefox needs to explicitly have this default set … */ -moz-box-sizing: border-box; @@ -162,8 +162,8 @@ table td.filename input.filename { margin-left: 2px; cursor: text; } -table td.filename a, table td.login, table td.logout, table td.download, table td.upload, table td.create, table td.delete { padding:.2em .5em .5em .3em; } -table td.filename .nametext, .uploadtext, .modified { float:left; padding:.3em 0; } +table td.filename a, table td.login, table td.logout, table td.download, table td.upload, table td.create, table td.delete { padding:3px 8px 8px 3px; } +table td.filename .nametext, .uploadtext, .modified { float:left; padding:14px 0; } #modified { position: absolute; @@ -184,7 +184,7 @@ table td.filename .nametext { max-width: 800px; } table td.filename .uploadtext { font-weight:normal; margin-left:8px; } -table td.filename form { font-size:.85em; margin-left:48px; margin-right:48px; } +table td.filename form { font-size:14px; margin-left:48px; margin-right:48px; } .ie8 input[type="checkbox"]{ padding: 0; @@ -252,11 +252,11 @@ table td.filename form { font-size:.85em; margin-left:48px; margin-right:48px; } right: 0; } -#fileList img.move2trash { display:inline; margin:-.5em 0; padding:16px 8px 16px 8px !important; float:right; } +#fileList img.move2trash { display:inline; margin:-8px 0; padding:16px 8px 16px 8px !important; float:right; } #fileList a.action.delete { position: absolute; right: 0; - padding: 9px 14px 19px !important; + padding: 28px 14px 19px !important; } a.action>img { max-height:16px; max-width:16px; vertical-align:text-bottom; } diff --git a/apps/files_trashbin/css/trash.css b/apps/files_trashbin/css/trash.css index 97819f4e80..a85ee3f5a6 100644 --- a/apps/files_trashbin/css/trash.css +++ b/apps/files_trashbin/css/trash.css @@ -1,3 +1,5 @@ #fileList td a.file, #fileList td a.file span { cursor: default; } +.trash-controls { top: 45px; } +.trash-filestable { top: 5px !important; } /* To avoid the clashes with #filestable in files */ \ No newline at end of file diff --git a/apps/files_trashbin/templates/index.php b/apps/files_trashbin/templates/index.php index f9264d4352..45851d7f49 100644 --- a/apps/files_trashbin/templates/index.php +++ b/apps/files_trashbin/templates/index.php @@ -1,4 +1,4 @@ -
    +
    @@ -10,7 +10,7 @@ -
    +
    diff --git a/core/css/styles.css b/core/css/styles.css index df01456708..1fe40f987e 100644 --- a/core/css/styles.css +++ b/core/css/styles.css @@ -229,6 +229,7 @@ input[type="submit"].enabled { -webkit-box-sizing: border-box; box-sizing: border-box; position: fixed; + /*top: 45px;*/ right: 0; left: 0; height: 44px; @@ -264,7 +265,7 @@ input[type="submit"].enabled { top: 45px; } #content-wrapper { - position:absolute; height:100%; width:100%; padding-top:3.5em; padding-left:80px; + position:absolute; height:100%; width:100%; padding-left:80px;padding-top: 45px; -moz-box-sizing:border-box; box-sizing:border-box; } #leftcontent, .leftcontent { From fd49d3c5c5932bef4674a76f259ea5612f3130b4 Mon Sep 17 00:00:00 2001 From: raghunayyar Date: Thu, 16 Jan 2014 14:45:23 +0530 Subject: [PATCH 049/181] Fixes typo in versions.css --- apps/files_versions/css/versions.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/files_versions/css/versions.css b/apps/files_versions/css/versions.css index 8838ea8484..80fa196b72 100644 --- a/apps/files_versions/css/versions.css +++ b/apps/files_versions/css/versions.css @@ -1,5 +1,5 @@ #dropdown.drop-versions { - width:384em; + width:384px; } #found_versions li { From cd6ab2931325323cb59961c4327a18d934ecc72a Mon Sep 17 00:00:00 2001 From: Pellaeon Lin Date: Thu, 16 Jan 2014 17:51:00 +0800 Subject: [PATCH 050/181] Use t() 's native method --- apps/files/js/file-upload.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/files/js/file-upload.js b/apps/files/js/file-upload.js index 1a36a58053..a003e5eec8 100644 --- a/apps/files/js/file-upload.js +++ b/apps/files/js/file-upload.js @@ -236,13 +236,19 @@ $(document).ready(function() { // check PHP upload limit if (selection.totalBytes > $('#upload_limit').val()) { data.textStatus = 'sizeexceedlimit'; - data.errorThrown = t('files', 'Total file size {size1} exceeds upload limit {size2}').replace('{size1}', humanFileSize(selection.totalBytes)).replace('{size2}', humanFileSize($('#upload_limit').val())); + data.errorThrown = t('files', 'Total file size {size1} exceeds upload limit {size2}', { + 'size1': humanFileSize(selection.totalBytes), + 'size2': humanFileSize($('#upload_limit').val()) + }); } // check free space if (selection.totalBytes > $('#free_space').val()) { data.textStatus = 'notenoughspace'; - data.errorThrown = t('files', 'Not enough free space, you are uploading {size1} but only {size2} is left').replace('{size1}', humanFileSize(selection.totalBytes)).replace('{size2}', humanFileSize($('#free_space').val())); + data.errorThrown = t('files', 'Not enough free space, you are uploading {size1} but only {size2} is left', { + '{size1}': humanFileSize(selection.totalBytes), + '{size2}': humanFileSize($('#free_space').val()) + }); } // end upload for whole selection on error From 2233aa2a049f0b0fcb3a8f24fe2957d926339a93 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Thu, 16 Jan 2014 12:05:05 +0100 Subject: [PATCH 051/181] Fixed files row height in Firefox/KDE Firefox is using native checkboxes and in KDE the checkboxes have a bigger height which caused the row height to increase and be misaligned with the date column. This fix makes the checkbox absolute to prevent it to influence the row height. --- apps/files/css/files.css | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/files/css/files.css b/apps/files/css/files.css index 8edca4cd3c..b93cc458dd 100644 --- a/apps/files/css/files.css +++ b/apps/files/css/files.css @@ -219,6 +219,11 @@ table td.filename form { font-size:14px; margin-left:48px; margin-right:48px; } width: 50px; z-index: 5; } +#fileList tr td.filename>input[type="checkbox"]{ + /* sometimes checkbox height is bigger (KDE/Qt), so setting to absolute + * to prevent it to increase the height */ + position: absolute; +} #fileList tr td.filename>input[type="checkbox"] + label { left: 0; } From 6ec50e4b0c435789732186eb3c6839883061e5a8 Mon Sep 17 00:00:00 2001 From: Pellaeon Lin Date: Thu, 16 Jan 2014 19:48:46 +0800 Subject: [PATCH 052/181] Comments to clarify --- apps/files/index.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/files/index.php b/apps/files/index.php index 4ea0f9f249..c8b04bd462 100644 --- a/apps/files/index.php +++ b/apps/files/index.php @@ -136,10 +136,10 @@ if ($needUpgrade) { $tmpl->assign('files', $files); $tmpl->assign('trash', $trashEnabled); $tmpl->assign('trashEmpty', $trashEmpty); - $tmpl->assign('uploadMaxFilesize', $maxUploadFilesize); + $tmpl->assign('uploadMaxFilesize', $maxUploadFilesize); // minimium of freeSpace and uploadLimit $tmpl->assign('uploadMaxHumanFilesize', OCP\Util::humanFileSize($maxUploadFilesize)); $tmpl->assign('freeSpace', $freeSpace); - $tmpl->assign('uploadLimit', $uploadLimit); + $tmpl->assign('uploadLimit', $uploadLimit); // PHP upload limit $tmpl->assign('allowZipDownload', intval(OCP\Config::getSystemValue('allowZipDownload', true))); $tmpl->assign('usedSpacePercent', (int)$storageInfo['relative']); $tmpl->assign('isPublic', false); From d36da7e43abc716247fcc6252466f5a848cbbbed Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Thu, 16 Jan 2014 12:58:17 +0100 Subject: [PATCH 053/181] use appstoreenabled config switch --- settings/templates/apps.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/settings/templates/apps.php b/settings/templates/apps.php index bf2f178ca1..bd38714450 100644 --- a/settings/templates/apps.php +++ b/settings/templates/apps.php @@ -9,7 +9,7 @@
      - +
    • t('Add your App'));?> …
    • @@ -26,7 +26,7 @@ - +
    • t('More Apps'));?> …
    • From c0590676a005c0890e43b7a2b2950fee2758efef Mon Sep 17 00:00:00 2001 From: Jan-Christoph Borchardt Date: Thu, 16 Jan 2014 15:28:39 +0100 Subject: [PATCH 054/181] fix public share download button width --- apps/files_sharing/css/public.css | 9 ++++++++- apps/files_sharing/templates/public.php | 6 +++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/apps/files_sharing/css/public.css b/apps/files_sharing/css/public.css index 54a25d0ce3..d593d353dd 100644 --- a/apps/files_sharing/css/public.css +++ b/apps/files_sharing/css/public.css @@ -88,13 +88,20 @@ thead{ margin: 0; } +.directDownload, .directLink { margin-bottom: 20px; } + .directDownload .button img { + vertical-align: text-bottom; + } .directLink label { font-weight: normal; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=50)"; + filter: alpha(opacity=50); + opacity: .5; } .directLink input { - margin-left: 10px; + margin-left: 5px; width: 300px; } diff --git a/apps/files_sharing/templates/public.php b/apps/files_sharing/templates/public.php index e181e8a328..fb45401458 100644 --- a/apps/files_sharing/templates/public.php +++ b/apps/files_sharing/templates/public.php @@ -43,9 +43,9 @@
    -
    - - Download"/> + From 5cdab5fff3bcdbeb9107960f97c9006401a9168a Mon Sep 17 00:00:00 2001 From: Jan-Christoph Borchardt Date: Thu, 16 Jan 2014 15:32:23 +0100 Subject: [PATCH 055/181] show publicly shared image on full width, without margin --- apps/files_sharing/css/public.css | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/apps/files_sharing/css/public.css b/apps/files_sharing/css/public.css index d593d353dd..75c37f6a1c 100644 --- a/apps/files_sharing/css/public.css +++ b/apps/files_sharing/css/public.css @@ -60,11 +60,9 @@ p.info a { } #imgframe { - height:75%; - padding-bottom:2em; - padding-top:2em; - width:80%; - margin:0 auto; + width: 100%; + padding: 0; + margin-bottom: 35px; } #imgframe img { From d463edaf0943b82b2f3faeb0f134f9b88d28c32c Mon Sep 17 00:00:00 2001 From: Jan-Christoph Borchardt Date: Thu, 16 Jan 2014 15:56:18 +0100 Subject: [PATCH 056/181] on mobile, show single shared image at full width without margin --- apps/files_sharing/css/mobile.css | 7 +++++++ apps/files_sharing/css/public.css | 8 +++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/apps/files_sharing/css/mobile.css b/apps/files_sharing/css/mobile.css index 3578aff17f..2118cd31e4 100644 --- a/apps/files_sharing/css/mobile.css +++ b/apps/files_sharing/css/mobile.css @@ -19,5 +19,12 @@ table tr:focus td.filename .nametext { max-width: 60% !important; } +/* on mobile, show single shared image at full width without margin */ +#imgframe { + width: 100%; + padding: 0; + margin-bottom: 35px; +} + } diff --git a/apps/files_sharing/css/public.css b/apps/files_sharing/css/public.css index 75c37f6a1c..d593d353dd 100644 --- a/apps/files_sharing/css/public.css +++ b/apps/files_sharing/css/public.css @@ -60,9 +60,11 @@ p.info a { } #imgframe { - width: 100%; - padding: 0; - margin-bottom: 35px; + height:75%; + padding-bottom:2em; + padding-top:2em; + width:80%; + margin:0 auto; } #imgframe img { From b7b83377c57189d262d3c2f92cdb864b35afc3b1 Mon Sep 17 00:00:00 2001 From: raghunayyar Date: Thu, 16 Jan 2014 21:00:15 +0530 Subject: [PATCH 057/181] Fixes header going down in trash bin app. --- apps/files_trashbin/css/trash.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/files_trashbin/css/trash.css b/apps/files_trashbin/css/trash.css index a85ee3f5a6..b32c2df591 100644 --- a/apps/files_trashbin/css/trash.css +++ b/apps/files_trashbin/css/trash.css @@ -2,4 +2,4 @@ cursor: default; } .trash-controls { top: 45px; } -.trash-filestable { top: 5px !important; } /* To avoid the clashes with #filestable in files */ \ No newline at end of file +.trash-filestable { top: -35px !important; } /* To avoid the clashes with #filestable in files */ \ No newline at end of file From 12e5d0f68d2ba8c780482a4e808c4aeec5ec17d9 Mon Sep 17 00:00:00 2001 From: raghunayyar Date: Thu, 16 Jan 2014 21:06:14 +0530 Subject: [PATCH 058/181] Fixes typos, adds ; wherever not present. --- apps/files_sharing/css/public.css | 2 +- core/css/jquery.multiselect.css | 36 +++++++++++++++---------------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/apps/files_sharing/css/public.css b/apps/files_sharing/css/public.css index e948811c03..bf0a5f60a8 100644 --- a/apps/files_sharing/css/public.css +++ b/apps/files_sharing/css/public.css @@ -61,7 +61,7 @@ body { #noPreview { display:none; - padding-top:90px; + padding-top:80px; } footer { diff --git a/core/css/jquery.multiselect.css b/core/css/jquery.multiselect.css index 6b3ae47d6e..9b81c3bdcf 100644 --- a/core/css/jquery.multiselect.css +++ b/core/css/jquery.multiselect.css @@ -1,23 +1,23 @@ -.ui-multiselect { padding:2px 0 2px 4px; text-align:left } -.ui-multiselect span.ui-icon { float:right } +.ui-multiselect { padding:2px 0 2px 4px; text-align:left; } +.ui-multiselect span.ui-icon { float:right; } .ui-multiselect-single .ui-multiselect-checkboxes input { position:absolute !important; top: auto !important; left:-9999px; } -.ui-multiselect-single .ui-multiselect-checkboxes label { padding:5px !important } +.ui-multiselect-single .ui-multiselect-checkboxes label { padding:5px !important; } -.ui-multiselect-header { margin-bottom:3px; padding:3px 0 3px 4px } -.ui-multiselect-header ul { font-size:15px } -.ui-multiselect-header ul li { float:left; padding:0 10px 0 0 } -.ui-multiselect-header a { text-decoration:none } -.ui-multiselect-header a:hover { text-decoration:underline } -.ui-multiselect-header span.ui-icon { float:left } -.ui-multiselect-header li.ui-multiselect-close { float:right; text-align:right; padding-right:0 } +.ui-multiselect-header { margin-bottom:3px; padding:3px 0 3px 4px; } +.ui-multiselect-header ul { font-size:14px; } +.ui-multiselect-header ul li { float:left; padding:0 10px 0 0; } +.ui-multiselect-header a { text-decoration:none; } +.ui-multiselect-header a:hover { text-decoration:underline; } +.ui-multiselect-header span.ui-icon { float:left;} +.ui-multiselect-header li.ui-multiselect-close { float:right; text-align:right; padding-right:0; } -.ui-multiselect-menu { display:none; padding:3px; position:absolute; z-index:10000; text-align: left } -.ui-multiselect-checkboxes { position:relative /* fixes bug in IE6/7 */; overflow-y:scroll } -.ui-multiselect-checkboxes label { cursor:default; display:block; border:1px solid transparent; padding:3px 1px } -.ui-multiselect-checkboxes label input { position:relative; top:1px } -.ui-multiselect-checkboxes li { clear:both; font-size:0.9em; padding-right:3px } -.ui-multiselect-checkboxes li.ui-multiselect-optgroup-label { text-align:center; font-weight:bold; border-bottom:1px solid } -.ui-multiselect-checkboxes li.ui-multiselect-optgroup-label a { display:block; padding:3px; margin:1px 0; text-decoration:none } +.ui-multiselect-menu { display:none; padding:3px; position:absolute; z-index:10000; text-align: left; } +.ui-multiselect-checkboxes { position:relative /* fixes bug in IE6/7 */; overflow-y:scroll; } +.ui-multiselect-checkboxes label { cursor:default; display:block; border:1px solid transparent; padding:3px 1px; } +.ui-multiselect-checkboxes label input { position:relative; top:1px; } +.ui-multiselect-checkboxes li { clear:both; font-size:14px; padding-right:3px; } +.ui-multiselect-checkboxes li.ui-multiselect-optgroup-label { text-align:center; font-weight:bold; border-bottom:1px solid; } +.ui-multiselect-checkboxes li.ui-multiselect-optgroup-label a { display:block; padding:3px; margin:1px 0; text-decoration:none; } /* remove label borders in IE6 because IE6 does not support transparency */ -* html .ui-multiselect-checkboxes label { border:none } +* html .ui-multiselect-checkboxes label { border:none; } From 350214c6093bbd300102a364f20caa91d23d5fb9 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Sun, 12 Jan 2014 18:57:53 +0100 Subject: [PATCH 059/181] Added Javascript unit tests - added karma utility to run jasmine unit tests - added Sinon library (for stubs/mocks/fakeserver) - added a few unit tests for core and files - added autotest-js.sh script --- apps/files/tests/js/filelistSpec.js | 54 + apps/files/tests/js/filesSpec.js | 81 + autotest-js.sh | 37 + build/package.json | 19 + core/js/core.json | 28 + core/js/router.js | 7 +- core/js/tests/lib/sinon-1.7.3.js | 4290 +++++++++++++++++++++++++++ core/js/tests/specHelper.js | 89 + core/js/tests/specs/coreSpec.js | 70 + lib/base.php | 1 + tests/karma.config.js | 138 + 11 files changed, 4812 insertions(+), 2 deletions(-) create mode 100644 apps/files/tests/js/filelistSpec.js create mode 100644 apps/files/tests/js/filesSpec.js create mode 100755 autotest-js.sh create mode 100644 build/package.json create mode 100644 core/js/core.json create mode 100644 core/js/tests/lib/sinon-1.7.3.js create mode 100644 core/js/tests/specHelper.js create mode 100644 core/js/tests/specs/coreSpec.js create mode 100644 tests/karma.config.js diff --git a/apps/files/tests/js/filelistSpec.js b/apps/files/tests/js/filelistSpec.js new file mode 100644 index 0000000000..6b28a02989 --- /dev/null +++ b/apps/files/tests/js/filelistSpec.js @@ -0,0 +1,54 @@ +/** +* ownCloud +* +* @author Vincent Petry +* @copyright 2014 Vincent Petry +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the License, or any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. If not, see . +* +*/ +describe('FileList tests', function() { + beforeEach(function() { + // init horrible parameters + $('').append('body'); + $('').append('body'); + }); + afterEach(function() { + $('#dir, #permissions').remove(); + }); + it('generates file element with correct attributes when calling addFile', function() { + var lastMod = new Date(10000); + var $tr = FileList.addFile('testName.txt', 1234, lastMod, false, false, {download_url: 'test/download/url'}); + + expect($tr).toBeDefined(); + expect($tr[0].tagName.toLowerCase()).toEqual('tr'); + expect($tr.attr('data-type')).toEqual('file'); + expect($tr.attr('data-file')).toEqual('testName.txt'); + expect($tr.attr('data-size')).toEqual('1234'); + //expect($tr.attr('data-permissions')).toEqual('31'); + //expect($tr.attr('data-mime')).toEqual('plain/text'); + }); + it('generates dir element with correct attributes when calling addDir', function() { + var lastMod = new Date(10000); + var $tr = FileList.addDir('testFolder', 1234, lastMod, false); + + expect($tr).toBeDefined(); + expect($tr[0].tagName.toLowerCase()).toEqual('tr'); + expect($tr.attr('data-type')).toEqual('dir'); + expect($tr.attr('data-file')).toEqual('testFolder'); + expect($tr.attr('data-size')).toEqual('1234'); + //expect($tr.attr('data-permissions')).toEqual('31'); + //expect($tr.attr('data-mime')).toEqual('httpd/unix-directory'); + }); +}); diff --git a/apps/files/tests/js/filesSpec.js b/apps/files/tests/js/filesSpec.js new file mode 100644 index 0000000000..9d0a2e4f9d --- /dev/null +++ b/apps/files/tests/js/filesSpec.js @@ -0,0 +1,81 @@ +/** +* ownCloud +* +* @author Vincent Petry +* @copyright 2014 Vincent Petry +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the License, or any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. If not, see . +* +*/ +describe('Files tests', function() { + describe('File name validation', function() { + it('Validates correct file names', function() { + var fileNames = [ + 'boringname', + 'something.with.extension', + 'now with spaces', + '.a', + '..a', + '.dotfile', + 'single\'quote', + ' spaces before', + 'spaces after ', + 'allowed chars including the crazy ones $%&_-^@!,()[]{}=;#', + '汉字也能用', + 'und Ümläüte sind auch willkommen' + ]; + for ( var i = 0; i < fileNames.length; i++ ) { + try { + expect(Files.isFileNameValid(fileNames[i])).toEqual(true); + } + catch (e) { + fail(); + } + } + }); + it('Detects invalid file names', function() { + var fileNames = [ + '', + ' ', + '.', + '..', + 'back\\slash', + 'sl/ash', + 'ltgt', + 'col:on', + 'double"quote', + 'pi|pe', + 'dont?ask?questions?', + 'super*star', + 'new\nline', + ' ..', + '.. ', + '. ', + ' .' + ]; + for ( var i = 0; i < fileNames.length; i++ ) { + var threwException = false; + try { + Files.isFileNameValid(fileNames[i]); + fail(); + } + catch (e) { + threwException = true; + } + expect(threwException).toEqual(true); + } + }); + }); +}); diff --git a/autotest-js.sh b/autotest-js.sh new file mode 100755 index 0000000000..78f4948e7a --- /dev/null +++ b/autotest-js.sh @@ -0,0 +1,37 @@ +#!/bin/bash +# +# ownCloud +# +# Run JS tests +# +# @author Vincent Petry +# @copyright 2014 Vincent Petry +# +NPM="$(which npm 2>/dev/null)" +PREFIX="build" + +if test -z "$NPM" +then + echo 'Node JS >= 0.8 is required to run the JavaScript tests' >&2 + exit 1 +fi + +# update/install test packages +mkdir -p "$PREFIX" && $NPM install --link --prefix "$PREFIX" || exit 3 + +KARMA="$(which karma 2>/dev/null)" + +# If not installed globally, try local version +if test -z "$KARMA" +then + KARMA="$PREFIX/node_modules/karma/bin/karma" +fi + +if test -z "$KARMA" +then + echo 'Karma module executable not found' >&2 + exit 2 +fi + +KARMA_TESTSUITE="$1" $KARMA start tests/karma.config.js --single-run + diff --git a/build/package.json b/build/package.json new file mode 100644 index 0000000000..238ea6881a --- /dev/null +++ b/build/package.json @@ -0,0 +1,19 @@ +{ + "name": "owncloud-js-tests", + "description": "ownCloud tests", + "version": "0.0.1", + "author": { + "name": "Vincent Petry", + "email": "pvince81@owncloud.com" + }, + "private": true, + "homepage": "https://github.com/owncloud/", + "contributors": [], + "dependencies": {}, + "devDependencies": { + "karma": "*", + "karma-jasmine": "*", + "karma-junit-reporter": "*" + }, + "engine": "node >= 0.8" +} diff --git a/core/js/core.json b/core/js/core.json new file mode 100644 index 0000000000..79cfc42f58 --- /dev/null +++ b/core/js/core.json @@ -0,0 +1,28 @@ +{ + "modules": [ + "jquery-1.10.0.min.js", + "jquery-migrate-1.2.1.min.js", + "jquery-ui-1.10.0.custom.js", + "jquery-showpassword.js", + "jquery.infieldlabel.js", + "jquery.placeholder.js", + "jquery-tipsy.js", + "compatibility.js", + "jquery.ocdialog.js", + "oc-dialogs.js", + "js.js", + "octemplate.js", + "eventsource.js", + "config.js", + "multiselect.js", + "search.js", + "router.js", + "oc-requesttoken.js", + "styles.js", + "apps.js", + "fixes.js", + "jquery-ui-2.10.0.custom.js", + "jquery-tipsy.js", + "jquery.ocdialog.js" + ] +} diff --git a/core/js/router.js b/core/js/router.js index 44e7c30602..e6ef54a186 100644 --- a/core/js/router.js +++ b/core/js/router.js @@ -3,9 +3,12 @@ OC.Router = { // register your ajax requests to load after the loading of the routes // has finished. otherwise you face problems with race conditions registerLoadedCallback: function(callback){ + if (!this.routes_request){ + return; + } this.routes_request.done(callback); }, - routes_request: $.ajax(OC.router_base_url + '/core/routes.json', { + routes_request: !window.TESTING && $.ajax(OC.router_base_url + '/core/routes.json', { dataType: 'json', success: function(jsondata) { if (jsondata.status === 'success') { @@ -75,4 +78,4 @@ OC.Router = { return OC.router_base_url + url; } -}; +} diff --git a/core/js/tests/lib/sinon-1.7.3.js b/core/js/tests/lib/sinon-1.7.3.js new file mode 100644 index 0000000000..26c4bd9c46 --- /dev/null +++ b/core/js/tests/lib/sinon-1.7.3.js @@ -0,0 +1,4290 @@ +/** + * Sinon.JS 1.7.3, 2013/06/20 + * + * @author Christian Johansen (christian@cjohansen.no) + * @author Contributors: https://github.com/cjohansen/Sinon.JS/blob/master/AUTHORS + * + * (The BSD License) + * + * Copyright (c) 2010-2013, Christian Johansen, christian@cjohansen.no + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Christian Johansen nor the names of his contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +this.sinon = (function () { +var buster = (function (setTimeout, B) { + var isNode = typeof require == "function" && typeof module == "object"; + var div = typeof document != "undefined" && document.createElement("div"); + var F = function () {}; + + var buster = { + bind: function bind(obj, methOrProp) { + var method = typeof methOrProp == "string" ? obj[methOrProp] : methOrProp; + var args = Array.prototype.slice.call(arguments, 2); + return function () { + var allArgs = args.concat(Array.prototype.slice.call(arguments)); + return method.apply(obj, allArgs); + }; + }, + + partial: function partial(fn) { + var args = [].slice.call(arguments, 1); + return function () { + return fn.apply(this, args.concat([].slice.call(arguments))); + }; + }, + + create: function create(object) { + F.prototype = object; + return new F(); + }, + + extend: function extend(target) { + if (!target) { return; } + for (var i = 1, l = arguments.length, prop; i < l; ++i) { + for (prop in arguments[i]) { + target[prop] = arguments[i][prop]; + } + } + return target; + }, + + nextTick: function nextTick(callback) { + if (typeof process != "undefined" && process.nextTick) { + return process.nextTick(callback); + } + setTimeout(callback, 0); + }, + + functionName: function functionName(func) { + if (!func) return ""; + if (func.displayName) return func.displayName; + if (func.name) return func.name; + var matches = func.toString().match(/function\s+([^\(]+)/m); + return matches && matches[1] || ""; + }, + + isNode: function isNode(obj) { + if (!div) return false; + try { + obj.appendChild(div); + obj.removeChild(div); + } catch (e) { + return false; + } + return true; + }, + + isElement: function isElement(obj) { + return obj && obj.nodeType === 1 && buster.isNode(obj); + }, + + isArray: function isArray(arr) { + return Object.prototype.toString.call(arr) == "[object Array]"; + }, + + flatten: function flatten(arr) { + var result = [], arr = arr || []; + for (var i = 0, l = arr.length; i < l; ++i) { + result = result.concat(buster.isArray(arr[i]) ? flatten(arr[i]) : arr[i]); + } + return result; + }, + + each: function each(arr, callback) { + for (var i = 0, l = arr.length; i < l; ++i) { + callback(arr[i]); + } + }, + + map: function map(arr, callback) { + var results = []; + for (var i = 0, l = arr.length; i < l; ++i) { + results.push(callback(arr[i])); + } + return results; + }, + + parallel: function parallel(fns, callback) { + function cb(err, res) { + if (typeof callback == "function") { + callback(err, res); + callback = null; + } + } + if (fns.length == 0) { return cb(null, []); } + var remaining = fns.length, results = []; + function makeDone(num) { + return function done(err, result) { + if (err) { return cb(err); } + results[num] = result; + if (--remaining == 0) { cb(null, results); } + }; + } + for (var i = 0, l = fns.length; i < l; ++i) { + fns[i](makeDone(i)); + } + }, + + series: function series(fns, callback) { + function cb(err, res) { + if (typeof callback == "function") { + callback(err, res); + } + } + var remaining = fns.slice(); + var results = []; + function callNext() { + if (remaining.length == 0) return cb(null, results); + var promise = remaining.shift()(next); + if (promise && typeof promise.then == "function") { + promise.then(buster.partial(next, null), next); + } + } + function next(err, result) { + if (err) return cb(err); + results.push(result); + callNext(); + } + callNext(); + }, + + countdown: function countdown(num, done) { + return function () { + if (--num == 0) done(); + }; + } + }; + + if (typeof process === "object" && + typeof require === "function" && typeof module === "object") { + var crypto = require("crypto"); + var path = require("path"); + + buster.tmpFile = function (fileName) { + var hashed = crypto.createHash("sha1"); + hashed.update(fileName); + var tmpfileName = hashed.digest("hex"); + + if (process.platform == "win32") { + return path.join(process.env["TEMP"], tmpfileName); + } else { + return path.join("/tmp", tmpfileName); + } + }; + } + + if (Array.prototype.some) { + buster.some = function (arr, fn, thisp) { + return arr.some(fn, thisp); + }; + } else { + // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/some + buster.some = function (arr, fun, thisp) { + if (arr == null) { throw new TypeError(); } + arr = Object(arr); + var len = arr.length >>> 0; + if (typeof fun !== "function") { throw new TypeError(); } + + for (var i = 0; i < len; i++) { + if (arr.hasOwnProperty(i) && fun.call(thisp, arr[i], i, arr)) { + return true; + } + } + + return false; + }; + } + + if (Array.prototype.filter) { + buster.filter = function (arr, fn, thisp) { + return arr.filter(fn, thisp); + }; + } else { + // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/filter + buster.filter = function (fn, thisp) { + if (this == null) { throw new TypeError(); } + + var t = Object(this); + var len = t.length >>> 0; + if (typeof fn != "function") { throw new TypeError(); } + + var res = []; + for (var i = 0; i < len; i++) { + if (i in t) { + var val = t[i]; // in case fun mutates this + if (fn.call(thisp, val, i, t)) { res.push(val); } + } + } + + return res; + }; + } + + if (isNode) { + module.exports = buster; + buster.eventEmitter = require("./buster-event-emitter"); + Object.defineProperty(buster, "defineVersionGetter", { + get: function () { + return require("./define-version-getter"); + } + }); + } + + return buster.extend(B || {}, buster); +}(setTimeout, buster)); +if (typeof buster === "undefined") { + var buster = {}; +} + +if (typeof module === "object" && typeof require === "function") { + buster = require("buster-core"); +} + +buster.format = buster.format || {}; +buster.format.excludeConstructors = ["Object", /^.$/]; +buster.format.quoteStrings = true; + +buster.format.ascii = (function () { + + var hasOwn = Object.prototype.hasOwnProperty; + + var specialObjects = []; + if (typeof global != "undefined") { + specialObjects.push({ obj: global, value: "[object global]" }); + } + if (typeof document != "undefined") { + specialObjects.push({ obj: document, value: "[object HTMLDocument]" }); + } + if (typeof window != "undefined") { + specialObjects.push({ obj: window, value: "[object Window]" }); + } + + function keys(object) { + var k = Object.keys && Object.keys(object) || []; + + if (k.length == 0) { + for (var prop in object) { + if (hasOwn.call(object, prop)) { + k.push(prop); + } + } + } + + return k.sort(); + } + + function isCircular(object, objects) { + if (typeof object != "object") { + return false; + } + + for (var i = 0, l = objects.length; i < l; ++i) { + if (objects[i] === object) { + return true; + } + } + + return false; + } + + function ascii(object, processed, indent) { + if (typeof object == "string") { + var quote = typeof this.quoteStrings != "boolean" || this.quoteStrings; + return processed || quote ? '"' + object + '"' : object; + } + + if (typeof object == "function" && !(object instanceof RegExp)) { + return ascii.func(object); + } + + processed = processed || []; + + if (isCircular(object, processed)) { + return "[Circular]"; + } + + if (Object.prototype.toString.call(object) == "[object Array]") { + return ascii.array.call(this, object, processed); + } + + if (!object) { + return "" + object; + } + + if (buster.isElement(object)) { + return ascii.element(object); + } + + if (typeof object.toString == "function" && + object.toString !== Object.prototype.toString) { + return object.toString(); + } + + for (var i = 0, l = specialObjects.length; i < l; i++) { + if (object === specialObjects[i].obj) { + return specialObjects[i].value; + } + } + + return ascii.object.call(this, object, processed, indent); + } + + ascii.func = function (func) { + return "function " + buster.functionName(func) + "() {}"; + }; + + ascii.array = function (array, processed) { + processed = processed || []; + processed.push(array); + var pieces = []; + + for (var i = 0, l = array.length; i < l; ++i) { + pieces.push(ascii.call(this, array[i], processed)); + } + + return "[" + pieces.join(", ") + "]"; + }; + + ascii.object = function (object, processed, indent) { + processed = processed || []; + processed.push(object); + indent = indent || 0; + var pieces = [], properties = keys(object), prop, str, obj; + var is = ""; + var length = 3; + + for (var i = 0, l = indent; i < l; ++i) { + is += " "; + } + + for (i = 0, l = properties.length; i < l; ++i) { + prop = properties[i]; + obj = object[prop]; + + if (isCircular(obj, processed)) { + str = "[Circular]"; + } else { + str = ascii.call(this, obj, processed, indent + 2); + } + + str = (/\s/.test(prop) ? '"' + prop + '"' : prop) + ": " + str; + length += str.length; + pieces.push(str); + } + + var cons = ascii.constructorName.call(this, object); + var prefix = cons ? "[" + cons + "] " : "" + + return (length + indent) > 80 ? + prefix + "{\n " + is + pieces.join(",\n " + is) + "\n" + is + "}" : + prefix + "{ " + pieces.join(", ") + " }"; + }; + + ascii.element = function (element) { + var tagName = element.tagName.toLowerCase(); + var attrs = element.attributes, attribute, pairs = [], attrName; + + for (var i = 0, l = attrs.length; i < l; ++i) { + attribute = attrs.item(i); + attrName = attribute.nodeName.toLowerCase().replace("html:", ""); + + if (attrName == "contenteditable" && attribute.nodeValue == "inherit") { + continue; + } + + if (!!attribute.nodeValue) { + pairs.push(attrName + "=\"" + attribute.nodeValue + "\""); + } + } + + var formatted = "<" + tagName + (pairs.length > 0 ? " " : ""); + var content = element.innerHTML; + + if (content.length > 20) { + content = content.substr(0, 20) + "[...]"; + } + + var res = formatted + pairs.join(" ") + ">" + content + ""; + + return res.replace(/ contentEditable="inherit"/, ""); + }; + + ascii.constructorName = function (object) { + var name = buster.functionName(object && object.constructor); + var excludes = this.excludeConstructors || buster.format.excludeConstructors || []; + + for (var i = 0, l = excludes.length; i < l; ++i) { + if (typeof excludes[i] == "string" && excludes[i] == name) { + return ""; + } else if (excludes[i].test && excludes[i].test(name)) { + return ""; + } + } + + return name; + }; + + return ascii; +}()); + +if (typeof module != "undefined") { + module.exports = buster.format; +} +/*jslint eqeqeq: false, onevar: false, forin: true, nomen: false, regexp: false, plusplus: false*/ +/*global module, require, __dirname, document*/ +/** + * Sinon core utilities. For internal use only. + * + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + */ + +var sinon = (function (buster) { + var div = typeof document != "undefined" && document.createElement("div"); + var hasOwn = Object.prototype.hasOwnProperty; + + function isDOMNode(obj) { + var success = false; + + try { + obj.appendChild(div); + success = div.parentNode == obj; + } catch (e) { + return false; + } finally { + try { + obj.removeChild(div); + } catch (e) { + // Remove failed, not much we can do about that + } + } + + return success; + } + + function isElement(obj) { + return div && obj && obj.nodeType === 1 && isDOMNode(obj); + } + + function isFunction(obj) { + return typeof obj === "function" || !!(obj && obj.constructor && obj.call && obj.apply); + } + + function mirrorProperties(target, source) { + for (var prop in source) { + if (!hasOwn.call(target, prop)) { + target[prop] = source[prop]; + } + } + } + + function isRestorable (obj) { + return typeof obj === "function" && typeof obj.restore === "function" && obj.restore.sinon; + } + + var sinon = { + wrapMethod: function wrapMethod(object, property, method) { + if (!object) { + throw new TypeError("Should wrap property of object"); + } + + if (typeof method != "function") { + throw new TypeError("Method wrapper should be function"); + } + + var wrappedMethod = object[property]; + + if (!isFunction(wrappedMethod)) { + throw new TypeError("Attempted to wrap " + (typeof wrappedMethod) + " property " + + property + " as function"); + } + + if (wrappedMethod.restore && wrappedMethod.restore.sinon) { + throw new TypeError("Attempted to wrap " + property + " which is already wrapped"); + } + + if (wrappedMethod.calledBefore) { + var verb = !!wrappedMethod.returns ? "stubbed" : "spied on"; + throw new TypeError("Attempted to wrap " + property + " which is already " + verb); + } + + // IE 8 does not support hasOwnProperty on the window object. + var owned = hasOwn.call(object, property); + object[property] = method; + method.displayName = property; + + method.restore = function () { + // For prototype properties try to reset by delete first. + // If this fails (ex: localStorage on mobile safari) then force a reset + // via direct assignment. + if (!owned) { + delete object[property]; + } + if (object[property] === method) { + object[property] = wrappedMethod; + } + }; + + method.restore.sinon = true; + mirrorProperties(method, wrappedMethod); + + return method; + }, + + extend: function extend(target) { + for (var i = 1, l = arguments.length; i < l; i += 1) { + for (var prop in arguments[i]) { + if (arguments[i].hasOwnProperty(prop)) { + target[prop] = arguments[i][prop]; + } + + // DONT ENUM bug, only care about toString + if (arguments[i].hasOwnProperty("toString") && + arguments[i].toString != target.toString) { + target.toString = arguments[i].toString; + } + } + } + + return target; + }, + + create: function create(proto) { + var F = function () {}; + F.prototype = proto; + return new F(); + }, + + deepEqual: function deepEqual(a, b) { + if (sinon.match && sinon.match.isMatcher(a)) { + return a.test(b); + } + if (typeof a != "object" || typeof b != "object") { + return a === b; + } + + if (isElement(a) || isElement(b)) { + return a === b; + } + + if (a === b) { + return true; + } + + if ((a === null && b !== null) || (a !== null && b === null)) { + return false; + } + + var aString = Object.prototype.toString.call(a); + if (aString != Object.prototype.toString.call(b)) { + return false; + } + + if (aString == "[object Array]") { + if (a.length !== b.length) { + return false; + } + + for (var i = 0, l = a.length; i < l; i += 1) { + if (!deepEqual(a[i], b[i])) { + return false; + } + } + + return true; + } + + if (aString == "[object Date]") { + return a.valueOf() === b.valueOf(); + } + + var prop, aLength = 0, bLength = 0; + + for (prop in a) { + aLength += 1; + + if (!deepEqual(a[prop], b[prop])) { + return false; + } + } + + for (prop in b) { + bLength += 1; + } + + return aLength == bLength; + }, + + functionName: function functionName(func) { + var name = func.displayName || func.name; + + // Use function decomposition as a last resort to get function + // name. Does not rely on function decomposition to work - if it + // doesn't debugging will be slightly less informative + // (i.e. toString will say 'spy' rather than 'myFunc'). + if (!name) { + var matches = func.toString().match(/function ([^\s\(]+)/); + name = matches && matches[1]; + } + + return name; + }, + + functionToString: function toString() { + if (this.getCall && this.callCount) { + var thisValue, prop, i = this.callCount; + + while (i--) { + thisValue = this.getCall(i).thisValue; + + for (prop in thisValue) { + if (thisValue[prop] === this) { + return prop; + } + } + } + } + + return this.displayName || "sinon fake"; + }, + + getConfig: function (custom) { + var config = {}; + custom = custom || {}; + var defaults = sinon.defaultConfig; + + for (var prop in defaults) { + if (defaults.hasOwnProperty(prop)) { + config[prop] = custom.hasOwnProperty(prop) ? custom[prop] : defaults[prop]; + } + } + + return config; + }, + + format: function (val) { + return "" + val; + }, + + defaultConfig: { + injectIntoThis: true, + injectInto: null, + properties: ["spy", "stub", "mock", "clock", "server", "requests"], + useFakeTimers: true, + useFakeServer: true + }, + + timesInWords: function timesInWords(count) { + return count == 1 && "once" || + count == 2 && "twice" || + count == 3 && "thrice" || + (count || 0) + " times"; + }, + + calledInOrder: function (spies) { + for (var i = 1, l = spies.length; i < l; i++) { + if (!spies[i - 1].calledBefore(spies[i]) || !spies[i].called) { + return false; + } + } + + return true; + }, + + orderByFirstCall: function (spies) { + return spies.sort(function (a, b) { + // uuid, won't ever be equal + var aCall = a.getCall(0); + var bCall = b.getCall(0); + var aId = aCall && aCall.callId || -1; + var bId = bCall && bCall.callId || -1; + + return aId < bId ? -1 : 1; + }); + }, + + log: function () {}, + + logError: function (label, err) { + var msg = label + " threw exception: " + sinon.log(msg + "[" + err.name + "] " + err.message); + if (err.stack) { sinon.log(err.stack); } + + setTimeout(function () { + err.message = msg + err.message; + throw err; + }, 0); + }, + + typeOf: function (value) { + if (value === null) { + return "null"; + } + else if (value === undefined) { + return "undefined"; + } + var string = Object.prototype.toString.call(value); + return string.substring(8, string.length - 1).toLowerCase(); + }, + + createStubInstance: function (constructor) { + if (typeof constructor !== "function") { + throw new TypeError("The constructor should be a function."); + } + return sinon.stub(sinon.create(constructor.prototype)); + }, + + restore: function (object) { + if (object !== null && typeof object === "object") { + for (var prop in object) { + if (isRestorable(object[prop])) { + object[prop].restore(); + } + } + } + else if (isRestorable(object)) { + object.restore(); + } + } + }; + + var isNode = typeof module == "object" && typeof require == "function"; + + if (isNode) { + try { + buster = { format: require("buster-format") }; + } catch (e) {} + module.exports = sinon; + module.exports.spy = require("./sinon/spy"); + module.exports.stub = require("./sinon/stub"); + module.exports.mock = require("./sinon/mock"); + module.exports.collection = require("./sinon/collection"); + module.exports.assert = require("./sinon/assert"); + module.exports.sandbox = require("./sinon/sandbox"); + module.exports.test = require("./sinon/test"); + module.exports.testCase = require("./sinon/test_case"); + module.exports.assert = require("./sinon/assert"); + module.exports.match = require("./sinon/match"); + } + + if (buster) { + var formatter = sinon.create(buster.format); + formatter.quoteStrings = false; + sinon.format = function () { + return formatter.ascii.apply(formatter, arguments); + }; + } else if (isNode) { + try { + var util = require("util"); + sinon.format = function (value) { + return typeof value == "object" && value.toString === Object.prototype.toString ? util.inspect(value) : value; + }; + } catch (e) { + /* Node, but no util module - would be very old, but better safe than + sorry */ + } + } + + return sinon; +}(typeof buster == "object" && buster)); + +/* @depend ../sinon.js */ +/*jslint eqeqeq: false, onevar: false, plusplus: false*/ +/*global module, require, sinon*/ +/** + * Match functions + * + * @author Maximilian Antoni (mail@maxantoni.de) + * @license BSD + * + * Copyright (c) 2012 Maximilian Antoni + */ + +(function (sinon) { + var commonJSModule = typeof module == "object" && typeof require == "function"; + + if (!sinon && commonJSModule) { + sinon = require("../sinon"); + } + + if (!sinon) { + return; + } + + function assertType(value, type, name) { + var actual = sinon.typeOf(value); + if (actual !== type) { + throw new TypeError("Expected type of " + name + " to be " + + type + ", but was " + actual); + } + } + + var matcher = { + toString: function () { + return this.message; + } + }; + + function isMatcher(object) { + return matcher.isPrototypeOf(object); + } + + function matchObject(expectation, actual) { + if (actual === null || actual === undefined) { + return false; + } + for (var key in expectation) { + if (expectation.hasOwnProperty(key)) { + var exp = expectation[key]; + var act = actual[key]; + if (match.isMatcher(exp)) { + if (!exp.test(act)) { + return false; + } + } else if (sinon.typeOf(exp) === "object") { + if (!matchObject(exp, act)) { + return false; + } + } else if (!sinon.deepEqual(exp, act)) { + return false; + } + } + } + return true; + } + + matcher.or = function (m2) { + if (!isMatcher(m2)) { + throw new TypeError("Matcher expected"); + } + var m1 = this; + var or = sinon.create(matcher); + or.test = function (actual) { + return m1.test(actual) || m2.test(actual); + }; + or.message = m1.message + ".or(" + m2.message + ")"; + return or; + }; + + matcher.and = function (m2) { + if (!isMatcher(m2)) { + throw new TypeError("Matcher expected"); + } + var m1 = this; + var and = sinon.create(matcher); + and.test = function (actual) { + return m1.test(actual) && m2.test(actual); + }; + and.message = m1.message + ".and(" + m2.message + ")"; + return and; + }; + + var match = function (expectation, message) { + var m = sinon.create(matcher); + var type = sinon.typeOf(expectation); + switch (type) { + case "object": + if (typeof expectation.test === "function") { + m.test = function (actual) { + return expectation.test(actual) === true; + }; + m.message = "match(" + sinon.functionName(expectation.test) + ")"; + return m; + } + var str = []; + for (var key in expectation) { + if (expectation.hasOwnProperty(key)) { + str.push(key + ": " + expectation[key]); + } + } + m.test = function (actual) { + return matchObject(expectation, actual); + }; + m.message = "match(" + str.join(", ") + ")"; + break; + case "number": + m.test = function (actual) { + return expectation == actual; + }; + break; + case "string": + m.test = function (actual) { + if (typeof actual !== "string") { + return false; + } + return actual.indexOf(expectation) !== -1; + }; + m.message = "match(\"" + expectation + "\")"; + break; + case "regexp": + m.test = function (actual) { + if (typeof actual !== "string") { + return false; + } + return expectation.test(actual); + }; + break; + case "function": + m.test = expectation; + if (message) { + m.message = message; + } else { + m.message = "match(" + sinon.functionName(expectation) + ")"; + } + break; + default: + m.test = function (actual) { + return sinon.deepEqual(expectation, actual); + }; + } + if (!m.message) { + m.message = "match(" + expectation + ")"; + } + return m; + }; + + match.isMatcher = isMatcher; + + match.any = match(function () { + return true; + }, "any"); + + match.defined = match(function (actual) { + return actual !== null && actual !== undefined; + }, "defined"); + + match.truthy = match(function (actual) { + return !!actual; + }, "truthy"); + + match.falsy = match(function (actual) { + return !actual; + }, "falsy"); + + match.same = function (expectation) { + return match(function (actual) { + return expectation === actual; + }, "same(" + expectation + ")"); + }; + + match.typeOf = function (type) { + assertType(type, "string", "type"); + return match(function (actual) { + return sinon.typeOf(actual) === type; + }, "typeOf(\"" + type + "\")"); + }; + + match.instanceOf = function (type) { + assertType(type, "function", "type"); + return match(function (actual) { + return actual instanceof type; + }, "instanceOf(" + sinon.functionName(type) + ")"); + }; + + function createPropertyMatcher(propertyTest, messagePrefix) { + return function (property, value) { + assertType(property, "string", "property"); + var onlyProperty = arguments.length === 1; + var message = messagePrefix + "(\"" + property + "\""; + if (!onlyProperty) { + message += ", " + value; + } + message += ")"; + return match(function (actual) { + if (actual === undefined || actual === null || + !propertyTest(actual, property)) { + return false; + } + return onlyProperty || sinon.deepEqual(value, actual[property]); + }, message); + }; + } + + match.has = createPropertyMatcher(function (actual, property) { + if (typeof actual === "object") { + return property in actual; + } + return actual[property] !== undefined; + }, "has"); + + match.hasOwn = createPropertyMatcher(function (actual, property) { + return actual.hasOwnProperty(property); + }, "hasOwn"); + + match.bool = match.typeOf("boolean"); + match.number = match.typeOf("number"); + match.string = match.typeOf("string"); + match.object = match.typeOf("object"); + match.func = match.typeOf("function"); + match.array = match.typeOf("array"); + match.regexp = match.typeOf("regexp"); + match.date = match.typeOf("date"); + + if (commonJSModule) { + module.exports = match; + } else { + sinon.match = match; + } +}(typeof sinon == "object" && sinon || null)); + +/** + * @depend ../sinon.js + * @depend match.js + */ +/*jslint eqeqeq: false, onevar: false, plusplus: false*/ +/*global module, require, sinon*/ +/** + * Spy calls + * + * @author Christian Johansen (christian@cjohansen.no) + * @author Maximilian Antoni (mail@maxantoni.de) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + * Copyright (c) 2013 Maximilian Antoni + */ + +var commonJSModule = typeof module == "object" && typeof require == "function"; + +if (!this.sinon && commonJSModule) { + var sinon = require("../sinon"); +} + +(function (sinon) { + function throwYieldError(proxy, text, args) { + var msg = sinon.functionName(proxy) + text; + if (args.length) { + msg += " Received [" + slice.call(args).join(", ") + "]"; + } + throw new Error(msg); + } + + var slice = Array.prototype.slice; + + var callProto = { + calledOn: function calledOn(thisValue) { + if (sinon.match && sinon.match.isMatcher(thisValue)) { + return thisValue.test(this.thisValue); + } + return this.thisValue === thisValue; + }, + + calledWith: function calledWith() { + for (var i = 0, l = arguments.length; i < l; i += 1) { + if (!sinon.deepEqual(arguments[i], this.args[i])) { + return false; + } + } + + return true; + }, + + calledWithMatch: function calledWithMatch() { + for (var i = 0, l = arguments.length; i < l; i += 1) { + var actual = this.args[i]; + var expectation = arguments[i]; + if (!sinon.match || !sinon.match(expectation).test(actual)) { + return false; + } + } + return true; + }, + + calledWithExactly: function calledWithExactly() { + return arguments.length == this.args.length && + this.calledWith.apply(this, arguments); + }, + + notCalledWith: function notCalledWith() { + return !this.calledWith.apply(this, arguments); + }, + + notCalledWithMatch: function notCalledWithMatch() { + return !this.calledWithMatch.apply(this, arguments); + }, + + returned: function returned(value) { + return sinon.deepEqual(value, this.returnValue); + }, + + threw: function threw(error) { + if (typeof error === "undefined" || !this.exception) { + return !!this.exception; + } + + return this.exception === error || this.exception.name === error; + }, + + calledWithNew: function calledWithNew(thisValue) { + return this.thisValue instanceof this.proxy; + }, + + calledBefore: function (other) { + return this.callId < other.callId; + }, + + calledAfter: function (other) { + return this.callId > other.callId; + }, + + callArg: function (pos) { + this.args[pos](); + }, + + callArgOn: function (pos, thisValue) { + this.args[pos].apply(thisValue); + }, + + callArgWith: function (pos) { + this.callArgOnWith.apply(this, [pos, null].concat(slice.call(arguments, 1))); + }, + + callArgOnWith: function (pos, thisValue) { + var args = slice.call(arguments, 2); + this.args[pos].apply(thisValue, args); + }, + + "yield": function () { + this.yieldOn.apply(this, [null].concat(slice.call(arguments, 0))); + }, + + yieldOn: function (thisValue) { + var args = this.args; + for (var i = 0, l = args.length; i < l; ++i) { + if (typeof args[i] === "function") { + args[i].apply(thisValue, slice.call(arguments, 1)); + return; + } + } + throwYieldError(this.proxy, " cannot yield since no callback was passed.", args); + }, + + yieldTo: function (prop) { + this.yieldToOn.apply(this, [prop, null].concat(slice.call(arguments, 1))); + }, + + yieldToOn: function (prop, thisValue) { + var args = this.args; + for (var i = 0, l = args.length; i < l; ++i) { + if (args[i] && typeof args[i][prop] === "function") { + args[i][prop].apply(thisValue, slice.call(arguments, 2)); + return; + } + } + throwYieldError(this.proxy, " cannot yield to '" + prop + + "' since no callback was passed.", args); + }, + + toString: function () { + var callStr = this.proxy.toString() + "("; + var args = []; + + for (var i = 0, l = this.args.length; i < l; ++i) { + args.push(sinon.format(this.args[i])); + } + + callStr = callStr + args.join(", ") + ")"; + + if (typeof this.returnValue != "undefined") { + callStr += " => " + sinon.format(this.returnValue); + } + + if (this.exception) { + callStr += " !" + this.exception.name; + + if (this.exception.message) { + callStr += "(" + this.exception.message + ")"; + } + } + + return callStr; + } + }; + + callProto.invokeCallback = callProto.yield; + + function createSpyCall(spy, thisValue, args, returnValue, exception, id) { + if (typeof id !== "number") { + throw new TypeError("Call id is not a number"); + } + var proxyCall = sinon.create(callProto); + proxyCall.proxy = spy; + proxyCall.thisValue = thisValue; + proxyCall.args = args; + proxyCall.returnValue = returnValue; + proxyCall.exception = exception; + proxyCall.callId = id; + + return proxyCall; + }; + createSpyCall.toString = callProto.toString; // used by mocks + + sinon.spyCall = createSpyCall; +}(typeof sinon == "object" && sinon || null)); + +/** + * @depend ../sinon.js + */ +/*jslint eqeqeq: false, onevar: false, plusplus: false*/ +/*global module, require, sinon*/ +/** + * Spy functions + * + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + */ + +(function (sinon) { + var commonJSModule = typeof module == "object" && typeof require == "function"; + var push = Array.prototype.push; + var slice = Array.prototype.slice; + var callId = 0; + + function spy(object, property) { + if (!property && typeof object == "function") { + return spy.create(object); + } + + if (!object && !property) { + return spy.create(function () { }); + } + + var method = object[property]; + return sinon.wrapMethod(object, property, spy.create(method)); + } + + function matchingFake(fakes, args, strict) { + if (!fakes) { + return; + } + + var alen = args.length; + + for (var i = 0, l = fakes.length; i < l; i++) { + if (fakes[i].matches(args, strict)) { + return fakes[i]; + } + } + } + + function incrementCallCount() { + this.called = true; + this.callCount += 1; + this.notCalled = false; + this.calledOnce = this.callCount == 1; + this.calledTwice = this.callCount == 2; + this.calledThrice = this.callCount == 3; + } + + function createCallProperties() { + this.firstCall = this.getCall(0); + this.secondCall = this.getCall(1); + this.thirdCall = this.getCall(2); + this.lastCall = this.getCall(this.callCount - 1); + } + + var vars = "a,b,c,d,e,f,g,h,i,j,k,l"; + function createProxy(func) { + // Retain the function length: + var p; + if (func.length) { + eval("p = (function proxy(" + vars.substring(0, func.length * 2 - 1) + + ") { return p.invoke(func, this, slice.call(arguments)); });"); + } + else { + p = function proxy() { + return p.invoke(func, this, slice.call(arguments)); + }; + } + return p; + } + + var uuid = 0; + + // Public API + var spyApi = { + reset: function () { + this.called = false; + this.notCalled = true; + this.calledOnce = false; + this.calledTwice = false; + this.calledThrice = false; + this.callCount = 0; + this.firstCall = null; + this.secondCall = null; + this.thirdCall = null; + this.lastCall = null; + this.args = []; + this.returnValues = []; + this.thisValues = []; + this.exceptions = []; + this.callIds = []; + if (this.fakes) { + for (var i = 0; i < this.fakes.length; i++) { + this.fakes[i].reset(); + } + } + }, + + create: function create(func) { + var name; + + if (typeof func != "function") { + func = function () { }; + } else { + name = sinon.functionName(func); + } + + var proxy = createProxy(func); + + sinon.extend(proxy, spy); + delete proxy.create; + sinon.extend(proxy, func); + + proxy.reset(); + proxy.prototype = func.prototype; + proxy.displayName = name || "spy"; + proxy.toString = sinon.functionToString; + proxy._create = sinon.spy.create; + proxy.id = "spy#" + uuid++; + + return proxy; + }, + + invoke: function invoke(func, thisValue, args) { + var matching = matchingFake(this.fakes, args); + var exception, returnValue; + + incrementCallCount.call(this); + push.call(this.thisValues, thisValue); + push.call(this.args, args); + push.call(this.callIds, callId++); + + try { + if (matching) { + returnValue = matching.invoke(func, thisValue, args); + } else { + returnValue = (this.func || func).apply(thisValue, args); + } + } catch (e) { + push.call(this.returnValues, undefined); + exception = e; + throw e; + } finally { + push.call(this.exceptions, exception); + } + + push.call(this.returnValues, returnValue); + + createCallProperties.call(this); + + return returnValue; + }, + + getCall: function getCall(i) { + if (i < 0 || i >= this.callCount) { + return null; + } + + return sinon.spyCall(this, this.thisValues[i], this.args[i], + this.returnValues[i], this.exceptions[i], + this.callIds[i]); + }, + + calledBefore: function calledBefore(spyFn) { + if (!this.called) { + return false; + } + + if (!spyFn.called) { + return true; + } + + return this.callIds[0] < spyFn.callIds[spyFn.callIds.length - 1]; + }, + + calledAfter: function calledAfter(spyFn) { + if (!this.called || !spyFn.called) { + return false; + } + + return this.callIds[this.callCount - 1] > spyFn.callIds[spyFn.callCount - 1]; + }, + + withArgs: function () { + var args = slice.call(arguments); + + if (this.fakes) { + var match = matchingFake(this.fakes, args, true); + + if (match) { + return match; + } + } else { + this.fakes = []; + } + + var original = this; + var fake = this._create(); + fake.matchingAguments = args; + push.call(this.fakes, fake); + + fake.withArgs = function () { + return original.withArgs.apply(original, arguments); + }; + + for (var i = 0; i < this.args.length; i++) { + if (fake.matches(this.args[i])) { + incrementCallCount.call(fake); + push.call(fake.thisValues, this.thisValues[i]); + push.call(fake.args, this.args[i]); + push.call(fake.returnValues, this.returnValues[i]); + push.call(fake.exceptions, this.exceptions[i]); + push.call(fake.callIds, this.callIds[i]); + } + } + createCallProperties.call(fake); + + return fake; + }, + + matches: function (args, strict) { + var margs = this.matchingAguments; + + if (margs.length <= args.length && + sinon.deepEqual(margs, args.slice(0, margs.length))) { + return !strict || margs.length == args.length; + } + }, + + printf: function (format) { + var spy = this; + var args = slice.call(arguments, 1); + var formatter; + + return (format || "").replace(/%(.)/g, function (match, specifyer) { + formatter = spyApi.formatters[specifyer]; + + if (typeof formatter == "function") { + return formatter.call(null, spy, args); + } else if (!isNaN(parseInt(specifyer), 10)) { + return sinon.format(args[specifyer - 1]); + } + + return "%" + specifyer; + }); + } + }; + + function delegateToCalls(method, matchAny, actual, notCalled) { + spyApi[method] = function () { + if (!this.called) { + if (notCalled) { + return notCalled.apply(this, arguments); + } + return false; + } + + var currentCall; + var matches = 0; + + for (var i = 0, l = this.callCount; i < l; i += 1) { + currentCall = this.getCall(i); + + if (currentCall[actual || method].apply(currentCall, arguments)) { + matches += 1; + + if (matchAny) { + return true; + } + } + } + + return matches === this.callCount; + }; + } + + delegateToCalls("calledOn", true); + delegateToCalls("alwaysCalledOn", false, "calledOn"); + delegateToCalls("calledWith", true); + delegateToCalls("calledWithMatch", true); + delegateToCalls("alwaysCalledWith", false, "calledWith"); + delegateToCalls("alwaysCalledWithMatch", false, "calledWithMatch"); + delegateToCalls("calledWithExactly", true); + delegateToCalls("alwaysCalledWithExactly", false, "calledWithExactly"); + delegateToCalls("neverCalledWith", false, "notCalledWith", + function () { return true; }); + delegateToCalls("neverCalledWithMatch", false, "notCalledWithMatch", + function () { return true; }); + delegateToCalls("threw", true); + delegateToCalls("alwaysThrew", false, "threw"); + delegateToCalls("returned", true); + delegateToCalls("alwaysReturned", false, "returned"); + delegateToCalls("calledWithNew", true); + delegateToCalls("alwaysCalledWithNew", false, "calledWithNew"); + delegateToCalls("callArg", false, "callArgWith", function () { + throw new Error(this.toString() + " cannot call arg since it was not yet invoked."); + }); + spyApi.callArgWith = spyApi.callArg; + delegateToCalls("callArgOn", false, "callArgOnWith", function () { + throw new Error(this.toString() + " cannot call arg since it was not yet invoked."); + }); + spyApi.callArgOnWith = spyApi.callArgOn; + delegateToCalls("yield", false, "yield", function () { + throw new Error(this.toString() + " cannot yield since it was not yet invoked."); + }); + // "invokeCallback" is an alias for "yield" since "yield" is invalid in strict mode. + spyApi.invokeCallback = spyApi.yield; + delegateToCalls("yieldOn", false, "yieldOn", function () { + throw new Error(this.toString() + " cannot yield since it was not yet invoked."); + }); + delegateToCalls("yieldTo", false, "yieldTo", function (property) { + throw new Error(this.toString() + " cannot yield to '" + property + + "' since it was not yet invoked."); + }); + delegateToCalls("yieldToOn", false, "yieldToOn", function (property) { + throw new Error(this.toString() + " cannot yield to '" + property + + "' since it was not yet invoked."); + }); + + spyApi.formatters = { + "c": function (spy) { + return sinon.timesInWords(spy.callCount); + }, + + "n": function (spy) { + return spy.toString(); + }, + + "C": function (spy) { + var calls = []; + + for (var i = 0, l = spy.callCount; i < l; ++i) { + var stringifiedCall = " " + spy.getCall(i).toString(); + if (/\n/.test(calls[i - 1])) { + stringifiedCall = "\n" + stringifiedCall; + } + push.call(calls, stringifiedCall); + } + + return calls.length > 0 ? "\n" + calls.join("\n") : ""; + }, + + "t": function (spy) { + var objects = []; + + for (var i = 0, l = spy.callCount; i < l; ++i) { + push.call(objects, sinon.format(spy.thisValues[i])); + } + + return objects.join(", "); + }, + + "*": function (spy, args) { + var formatted = []; + + for (var i = 0, l = args.length; i < l; ++i) { + push.call(formatted, sinon.format(args[i])); + } + + return formatted.join(", "); + } + }; + + sinon.extend(spy, spyApi); + + spy.spyCall = sinon.spyCall; + + if (commonJSModule) { + module.exports = spy; + } else { + sinon.spy = spy; + } +}(typeof sinon == "object" && sinon || null)); + +/** + * @depend ../sinon.js + * @depend spy.js + */ +/*jslint eqeqeq: false, onevar: false*/ +/*global module, require, sinon*/ +/** + * Stub functions + * + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + */ + +(function (sinon) { + var commonJSModule = typeof module == "object" && typeof require == "function"; + + if (!sinon && commonJSModule) { + sinon = require("../sinon"); + } + + if (!sinon) { + return; + } + + function stub(object, property, func) { + if (!!func && typeof func != "function") { + throw new TypeError("Custom stub should be function"); + } + + var wrapper; + + if (func) { + wrapper = sinon.spy && sinon.spy.create ? sinon.spy.create(func) : func; + } else { + wrapper = stub.create(); + } + + if (!object && !property) { + return sinon.stub.create(); + } + + if (!property && !!object && typeof object == "object") { + for (var prop in object) { + if (typeof object[prop] === "function") { + stub(object, prop); + } + } + + return object; + } + + return sinon.wrapMethod(object, property, wrapper); + } + + function getChangingValue(stub, property) { + var index = stub.callCount - 1; + var values = stub[property]; + var prop = index in values ? values[index] : values[values.length - 1]; + stub[property + "Last"] = prop; + + return prop; + } + + function getCallback(stub, args) { + var callArgAt = getChangingValue(stub, "callArgAts"); + + if (callArgAt < 0) { + var callArgProp = getChangingValue(stub, "callArgProps"); + + for (var i = 0, l = args.length; i < l; ++i) { + if (!callArgProp && typeof args[i] == "function") { + return args[i]; + } + + if (callArgProp && args[i] && + typeof args[i][callArgProp] == "function") { + return args[i][callArgProp]; + } + } + + return null; + } + + return args[callArgAt]; + } + + var join = Array.prototype.join; + + function getCallbackError(stub, func, args) { + if (stub.callArgAtsLast < 0) { + var msg; + + if (stub.callArgPropsLast) { + msg = sinon.functionName(stub) + + " expected to yield to '" + stub.callArgPropsLast + + "', but no object with such a property was passed." + } else { + msg = sinon.functionName(stub) + + " expected to yield, but no callback was passed." + } + + if (args.length > 0) { + msg += " Received [" + join.call(args, ", ") + "]"; + } + + return msg; + } + + return "argument at index " + stub.callArgAtsLast + " is not a function: " + func; + } + + var nextTick = (function () { + if (typeof process === "object" && typeof process.nextTick === "function") { + return process.nextTick; + } else if (typeof setImmediate === "function") { + return setImmediate; + } else { + return function (callback) { + setTimeout(callback, 0); + }; + } + })(); + + function callCallback(stub, args) { + if (stub.callArgAts.length > 0) { + var func = getCallback(stub, args); + + if (typeof func != "function") { + throw new TypeError(getCallbackError(stub, func, args)); + } + + var callbackArguments = getChangingValue(stub, "callbackArguments"); + var callbackContext = getChangingValue(stub, "callbackContexts"); + + if (stub.callbackAsync) { + nextTick(function() { + func.apply(callbackContext, callbackArguments); + }); + } else { + func.apply(callbackContext, callbackArguments); + } + } + } + + var uuid = 0; + + sinon.extend(stub, (function () { + var slice = Array.prototype.slice, proto; + + function throwsException(error, message) { + if (typeof error == "string") { + this.exception = new Error(message || ""); + this.exception.name = error; + } else if (!error) { + this.exception = new Error("Error"); + } else { + this.exception = error; + } + + return this; + } + + proto = { + create: function create() { + var functionStub = function () { + + callCallback(functionStub, arguments); + + if (functionStub.exception) { + throw functionStub.exception; + } else if (typeof functionStub.returnArgAt == 'number') { + return arguments[functionStub.returnArgAt]; + } else if (functionStub.returnThis) { + return this; + } + return functionStub.returnValue; + }; + + functionStub.id = "stub#" + uuid++; + var orig = functionStub; + functionStub = sinon.spy.create(functionStub); + functionStub.func = orig; + + functionStub.callArgAts = []; + functionStub.callbackArguments = []; + functionStub.callbackContexts = []; + functionStub.callArgProps = []; + + sinon.extend(functionStub, stub); + functionStub._create = sinon.stub.create; + functionStub.displayName = "stub"; + functionStub.toString = sinon.functionToString; + + return functionStub; + }, + + resetBehavior: function () { + var i; + + this.callArgAts = []; + this.callbackArguments = []; + this.callbackContexts = []; + this.callArgProps = []; + + delete this.returnValue; + delete this.returnArgAt; + this.returnThis = false; + + if (this.fakes) { + for (i = 0; i < this.fakes.length; i++) { + this.fakes[i].resetBehavior(); + } + } + }, + + returns: function returns(value) { + this.returnValue = value; + + return this; + }, + + returnsArg: function returnsArg(pos) { + if (typeof pos != "number") { + throw new TypeError("argument index is not number"); + } + + this.returnArgAt = pos; + + return this; + }, + + returnsThis: function returnsThis() { + this.returnThis = true; + + return this; + }, + + "throws": throwsException, + throwsException: throwsException, + + callsArg: function callsArg(pos) { + if (typeof pos != "number") { + throw new TypeError("argument index is not number"); + } + + this.callArgAts.push(pos); + this.callbackArguments.push([]); + this.callbackContexts.push(undefined); + this.callArgProps.push(undefined); + + return this; + }, + + callsArgOn: function callsArgOn(pos, context) { + if (typeof pos != "number") { + throw new TypeError("argument index is not number"); + } + if (typeof context != "object") { + throw new TypeError("argument context is not an object"); + } + + this.callArgAts.push(pos); + this.callbackArguments.push([]); + this.callbackContexts.push(context); + this.callArgProps.push(undefined); + + return this; + }, + + callsArgWith: function callsArgWith(pos) { + if (typeof pos != "number") { + throw new TypeError("argument index is not number"); + } + + this.callArgAts.push(pos); + this.callbackArguments.push(slice.call(arguments, 1)); + this.callbackContexts.push(undefined); + this.callArgProps.push(undefined); + + return this; + }, + + callsArgOnWith: function callsArgWith(pos, context) { + if (typeof pos != "number") { + throw new TypeError("argument index is not number"); + } + if (typeof context != "object") { + throw new TypeError("argument context is not an object"); + } + + this.callArgAts.push(pos); + this.callbackArguments.push(slice.call(arguments, 2)); + this.callbackContexts.push(context); + this.callArgProps.push(undefined); + + return this; + }, + + yields: function () { + this.callArgAts.push(-1); + this.callbackArguments.push(slice.call(arguments, 0)); + this.callbackContexts.push(undefined); + this.callArgProps.push(undefined); + + return this; + }, + + yieldsOn: function (context) { + if (typeof context != "object") { + throw new TypeError("argument context is not an object"); + } + + this.callArgAts.push(-1); + this.callbackArguments.push(slice.call(arguments, 1)); + this.callbackContexts.push(context); + this.callArgProps.push(undefined); + + return this; + }, + + yieldsTo: function (prop) { + this.callArgAts.push(-1); + this.callbackArguments.push(slice.call(arguments, 1)); + this.callbackContexts.push(undefined); + this.callArgProps.push(prop); + + return this; + }, + + yieldsToOn: function (prop, context) { + if (typeof context != "object") { + throw new TypeError("argument context is not an object"); + } + + this.callArgAts.push(-1); + this.callbackArguments.push(slice.call(arguments, 2)); + this.callbackContexts.push(context); + this.callArgProps.push(prop); + + return this; + } + }; + + // create asynchronous versions of callsArg* and yields* methods + for (var method in proto) { + // need to avoid creating anotherasync versions of the newly added async methods + if (proto.hasOwnProperty(method) && + method.match(/^(callsArg|yields|thenYields$)/) && + !method.match(/Async/)) { + proto[method + 'Async'] = (function (syncFnName) { + return function () { + this.callbackAsync = true; + return this[syncFnName].apply(this, arguments); + }; + })(method); + } + } + + return proto; + + }())); + + if (commonJSModule) { + module.exports = stub; + } else { + sinon.stub = stub; + } +}(typeof sinon == "object" && sinon || null)); + +/** + * @depend ../sinon.js + * @depend stub.js + */ +/*jslint eqeqeq: false, onevar: false, nomen: false*/ +/*global module, require, sinon*/ +/** + * Mock functions. + * + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + */ + +(function (sinon) { + var commonJSModule = typeof module == "object" && typeof require == "function"; + var push = [].push; + + if (!sinon && commonJSModule) { + sinon = require("../sinon"); + } + + if (!sinon) { + return; + } + + function mock(object) { + if (!object) { + return sinon.expectation.create("Anonymous mock"); + } + + return mock.create(object); + } + + sinon.mock = mock; + + sinon.extend(mock, (function () { + function each(collection, callback) { + if (!collection) { + return; + } + + for (var i = 0, l = collection.length; i < l; i += 1) { + callback(collection[i]); + } + } + + return { + create: function create(object) { + if (!object) { + throw new TypeError("object is null"); + } + + var mockObject = sinon.extend({}, mock); + mockObject.object = object; + delete mockObject.create; + + return mockObject; + }, + + expects: function expects(method) { + if (!method) { + throw new TypeError("method is falsy"); + } + + if (!this.expectations) { + this.expectations = {}; + this.proxies = []; + } + + if (!this.expectations[method]) { + this.expectations[method] = []; + var mockObject = this; + + sinon.wrapMethod(this.object, method, function () { + return mockObject.invokeMethod(method, this, arguments); + }); + + push.call(this.proxies, method); + } + + var expectation = sinon.expectation.create(method); + push.call(this.expectations[method], expectation); + + return expectation; + }, + + restore: function restore() { + var object = this.object; + + each(this.proxies, function (proxy) { + if (typeof object[proxy].restore == "function") { + object[proxy].restore(); + } + }); + }, + + verify: function verify() { + var expectations = this.expectations || {}; + var messages = [], met = []; + + each(this.proxies, function (proxy) { + each(expectations[proxy], function (expectation) { + if (!expectation.met()) { + push.call(messages, expectation.toString()); + } else { + push.call(met, expectation.toString()); + } + }); + }); + + this.restore(); + + if (messages.length > 0) { + sinon.expectation.fail(messages.concat(met).join("\n")); + } else { + sinon.expectation.pass(messages.concat(met).join("\n")); + } + + return true; + }, + + invokeMethod: function invokeMethod(method, thisValue, args) { + var expectations = this.expectations && this.expectations[method]; + var length = expectations && expectations.length || 0, i; + + for (i = 0; i < length; i += 1) { + if (!expectations[i].met() && + expectations[i].allowsCall(thisValue, args)) { + return expectations[i].apply(thisValue, args); + } + } + + var messages = [], available, exhausted = 0; + + for (i = 0; i < length; i += 1) { + if (expectations[i].allowsCall(thisValue, args)) { + available = available || expectations[i]; + } else { + exhausted += 1; + } + push.call(messages, " " + expectations[i].toString()); + } + + if (exhausted === 0) { + return available.apply(thisValue, args); + } + + messages.unshift("Unexpected call: " + sinon.spyCall.toString.call({ + proxy: method, + args: args + })); + + sinon.expectation.fail(messages.join("\n")); + } + }; + }())); + + var times = sinon.timesInWords; + + sinon.expectation = (function () { + var slice = Array.prototype.slice; + var _invoke = sinon.spy.invoke; + + function callCountInWords(callCount) { + if (callCount == 0) { + return "never called"; + } else { + return "called " + times(callCount); + } + } + + function expectedCallCountInWords(expectation) { + var min = expectation.minCalls; + var max = expectation.maxCalls; + + if (typeof min == "number" && typeof max == "number") { + var str = times(min); + + if (min != max) { + str = "at least " + str + " and at most " + times(max); + } + + return str; + } + + if (typeof min == "number") { + return "at least " + times(min); + } + + return "at most " + times(max); + } + + function receivedMinCalls(expectation) { + var hasMinLimit = typeof expectation.minCalls == "number"; + return !hasMinLimit || expectation.callCount >= expectation.minCalls; + } + + function receivedMaxCalls(expectation) { + if (typeof expectation.maxCalls != "number") { + return false; + } + + return expectation.callCount == expectation.maxCalls; + } + + return { + minCalls: 1, + maxCalls: 1, + + create: function create(methodName) { + var expectation = sinon.extend(sinon.stub.create(), sinon.expectation); + delete expectation.create; + expectation.method = methodName; + + return expectation; + }, + + invoke: function invoke(func, thisValue, args) { + this.verifyCallAllowed(thisValue, args); + + return _invoke.apply(this, arguments); + }, + + atLeast: function atLeast(num) { + if (typeof num != "number") { + throw new TypeError("'" + num + "' is not number"); + } + + if (!this.limitsSet) { + this.maxCalls = null; + this.limitsSet = true; + } + + this.minCalls = num; + + return this; + }, + + atMost: function atMost(num) { + if (typeof num != "number") { + throw new TypeError("'" + num + "' is not number"); + } + + if (!this.limitsSet) { + this.minCalls = null; + this.limitsSet = true; + } + + this.maxCalls = num; + + return this; + }, + + never: function never() { + return this.exactly(0); + }, + + once: function once() { + return this.exactly(1); + }, + + twice: function twice() { + return this.exactly(2); + }, + + thrice: function thrice() { + return this.exactly(3); + }, + + exactly: function exactly(num) { + if (typeof num != "number") { + throw new TypeError("'" + num + "' is not a number"); + } + + this.atLeast(num); + return this.atMost(num); + }, + + met: function met() { + return !this.failed && receivedMinCalls(this); + }, + + verifyCallAllowed: function verifyCallAllowed(thisValue, args) { + if (receivedMaxCalls(this)) { + this.failed = true; + sinon.expectation.fail(this.method + " already called " + times(this.maxCalls)); + } + + if ("expectedThis" in this && this.expectedThis !== thisValue) { + sinon.expectation.fail(this.method + " called with " + thisValue + " as thisValue, expected " + + this.expectedThis); + } + + if (!("expectedArguments" in this)) { + return; + } + + if (!args) { + sinon.expectation.fail(this.method + " received no arguments, expected " + + sinon.format(this.expectedArguments)); + } + + if (args.length < this.expectedArguments.length) { + sinon.expectation.fail(this.method + " received too few arguments (" + sinon.format(args) + + "), expected " + sinon.format(this.expectedArguments)); + } + + if (this.expectsExactArgCount && + args.length != this.expectedArguments.length) { + sinon.expectation.fail(this.method + " received too many arguments (" + sinon.format(args) + + "), expected " + sinon.format(this.expectedArguments)); + } + + for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) { + if (!sinon.deepEqual(this.expectedArguments[i], args[i])) { + sinon.expectation.fail(this.method + " received wrong arguments " + sinon.format(args) + + ", expected " + sinon.format(this.expectedArguments)); + } + } + }, + + allowsCall: function allowsCall(thisValue, args) { + if (this.met() && receivedMaxCalls(this)) { + return false; + } + + if ("expectedThis" in this && this.expectedThis !== thisValue) { + return false; + } + + if (!("expectedArguments" in this)) { + return true; + } + + args = args || []; + + if (args.length < this.expectedArguments.length) { + return false; + } + + if (this.expectsExactArgCount && + args.length != this.expectedArguments.length) { + return false; + } + + for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) { + if (!sinon.deepEqual(this.expectedArguments[i], args[i])) { + return false; + } + } + + return true; + }, + + withArgs: function withArgs() { + this.expectedArguments = slice.call(arguments); + return this; + }, + + withExactArgs: function withExactArgs() { + this.withArgs.apply(this, arguments); + this.expectsExactArgCount = true; + return this; + }, + + on: function on(thisValue) { + this.expectedThis = thisValue; + return this; + }, + + toString: function () { + var args = (this.expectedArguments || []).slice(); + + if (!this.expectsExactArgCount) { + push.call(args, "[...]"); + } + + var callStr = sinon.spyCall.toString.call({ + proxy: this.method || "anonymous mock expectation", + args: args + }); + + var message = callStr.replace(", [...", "[, ...") + " " + + expectedCallCountInWords(this); + + if (this.met()) { + return "Expectation met: " + message; + } + + return "Expected " + message + " (" + + callCountInWords(this.callCount) + ")"; + }, + + verify: function verify() { + if (!this.met()) { + sinon.expectation.fail(this.toString()); + } else { + sinon.expectation.pass(this.toString()); + } + + return true; + }, + + pass: function(message) { + sinon.assert.pass(message); + }, + fail: function (message) { + var exception = new Error(message); + exception.name = "ExpectationError"; + + throw exception; + } + }; + }()); + + if (commonJSModule) { + module.exports = mock; + } else { + sinon.mock = mock; + } +}(typeof sinon == "object" && sinon || null)); + +/** + * @depend ../sinon.js + * @depend stub.js + * @depend mock.js + */ +/*jslint eqeqeq: false, onevar: false, forin: true*/ +/*global module, require, sinon*/ +/** + * Collections of stubs, spies and mocks. + * + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + */ + +(function (sinon) { + var commonJSModule = typeof module == "object" && typeof require == "function"; + var push = [].push; + var hasOwnProperty = Object.prototype.hasOwnProperty; + + if (!sinon && commonJSModule) { + sinon = require("../sinon"); + } + + if (!sinon) { + return; + } + + function getFakes(fakeCollection) { + if (!fakeCollection.fakes) { + fakeCollection.fakes = []; + } + + return fakeCollection.fakes; + } + + function each(fakeCollection, method) { + var fakes = getFakes(fakeCollection); + + for (var i = 0, l = fakes.length; i < l; i += 1) { + if (typeof fakes[i][method] == "function") { + fakes[i][method](); + } + } + } + + function compact(fakeCollection) { + var fakes = getFakes(fakeCollection); + var i = 0; + while (i < fakes.length) { + fakes.splice(i, 1); + } + } + + var collection = { + verify: function resolve() { + each(this, "verify"); + }, + + restore: function restore() { + each(this, "restore"); + compact(this); + }, + + verifyAndRestore: function verifyAndRestore() { + var exception; + + try { + this.verify(); + } catch (e) { + exception = e; + } + + this.restore(); + + if (exception) { + throw exception; + } + }, + + add: function add(fake) { + push.call(getFakes(this), fake); + return fake; + }, + + spy: function spy() { + return this.add(sinon.spy.apply(sinon, arguments)); + }, + + stub: function stub(object, property, value) { + if (property) { + var original = object[property]; + + if (typeof original != "function") { + if (!hasOwnProperty.call(object, property)) { + throw new TypeError("Cannot stub non-existent own property " + property); + } + + object[property] = value; + + return this.add({ + restore: function () { + object[property] = original; + } + }); + } + } + if (!property && !!object && typeof object == "object") { + var stubbedObj = sinon.stub.apply(sinon, arguments); + + for (var prop in stubbedObj) { + if (typeof stubbedObj[prop] === "function") { + this.add(stubbedObj[prop]); + } + } + + return stubbedObj; + } + + return this.add(sinon.stub.apply(sinon, arguments)); + }, + + mock: function mock() { + return this.add(sinon.mock.apply(sinon, arguments)); + }, + + inject: function inject(obj) { + var col = this; + + obj.spy = function () { + return col.spy.apply(col, arguments); + }; + + obj.stub = function () { + return col.stub.apply(col, arguments); + }; + + obj.mock = function () { + return col.mock.apply(col, arguments); + }; + + return obj; + } + }; + + if (commonJSModule) { + module.exports = collection; + } else { + sinon.collection = collection; + } +}(typeof sinon == "object" && sinon || null)); + +/*jslint eqeqeq: false, plusplus: false, evil: true, onevar: false, browser: true, forin: false*/ +/*global module, require, window*/ +/** + * Fake timer API + * setTimeout + * setInterval + * clearTimeout + * clearInterval + * tick + * reset + * Date + * + * Inspired by jsUnitMockTimeOut from JsUnit + * + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + */ + +if (typeof sinon == "undefined") { + var sinon = {}; +} + +(function (global) { + var id = 1; + + function addTimer(args, recurring) { + if (args.length === 0) { + throw new Error("Function requires at least 1 parameter"); + } + + var toId = id++; + var delay = args[1] || 0; + + if (!this.timeouts) { + this.timeouts = {}; + } + + this.timeouts[toId] = { + id: toId, + func: args[0], + callAt: this.now + delay, + invokeArgs: Array.prototype.slice.call(args, 2) + }; + + if (recurring === true) { + this.timeouts[toId].interval = delay; + } + + return toId; + } + + function parseTime(str) { + if (!str) { + return 0; + } + + var strings = str.split(":"); + var l = strings.length, i = l; + var ms = 0, parsed; + + if (l > 3 || !/^(\d\d:){0,2}\d\d?$/.test(str)) { + throw new Error("tick only understands numbers and 'h:m:s'"); + } + + while (i--) { + parsed = parseInt(strings[i], 10); + + if (parsed >= 60) { + throw new Error("Invalid time " + str); + } + + ms += parsed * Math.pow(60, (l - i - 1)); + } + + return ms * 1000; + } + + function createObject(object) { + var newObject; + + if (Object.create) { + newObject = Object.create(object); + } else { + var F = function () {}; + F.prototype = object; + newObject = new F(); + } + + newObject.Date.clock = newObject; + return newObject; + } + + sinon.clock = { + now: 0, + + create: function create(now) { + var clock = createObject(this); + + if (typeof now == "number") { + clock.now = now; + } + + if (!!now && typeof now == "object") { + throw new TypeError("now should be milliseconds since UNIX epoch"); + } + + return clock; + }, + + setTimeout: function setTimeout(callback, timeout) { + return addTimer.call(this, arguments, false); + }, + + clearTimeout: function clearTimeout(timerId) { + if (!this.timeouts) { + this.timeouts = []; + } + + if (timerId in this.timeouts) { + delete this.timeouts[timerId]; + } + }, + + setInterval: function setInterval(callback, timeout) { + return addTimer.call(this, arguments, true); + }, + + clearInterval: function clearInterval(timerId) { + this.clearTimeout(timerId); + }, + + tick: function tick(ms) { + ms = typeof ms == "number" ? ms : parseTime(ms); + var tickFrom = this.now, tickTo = this.now + ms, previous = this.now; + var timer = this.firstTimerInRange(tickFrom, tickTo); + + var firstException; + while (timer && tickFrom <= tickTo) { + if (this.timeouts[timer.id]) { + tickFrom = this.now = timer.callAt; + try { + this.callTimer(timer); + } catch (e) { + firstException = firstException || e; + } + } + + timer = this.firstTimerInRange(previous, tickTo); + previous = tickFrom; + } + + this.now = tickTo; + + if (firstException) { + throw firstException; + } + + return this.now; + }, + + firstTimerInRange: function (from, to) { + var timer, smallest, originalTimer; + + for (var id in this.timeouts) { + if (this.timeouts.hasOwnProperty(id)) { + if (this.timeouts[id].callAt < from || this.timeouts[id].callAt > to) { + continue; + } + + if (!smallest || this.timeouts[id].callAt < smallest) { + originalTimer = this.timeouts[id]; + smallest = this.timeouts[id].callAt; + + timer = { + func: this.timeouts[id].func, + callAt: this.timeouts[id].callAt, + interval: this.timeouts[id].interval, + id: this.timeouts[id].id, + invokeArgs: this.timeouts[id].invokeArgs + }; + } + } + } + + return timer || null; + }, + + callTimer: function (timer) { + if (typeof timer.interval == "number") { + this.timeouts[timer.id].callAt += timer.interval; + } else { + delete this.timeouts[timer.id]; + } + + try { + if (typeof timer.func == "function") { + timer.func.apply(null, timer.invokeArgs); + } else { + eval(timer.func); + } + } catch (e) { + var exception = e; + } + + if (!this.timeouts[timer.id]) { + if (exception) { + throw exception; + } + return; + } + + if (exception) { + throw exception; + } + }, + + reset: function reset() { + this.timeouts = {}; + }, + + Date: (function () { + var NativeDate = Date; + + function ClockDate(year, month, date, hour, minute, second, ms) { + // Defensive and verbose to avoid potential harm in passing + // explicit undefined when user does not pass argument + switch (arguments.length) { + case 0: + return new NativeDate(ClockDate.clock.now); + case 1: + return new NativeDate(year); + case 2: + return new NativeDate(year, month); + case 3: + return new NativeDate(year, month, date); + case 4: + return new NativeDate(year, month, date, hour); + case 5: + return new NativeDate(year, month, date, hour, minute); + case 6: + return new NativeDate(year, month, date, hour, minute, second); + default: + return new NativeDate(year, month, date, hour, minute, second, ms); + } + } + + return mirrorDateProperties(ClockDate, NativeDate); + }()) + }; + + function mirrorDateProperties(target, source) { + if (source.now) { + target.now = function now() { + return target.clock.now; + }; + } else { + delete target.now; + } + + if (source.toSource) { + target.toSource = function toSource() { + return source.toSource(); + }; + } else { + delete target.toSource; + } + + target.toString = function toString() { + return source.toString(); + }; + + target.prototype = source.prototype; + target.parse = source.parse; + target.UTC = source.UTC; + target.prototype.toUTCString = source.prototype.toUTCString; + return target; + } + + var methods = ["Date", "setTimeout", "setInterval", + "clearTimeout", "clearInterval"]; + + function restore() { + var method; + + for (var i = 0, l = this.methods.length; i < l; i++) { + method = this.methods[i]; + if (global[method].hadOwnProperty) { + global[method] = this["_" + method]; + } else { + delete global[method]; + } + } + + // Prevent multiple executions which will completely remove these props + this.methods = []; + } + + function stubGlobal(method, clock) { + clock[method].hadOwnProperty = Object.prototype.hasOwnProperty.call(global, method); + clock["_" + method] = global[method]; + + if (method == "Date") { + var date = mirrorDateProperties(clock[method], global[method]); + global[method] = date; + } else { + global[method] = function () { + return clock[method].apply(clock, arguments); + }; + + for (var prop in clock[method]) { + if (clock[method].hasOwnProperty(prop)) { + global[method][prop] = clock[method][prop]; + } + } + } + + global[method].clock = clock; + } + + sinon.useFakeTimers = function useFakeTimers(now) { + var clock = sinon.clock.create(now); + clock.restore = restore; + clock.methods = Array.prototype.slice.call(arguments, + typeof now == "number" ? 1 : 0); + + if (clock.methods.length === 0) { + clock.methods = methods; + } + + for (var i = 0, l = clock.methods.length; i < l; i++) { + stubGlobal(clock.methods[i], clock); + } + + return clock; + }; +}(typeof global != "undefined" && typeof global !== "function" ? global : this)); + +sinon.timers = { + setTimeout: setTimeout, + clearTimeout: clearTimeout, + setInterval: setInterval, + clearInterval: clearInterval, + Date: Date +}; + +if (typeof module == "object" && typeof require == "function") { + module.exports = sinon; +} + +/*jslint eqeqeq: false, onevar: false*/ +/*global sinon, module, require, ActiveXObject, XMLHttpRequest, DOMParser*/ +/** + * Minimal Event interface implementation + * + * Original implementation by Sven Fuchs: https://gist.github.com/995028 + * Modifications and tests by Christian Johansen. + * + * @author Sven Fuchs (svenfuchs@artweb-design.de) + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2011 Sven Fuchs, Christian Johansen + */ + +if (typeof sinon == "undefined") { + this.sinon = {}; +} + +(function () { + var push = [].push; + + sinon.Event = function Event(type, bubbles, cancelable, target) { + this.initEvent(type, bubbles, cancelable, target); + }; + + sinon.Event.prototype = { + initEvent: function(type, bubbles, cancelable, target) { + this.type = type; + this.bubbles = bubbles; + this.cancelable = cancelable; + this.target = target; + }, + + stopPropagation: function () {}, + + preventDefault: function () { + this.defaultPrevented = true; + } + }; + + sinon.EventTarget = { + addEventListener: function addEventListener(event, listener, useCapture) { + this.eventListeners = this.eventListeners || {}; + this.eventListeners[event] = this.eventListeners[event] || []; + push.call(this.eventListeners[event], listener); + }, + + removeEventListener: function removeEventListener(event, listener, useCapture) { + var listeners = this.eventListeners && this.eventListeners[event] || []; + + for (var i = 0, l = listeners.length; i < l; ++i) { + if (listeners[i] == listener) { + return listeners.splice(i, 1); + } + } + }, + + dispatchEvent: function dispatchEvent(event) { + var type = event.type; + var listeners = this.eventListeners && this.eventListeners[type] || []; + + for (var i = 0; i < listeners.length; i++) { + if (typeof listeners[i] == "function") { + listeners[i].call(this, event); + } else { + listeners[i].handleEvent(event); + } + } + + return !!event.defaultPrevented; + } + }; +}()); + +/** + * @depend ../../sinon.js + * @depend event.js + */ +/*jslint eqeqeq: false, onevar: false*/ +/*global sinon, module, require, ActiveXObject, XMLHttpRequest, DOMParser*/ +/** + * Fake XMLHttpRequest object + * + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + */ + +if (typeof sinon == "undefined") { + this.sinon = {}; +} +sinon.xhr = { XMLHttpRequest: this.XMLHttpRequest }; + +// wrapper for global +(function(global) { + var xhr = sinon.xhr; + xhr.GlobalXMLHttpRequest = global.XMLHttpRequest; + xhr.GlobalActiveXObject = global.ActiveXObject; + xhr.supportsActiveX = typeof xhr.GlobalActiveXObject != "undefined"; + xhr.supportsXHR = typeof xhr.GlobalXMLHttpRequest != "undefined"; + xhr.workingXHR = xhr.supportsXHR ? xhr.GlobalXMLHttpRequest : xhr.supportsActiveX + ? function() { return new xhr.GlobalActiveXObject("MSXML2.XMLHTTP.3.0") } : false; + + /*jsl:ignore*/ + var unsafeHeaders = { + "Accept-Charset": true, + "Accept-Encoding": true, + "Connection": true, + "Content-Length": true, + "Cookie": true, + "Cookie2": true, + "Content-Transfer-Encoding": true, + "Date": true, + "Expect": true, + "Host": true, + "Keep-Alive": true, + "Referer": true, + "TE": true, + "Trailer": true, + "Transfer-Encoding": true, + "Upgrade": true, + "User-Agent": true, + "Via": true + }; + /*jsl:end*/ + + function FakeXMLHttpRequest() { + this.readyState = FakeXMLHttpRequest.UNSENT; + this.requestHeaders = {}; + this.requestBody = null; + this.status = 0; + this.statusText = ""; + + var xhr = this; + var events = ["loadstart", "load", "abort", "loadend"]; + + function addEventListener(eventName) { + xhr.addEventListener(eventName, function (event) { + var listener = xhr["on" + eventName]; + + if (listener && typeof listener == "function") { + listener(event); + } + }); + } + + for (var i = events.length - 1; i >= 0; i--) { + addEventListener(events[i]); + } + + if (typeof FakeXMLHttpRequest.onCreate == "function") { + FakeXMLHttpRequest.onCreate(this); + } + } + + function verifyState(xhr) { + if (xhr.readyState !== FakeXMLHttpRequest.OPENED) { + throw new Error("INVALID_STATE_ERR"); + } + + if (xhr.sendFlag) { + throw new Error("INVALID_STATE_ERR"); + } + } + + // filtering to enable a white-list version of Sinon FakeXhr, + // where whitelisted requests are passed through to real XHR + function each(collection, callback) { + if (!collection) return; + for (var i = 0, l = collection.length; i < l; i += 1) { + callback(collection[i]); + } + } + function some(collection, callback) { + for (var index = 0; index < collection.length; index++) { + if(callback(collection[index]) === true) return true; + }; + return false; + } + // largest arity in XHR is 5 - XHR#open + var apply = function(obj,method,args) { + switch(args.length) { + case 0: return obj[method](); + case 1: return obj[method](args[0]); + case 2: return obj[method](args[0],args[1]); + case 3: return obj[method](args[0],args[1],args[2]); + case 4: return obj[method](args[0],args[1],args[2],args[3]); + case 5: return obj[method](args[0],args[1],args[2],args[3],args[4]); + }; + }; + + FakeXMLHttpRequest.filters = []; + FakeXMLHttpRequest.addFilter = function(fn) { + this.filters.push(fn) + }; + var IE6Re = /MSIE 6/; + FakeXMLHttpRequest.defake = function(fakeXhr,xhrArgs) { + var xhr = new sinon.xhr.workingXHR(); + each(["open","setRequestHeader","send","abort","getResponseHeader", + "getAllResponseHeaders","addEventListener","overrideMimeType","removeEventListener"], + function(method) { + fakeXhr[method] = function() { + return apply(xhr,method,arguments); + }; + }); + + var copyAttrs = function(args) { + each(args, function(attr) { + try { + fakeXhr[attr] = xhr[attr] + } catch(e) { + if(!IE6Re.test(navigator.userAgent)) throw e; + } + }); + }; + + var stateChange = function() { + fakeXhr.readyState = xhr.readyState; + if(xhr.readyState >= FakeXMLHttpRequest.HEADERS_RECEIVED) { + copyAttrs(["status","statusText"]); + } + if(xhr.readyState >= FakeXMLHttpRequest.LOADING) { + copyAttrs(["responseText"]); + } + if(xhr.readyState === FakeXMLHttpRequest.DONE) { + copyAttrs(["responseXML"]); + } + if(fakeXhr.onreadystatechange) fakeXhr.onreadystatechange.call(fakeXhr); + }; + if(xhr.addEventListener) { + for(var event in fakeXhr.eventListeners) { + if(fakeXhr.eventListeners.hasOwnProperty(event)) { + each(fakeXhr.eventListeners[event],function(handler) { + xhr.addEventListener(event, handler); + }); + } + } + xhr.addEventListener("readystatechange",stateChange); + } else { + xhr.onreadystatechange = stateChange; + } + apply(xhr,"open",xhrArgs); + }; + FakeXMLHttpRequest.useFilters = false; + + function verifyRequestSent(xhr) { + if (xhr.readyState == FakeXMLHttpRequest.DONE) { + throw new Error("Request done"); + } + } + + function verifyHeadersReceived(xhr) { + if (xhr.async && xhr.readyState != FakeXMLHttpRequest.HEADERS_RECEIVED) { + throw new Error("No headers received"); + } + } + + function verifyResponseBodyType(body) { + if (typeof body != "string") { + var error = new Error("Attempted to respond to fake XMLHttpRequest with " + + body + ", which is not a string."); + error.name = "InvalidBodyException"; + throw error; + } + } + + sinon.extend(FakeXMLHttpRequest.prototype, sinon.EventTarget, { + async: true, + + open: function open(method, url, async, username, password) { + this.method = method; + this.url = url; + this.async = typeof async == "boolean" ? async : true; + this.username = username; + this.password = password; + this.responseText = null; + this.responseXML = null; + this.requestHeaders = {}; + this.sendFlag = false; + if(sinon.FakeXMLHttpRequest.useFilters === true) { + var xhrArgs = arguments; + var defake = some(FakeXMLHttpRequest.filters,function(filter) { + return filter.apply(this,xhrArgs) + }); + if (defake) { + return sinon.FakeXMLHttpRequest.defake(this,arguments); + } + } + this.readyStateChange(FakeXMLHttpRequest.OPENED); + }, + + readyStateChange: function readyStateChange(state) { + this.readyState = state; + + if (typeof this.onreadystatechange == "function") { + try { + this.onreadystatechange(); + } catch (e) { + sinon.logError("Fake XHR onreadystatechange handler", e); + } + } + + this.dispatchEvent(new sinon.Event("readystatechange")); + + switch (this.readyState) { + case FakeXMLHttpRequest.DONE: + this.dispatchEvent(new sinon.Event("load", false, false, this)); + this.dispatchEvent(new sinon.Event("loadend", false, false, this)); + break; + } + }, + + setRequestHeader: function setRequestHeader(header, value) { + verifyState(this); + + if (unsafeHeaders[header] || /^(Sec-|Proxy-)/.test(header)) { + throw new Error("Refused to set unsafe header \"" + header + "\""); + } + + if (this.requestHeaders[header]) { + this.requestHeaders[header] += "," + value; + } else { + this.requestHeaders[header] = value; + } + }, + + // Helps testing + setResponseHeaders: function setResponseHeaders(headers) { + this.responseHeaders = {}; + + for (var header in headers) { + if (headers.hasOwnProperty(header)) { + this.responseHeaders[header] = headers[header]; + } + } + + if (this.async) { + this.readyStateChange(FakeXMLHttpRequest.HEADERS_RECEIVED); + } else { + this.readyState = FakeXMLHttpRequest.HEADERS_RECEIVED; + } + }, + + // Currently treats ALL data as a DOMString (i.e. no Document) + send: function send(data) { + verifyState(this); + + if (!/^(get|head)$/i.test(this.method)) { + if (this.requestHeaders["Content-Type"]) { + var value = this.requestHeaders["Content-Type"].split(";"); + this.requestHeaders["Content-Type"] = value[0] + ";charset=utf-8"; + } else { + this.requestHeaders["Content-Type"] = "text/plain;charset=utf-8"; + } + + this.requestBody = data; + } + + this.errorFlag = false; + this.sendFlag = this.async; + this.readyStateChange(FakeXMLHttpRequest.OPENED); + + if (typeof this.onSend == "function") { + this.onSend(this); + } + + this.dispatchEvent(new sinon.Event("loadstart", false, false, this)); + }, + + abort: function abort() { + this.aborted = true; + this.responseText = null; + this.errorFlag = true; + this.requestHeaders = {}; + + if (this.readyState > sinon.FakeXMLHttpRequest.UNSENT && this.sendFlag) { + this.readyStateChange(sinon.FakeXMLHttpRequest.DONE); + this.sendFlag = false; + } + + this.readyState = sinon.FakeXMLHttpRequest.UNSENT; + + this.dispatchEvent(new sinon.Event("abort", false, false, this)); + if (typeof this.onerror === "function") { + this.onerror(); + } + }, + + getResponseHeader: function getResponseHeader(header) { + if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) { + return null; + } + + if (/^Set-Cookie2?$/i.test(header)) { + return null; + } + + header = header.toLowerCase(); + + for (var h in this.responseHeaders) { + if (h.toLowerCase() == header) { + return this.responseHeaders[h]; + } + } + + return null; + }, + + getAllResponseHeaders: function getAllResponseHeaders() { + if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) { + return ""; + } + + var headers = ""; + + for (var header in this.responseHeaders) { + if (this.responseHeaders.hasOwnProperty(header) && + !/^Set-Cookie2?$/i.test(header)) { + headers += header + ": " + this.responseHeaders[header] + "\r\n"; + } + } + + return headers; + }, + + setResponseBody: function setResponseBody(body) { + verifyRequestSent(this); + verifyHeadersReceived(this); + verifyResponseBodyType(body); + + var chunkSize = this.chunkSize || 10; + var index = 0; + this.responseText = ""; + + do { + if (this.async) { + this.readyStateChange(FakeXMLHttpRequest.LOADING); + } + + this.responseText += body.substring(index, index + chunkSize); + index += chunkSize; + } while (index < body.length); + + var type = this.getResponseHeader("Content-Type"); + + if (this.responseText && + (!type || /(text\/xml)|(application\/xml)|(\+xml)/.test(type))) { + try { + this.responseXML = FakeXMLHttpRequest.parseXML(this.responseText); + } catch (e) { + // Unable to parse XML - no biggie + } + } + + if (this.async) { + this.readyStateChange(FakeXMLHttpRequest.DONE); + } else { + this.readyState = FakeXMLHttpRequest.DONE; + } + }, + + respond: function respond(status, headers, body) { + this.setResponseHeaders(headers || {}); + this.status = typeof status == "number" ? status : 200; + this.statusText = FakeXMLHttpRequest.statusCodes[this.status]; + this.setResponseBody(body || ""); + if (typeof this.onload === "function"){ + this.onload(); + } + + } + }); + + sinon.extend(FakeXMLHttpRequest, { + UNSENT: 0, + OPENED: 1, + HEADERS_RECEIVED: 2, + LOADING: 3, + DONE: 4 + }); + + // Borrowed from JSpec + FakeXMLHttpRequest.parseXML = function parseXML(text) { + var xmlDoc; + + if (typeof DOMParser != "undefined") { + var parser = new DOMParser(); + xmlDoc = parser.parseFromString(text, "text/xml"); + } else { + xmlDoc = new ActiveXObject("Microsoft.XMLDOM"); + xmlDoc.async = "false"; + xmlDoc.loadXML(text); + } + + return xmlDoc; + }; + + FakeXMLHttpRequest.statusCodes = { + 100: "Continue", + 101: "Switching Protocols", + 200: "OK", + 201: "Created", + 202: "Accepted", + 203: "Non-Authoritative Information", + 204: "No Content", + 205: "Reset Content", + 206: "Partial Content", + 300: "Multiple Choice", + 301: "Moved Permanently", + 302: "Found", + 303: "See Other", + 304: "Not Modified", + 305: "Use Proxy", + 307: "Temporary Redirect", + 400: "Bad Request", + 401: "Unauthorized", + 402: "Payment Required", + 403: "Forbidden", + 404: "Not Found", + 405: "Method Not Allowed", + 406: "Not Acceptable", + 407: "Proxy Authentication Required", + 408: "Request Timeout", + 409: "Conflict", + 410: "Gone", + 411: "Length Required", + 412: "Precondition Failed", + 413: "Request Entity Too Large", + 414: "Request-URI Too Long", + 415: "Unsupported Media Type", + 416: "Requested Range Not Satisfiable", + 417: "Expectation Failed", + 422: "Unprocessable Entity", + 500: "Internal Server Error", + 501: "Not Implemented", + 502: "Bad Gateway", + 503: "Service Unavailable", + 504: "Gateway Timeout", + 505: "HTTP Version Not Supported" + }; + + sinon.useFakeXMLHttpRequest = function () { + sinon.FakeXMLHttpRequest.restore = function restore(keepOnCreate) { + if (xhr.supportsXHR) { + global.XMLHttpRequest = xhr.GlobalXMLHttpRequest; + } + + if (xhr.supportsActiveX) { + global.ActiveXObject = xhr.GlobalActiveXObject; + } + + delete sinon.FakeXMLHttpRequest.restore; + + if (keepOnCreate !== true) { + delete sinon.FakeXMLHttpRequest.onCreate; + } + }; + if (xhr.supportsXHR) { + global.XMLHttpRequest = sinon.FakeXMLHttpRequest; + } + + if (xhr.supportsActiveX) { + global.ActiveXObject = function ActiveXObject(objId) { + if (objId == "Microsoft.XMLHTTP" || /^Msxml2\.XMLHTTP/i.test(objId)) { + + return new sinon.FakeXMLHttpRequest(); + } + + return new xhr.GlobalActiveXObject(objId); + }; + } + + return sinon.FakeXMLHttpRequest; + }; + + sinon.FakeXMLHttpRequest = FakeXMLHttpRequest; +})(this); + +if (typeof module == "object" && typeof require == "function") { + module.exports = sinon; +} + +/** + * @depend fake_xml_http_request.js + */ +/*jslint eqeqeq: false, onevar: false, regexp: false, plusplus: false*/ +/*global module, require, window*/ +/** + * The Sinon "server" mimics a web server that receives requests from + * sinon.FakeXMLHttpRequest and provides an API to respond to those requests, + * both synchronously and asynchronously. To respond synchronuously, canned + * answers have to be provided upfront. + * + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + */ + +if (typeof sinon == "undefined") { + var sinon = {}; +} + +sinon.fakeServer = (function () { + var push = [].push; + function F() {} + + function create(proto) { + F.prototype = proto; + return new F(); + } + + function responseArray(handler) { + var response = handler; + + if (Object.prototype.toString.call(handler) != "[object Array]") { + response = [200, {}, handler]; + } + + if (typeof response[2] != "string") { + throw new TypeError("Fake server response body should be string, but was " + + typeof response[2]); + } + + return response; + } + + var wloc = typeof window !== "undefined" ? window.location : {}; + var rCurrLoc = new RegExp("^" + wloc.protocol + "//" + wloc.host); + + function matchOne(response, reqMethod, reqUrl) { + var rmeth = response.method; + var matchMethod = !rmeth || rmeth.toLowerCase() == reqMethod.toLowerCase(); + var url = response.url; + var matchUrl = !url || url == reqUrl || (typeof url.test == "function" && url.test(reqUrl)); + + return matchMethod && matchUrl; + } + + function match(response, request) { + var requestMethod = this.getHTTPMethod(request); + var requestUrl = request.url; + + if (!/^https?:\/\//.test(requestUrl) || rCurrLoc.test(requestUrl)) { + requestUrl = requestUrl.replace(rCurrLoc, ""); + } + + if (matchOne(response, this.getHTTPMethod(request), requestUrl)) { + if (typeof response.response == "function") { + var ru = response.url; + var args = [request].concat(!ru ? [] : requestUrl.match(ru).slice(1)); + return response.response.apply(response, args); + } + + return true; + } + + return false; + } + + function log(response, request) { + var str; + + str = "Request:\n" + sinon.format(request) + "\n\n"; + str += "Response:\n" + sinon.format(response) + "\n\n"; + + sinon.log(str); + } + + return { + create: function () { + var server = create(this); + this.xhr = sinon.useFakeXMLHttpRequest(); + server.requests = []; + + this.xhr.onCreate = function (xhrObj) { + server.addRequest(xhrObj); + }; + + return server; + }, + + addRequest: function addRequest(xhrObj) { + var server = this; + push.call(this.requests, xhrObj); + + xhrObj.onSend = function () { + server.handleRequest(this); + }; + + if (this.autoRespond && !this.responding) { + setTimeout(function () { + server.responding = false; + server.respond(); + }, this.autoRespondAfter || 10); + + this.responding = true; + } + }, + + getHTTPMethod: function getHTTPMethod(request) { + if (this.fakeHTTPMethods && /post/i.test(request.method)) { + var matches = (request.requestBody || "").match(/_method=([^\b;]+)/); + return !!matches ? matches[1] : request.method; + } + + return request.method; + }, + + handleRequest: function handleRequest(xhr) { + if (xhr.async) { + if (!this.queue) { + this.queue = []; + } + + push.call(this.queue, xhr); + } else { + this.processRequest(xhr); + } + }, + + respondWith: function respondWith(method, url, body) { + if (arguments.length == 1 && typeof method != "function") { + this.response = responseArray(method); + return; + } + + if (!this.responses) { this.responses = []; } + + if (arguments.length == 1) { + body = method; + url = method = null; + } + + if (arguments.length == 2) { + body = url; + url = method; + method = null; + } + + push.call(this.responses, { + method: method, + url: url, + response: typeof body == "function" ? body : responseArray(body) + }); + }, + + respond: function respond() { + if (arguments.length > 0) this.respondWith.apply(this, arguments); + var queue = this.queue || []; + var request; + + while(request = queue.shift()) { + this.processRequest(request); + } + }, + + processRequest: function processRequest(request) { + try { + if (request.aborted) { + return; + } + + var response = this.response || [404, {}, ""]; + + if (this.responses) { + for (var i = 0, l = this.responses.length; i < l; i++) { + if (match.call(this, this.responses[i], request)) { + response = this.responses[i].response; + break; + } + } + } + + if (request.readyState != 4) { + log(response, request); + + request.respond(response[0], response[1], response[2]); + } + } catch (e) { + sinon.logError("Fake server request processing", e); + } + }, + + restore: function restore() { + return this.xhr.restore && this.xhr.restore.apply(this.xhr, arguments); + } + }; +}()); + +if (typeof module == "object" && typeof require == "function") { + module.exports = sinon; +} + +/** + * @depend fake_server.js + * @depend fake_timers.js + */ +/*jslint browser: true, eqeqeq: false, onevar: false*/ +/*global sinon*/ +/** + * Add-on for sinon.fakeServer that automatically handles a fake timer along with + * the FakeXMLHttpRequest. The direct inspiration for this add-on is jQuery + * 1.3.x, which does not use xhr object's onreadystatehandler at all - instead, + * it polls the object for completion with setInterval. Dispite the direct + * motivation, there is nothing jQuery-specific in this file, so it can be used + * in any environment where the ajax implementation depends on setInterval or + * setTimeout. + * + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + */ + +(function () { + function Server() {} + Server.prototype = sinon.fakeServer; + + sinon.fakeServerWithClock = new Server(); + + sinon.fakeServerWithClock.addRequest = function addRequest(xhr) { + if (xhr.async) { + if (typeof setTimeout.clock == "object") { + this.clock = setTimeout.clock; + } else { + this.clock = sinon.useFakeTimers(); + this.resetClock = true; + } + + if (!this.longestTimeout) { + var clockSetTimeout = this.clock.setTimeout; + var clockSetInterval = this.clock.setInterval; + var server = this; + + this.clock.setTimeout = function (fn, timeout) { + server.longestTimeout = Math.max(timeout, server.longestTimeout || 0); + + return clockSetTimeout.apply(this, arguments); + }; + + this.clock.setInterval = function (fn, timeout) { + server.longestTimeout = Math.max(timeout, server.longestTimeout || 0); + + return clockSetInterval.apply(this, arguments); + }; + } + } + + return sinon.fakeServer.addRequest.call(this, xhr); + }; + + sinon.fakeServerWithClock.respond = function respond() { + var returnVal = sinon.fakeServer.respond.apply(this, arguments); + + if (this.clock) { + this.clock.tick(this.longestTimeout || 0); + this.longestTimeout = 0; + + if (this.resetClock) { + this.clock.restore(); + this.resetClock = false; + } + } + + return returnVal; + }; + + sinon.fakeServerWithClock.restore = function restore() { + if (this.clock) { + this.clock.restore(); + } + + return sinon.fakeServer.restore.apply(this, arguments); + }; +}()); + +/** + * @depend ../sinon.js + * @depend collection.js + * @depend util/fake_timers.js + * @depend util/fake_server_with_clock.js + */ +/*jslint eqeqeq: false, onevar: false, plusplus: false*/ +/*global require, module*/ +/** + * Manages fake collections as well as fake utilities such as Sinon's + * timers and fake XHR implementation in one convenient object. + * + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + */ + +if (typeof module == "object" && typeof require == "function") { + var sinon = require("../sinon"); + sinon.extend(sinon, require("./util/fake_timers")); +} + +(function () { + var push = [].push; + + function exposeValue(sandbox, config, key, value) { + if (!value) { + return; + } + + if (config.injectInto) { + config.injectInto[key] = value; + } else { + push.call(sandbox.args, value); + } + } + + function prepareSandboxFromConfig(config) { + var sandbox = sinon.create(sinon.sandbox); + + if (config.useFakeServer) { + if (typeof config.useFakeServer == "object") { + sandbox.serverPrototype = config.useFakeServer; + } + + sandbox.useFakeServer(); + } + + if (config.useFakeTimers) { + if (typeof config.useFakeTimers == "object") { + sandbox.useFakeTimers.apply(sandbox, config.useFakeTimers); + } else { + sandbox.useFakeTimers(); + } + } + + return sandbox; + } + + sinon.sandbox = sinon.extend(sinon.create(sinon.collection), { + useFakeTimers: function useFakeTimers() { + this.clock = sinon.useFakeTimers.apply(sinon, arguments); + + return this.add(this.clock); + }, + + serverPrototype: sinon.fakeServer, + + useFakeServer: function useFakeServer() { + var proto = this.serverPrototype || sinon.fakeServer; + + if (!proto || !proto.create) { + return null; + } + + this.server = proto.create(); + return this.add(this.server); + }, + + inject: function (obj) { + sinon.collection.inject.call(this, obj); + + if (this.clock) { + obj.clock = this.clock; + } + + if (this.server) { + obj.server = this.server; + obj.requests = this.server.requests; + } + + return obj; + }, + + create: function (config) { + if (!config) { + return sinon.create(sinon.sandbox); + } + + var sandbox = prepareSandboxFromConfig(config); + sandbox.args = sandbox.args || []; + var prop, value, exposed = sandbox.inject({}); + + if (config.properties) { + for (var i = 0, l = config.properties.length; i < l; i++) { + prop = config.properties[i]; + value = exposed[prop] || prop == "sandbox" && sandbox; + exposeValue(sandbox, config, prop, value); + } + } else { + exposeValue(sandbox, config, "sandbox", value); + } + + return sandbox; + } + }); + + sinon.sandbox.useFakeXMLHttpRequest = sinon.sandbox.useFakeServer; + + if (typeof module == "object" && typeof require == "function") { + module.exports = sinon.sandbox; + } +}()); + +/** + * @depend ../sinon.js + * @depend stub.js + * @depend mock.js + * @depend sandbox.js + */ +/*jslint eqeqeq: false, onevar: false, forin: true, plusplus: false*/ +/*global module, require, sinon*/ +/** + * Test function, sandboxes fakes + * + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + */ + +(function (sinon) { + var commonJSModule = typeof module == "object" && typeof require == "function"; + + if (!sinon && commonJSModule) { + sinon = require("../sinon"); + } + + if (!sinon) { + return; + } + + function test(callback) { + var type = typeof callback; + + if (type != "function") { + throw new TypeError("sinon.test needs to wrap a test function, got " + type); + } + + return function () { + var config = sinon.getConfig(sinon.config); + config.injectInto = config.injectIntoThis && this || config.injectInto; + var sandbox = sinon.sandbox.create(config); + var exception, result; + var args = Array.prototype.slice.call(arguments).concat(sandbox.args); + + try { + result = callback.apply(this, args); + } catch (e) { + exception = e; + } + + if (typeof exception !== "undefined") { + sandbox.restore(); + throw exception; + } + else { + sandbox.verifyAndRestore(); + } + + return result; + }; + } + + test.config = { + injectIntoThis: true, + injectInto: null, + properties: ["spy", "stub", "mock", "clock", "server", "requests"], + useFakeTimers: true, + useFakeServer: true + }; + + if (commonJSModule) { + module.exports = test; + } else { + sinon.test = test; + } +}(typeof sinon == "object" && sinon || null)); + +/** + * @depend ../sinon.js + * @depend test.js + */ +/*jslint eqeqeq: false, onevar: false, eqeqeq: false*/ +/*global module, require, sinon*/ +/** + * Test case, sandboxes all test functions + * + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + */ + +(function (sinon) { + var commonJSModule = typeof module == "object" && typeof require == "function"; + + if (!sinon && commonJSModule) { + sinon = require("../sinon"); + } + + if (!sinon || !Object.prototype.hasOwnProperty) { + return; + } + + function createTest(property, setUp, tearDown) { + return function () { + if (setUp) { + setUp.apply(this, arguments); + } + + var exception, result; + + try { + result = property.apply(this, arguments); + } catch (e) { + exception = e; + } + + if (tearDown) { + tearDown.apply(this, arguments); + } + + if (exception) { + throw exception; + } + + return result; + }; + } + + function testCase(tests, prefix) { + /*jsl:ignore*/ + if (!tests || typeof tests != "object") { + throw new TypeError("sinon.testCase needs an object with test functions"); + } + /*jsl:end*/ + + prefix = prefix || "test"; + var rPrefix = new RegExp("^" + prefix); + var methods = {}, testName, property, method; + var setUp = tests.setUp; + var tearDown = tests.tearDown; + + for (testName in tests) { + if (tests.hasOwnProperty(testName)) { + property = tests[testName]; + + if (/^(setUp|tearDown)$/.test(testName)) { + continue; + } + + if (typeof property == "function" && rPrefix.test(testName)) { + method = property; + + if (setUp || tearDown) { + method = createTest(property, setUp, tearDown); + } + + methods[testName] = sinon.test(method); + } else { + methods[testName] = tests[testName]; + } + } + } + + return methods; + } + + if (commonJSModule) { + module.exports = testCase; + } else { + sinon.testCase = testCase; + } +}(typeof sinon == "object" && sinon || null)); + +/** + * @depend ../sinon.js + * @depend stub.js + */ +/*jslint eqeqeq: false, onevar: false, nomen: false, plusplus: false*/ +/*global module, require, sinon*/ +/** + * Assertions matching the test spy retrieval interface. + * + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + */ + +(function (sinon, global) { + var commonJSModule = typeof module == "object" && typeof require == "function"; + var slice = Array.prototype.slice; + var assert; + + if (!sinon && commonJSModule) { + sinon = require("../sinon"); + } + + if (!sinon) { + return; + } + + function verifyIsStub() { + var method; + + for (var i = 0, l = arguments.length; i < l; ++i) { + method = arguments[i]; + + if (!method) { + assert.fail("fake is not a spy"); + } + + if (typeof method != "function") { + assert.fail(method + " is not a function"); + } + + if (typeof method.getCall != "function") { + assert.fail(method + " is not stubbed"); + } + } + } + + function failAssertion(object, msg) { + object = object || global; + var failMethod = object.fail || assert.fail; + failMethod.call(object, msg); + } + + function mirrorPropAsAssertion(name, method, message) { + if (arguments.length == 2) { + message = method; + method = name; + } + + assert[name] = function (fake) { + verifyIsStub(fake); + + var args = slice.call(arguments, 1); + var failed = false; + + if (typeof method == "function") { + failed = !method(fake); + } else { + failed = typeof fake[method] == "function" ? + !fake[method].apply(fake, args) : !fake[method]; + } + + if (failed) { + failAssertion(this, fake.printf.apply(fake, [message].concat(args))); + } else { + assert.pass(name); + } + }; + } + + function exposedName(prefix, prop) { + return !prefix || /^fail/.test(prop) ? prop : + prefix + prop.slice(0, 1).toUpperCase() + prop.slice(1); + }; + + assert = { + failException: "AssertError", + + fail: function fail(message) { + var error = new Error(message); + error.name = this.failException || assert.failException; + + throw error; + }, + + pass: function pass(assertion) {}, + + callOrder: function assertCallOrder() { + verifyIsStub.apply(null, arguments); + var expected = "", actual = ""; + + if (!sinon.calledInOrder(arguments)) { + try { + expected = [].join.call(arguments, ", "); + var calls = slice.call(arguments); + var i = calls.length; + while (i) { + if (!calls[--i].called) { + calls.splice(i, 1); + } + } + actual = sinon.orderByFirstCall(calls).join(", "); + } catch (e) { + // If this fails, we'll just fall back to the blank string + } + + failAssertion(this, "expected " + expected + " to be " + + "called in order but were called as " + actual); + } else { + assert.pass("callOrder"); + } + }, + + callCount: function assertCallCount(method, count) { + verifyIsStub(method); + + if (method.callCount != count) { + var msg = "expected %n to be called " + sinon.timesInWords(count) + + " but was called %c%C"; + failAssertion(this, method.printf(msg)); + } else { + assert.pass("callCount"); + } + }, + + expose: function expose(target, options) { + if (!target) { + throw new TypeError("target is null or undefined"); + } + + var o = options || {}; + var prefix = typeof o.prefix == "undefined" && "assert" || o.prefix; + var includeFail = typeof o.includeFail == "undefined" || !!o.includeFail; + + for (var method in this) { + if (method != "export" && (includeFail || !/^(fail)/.test(method))) { + target[exposedName(prefix, method)] = this[method]; + } + } + + return target; + } + }; + + mirrorPropAsAssertion("called", "expected %n to have been called at least once but was never called"); + mirrorPropAsAssertion("notCalled", function (spy) { return !spy.called; }, + "expected %n to not have been called but was called %c%C"); + mirrorPropAsAssertion("calledOnce", "expected %n to be called once but was called %c%C"); + mirrorPropAsAssertion("calledTwice", "expected %n to be called twice but was called %c%C"); + mirrorPropAsAssertion("calledThrice", "expected %n to be called thrice but was called %c%C"); + mirrorPropAsAssertion("calledOn", "expected %n to be called with %1 as this but was called with %t"); + mirrorPropAsAssertion("alwaysCalledOn", "expected %n to always be called with %1 as this but was called with %t"); + mirrorPropAsAssertion("calledWithNew", "expected %n to be called with new"); + mirrorPropAsAssertion("alwaysCalledWithNew", "expected %n to always be called with new"); + mirrorPropAsAssertion("calledWith", "expected %n to be called with arguments %*%C"); + mirrorPropAsAssertion("calledWithMatch", "expected %n to be called with match %*%C"); + mirrorPropAsAssertion("alwaysCalledWith", "expected %n to always be called with arguments %*%C"); + mirrorPropAsAssertion("alwaysCalledWithMatch", "expected %n to always be called with match %*%C"); + mirrorPropAsAssertion("calledWithExactly", "expected %n to be called with exact arguments %*%C"); + mirrorPropAsAssertion("alwaysCalledWithExactly", "expected %n to always be called with exact arguments %*%C"); + mirrorPropAsAssertion("neverCalledWith", "expected %n to never be called with arguments %*%C"); + mirrorPropAsAssertion("neverCalledWithMatch", "expected %n to never be called with match %*%C"); + mirrorPropAsAssertion("threw", "%n did not throw exception%C"); + mirrorPropAsAssertion("alwaysThrew", "%n did not always throw exception%C"); + + if (commonJSModule) { + module.exports = assert; + } else { + sinon.assert = assert; + } +}(typeof sinon == "object" && sinon || null, typeof window != "undefined" ? window : (typeof self != "undefined") ? self : global)); + +return sinon;}.call(typeof window != 'undefined' && window || {})); diff --git a/core/js/tests/specHelper.js b/core/js/tests/specHelper.js new file mode 100644 index 0000000000..4a30878df5 --- /dev/null +++ b/core/js/tests/specHelper.js @@ -0,0 +1,89 @@ +/** +* ownCloud +* +* @author Vincent Petry +* @copyright 2014 Vincent Petry +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the License, or any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. If not, see . +* +*/ + +/** + * Simulate the variables that are normally set by PHP code + */ + +// from core/js/config.php +window.TESTING = true; +window.oc_debug = true; +window.datepickerFormatDate = 'MM d, yy'; +window.dayNames = [ + 'Sunday', + 'Monday', + 'Tuesday', + 'Wednesday', + 'Thursday', + 'Friday', + 'Saturday' +]; +window.monthNames = [ + 'January', + 'February', + 'March', + 'April', + 'May', + 'June', + 'July', + 'August', + 'September', + 'October', + 'November', + 'December' +]; +window.firstDay = 0; + +// setup dummy webroots +window.oc_webroot = location.href + '/'; +window.oc_appswebroots = { + "files": window.oc_webroot + '/apps/files/' +}; + +// global setup for all tests +(function setupTests() { + var fakeServer = null; + + beforeEach(function() { + // enforce fake XHR, tests should not depend on the server and + // must use fake responses for expected calls + fakeServer = sinon.fakeServer.create(); + + // return fake translations as they might be requested for many test runs + fakeServer.respondWith(/\/index.php\/core\/ajax\/translations.php$/, [ + 200, { + "Content-Type": "application/json" + }, + '{"data": [], "plural_form": "nplurals=2; plural=(n != 1);"}' + ]); + + // make it globally available, so that other tests can define + // custom responses + window.fakeServer = fakeServer; + }); + + afterEach(function() { + // uncomment this to log requests + // console.log(window.fakeServer.requests); + fakeServer.restore(); + }); +})(); + diff --git a/core/js/tests/specs/coreSpec.js b/core/js/tests/specs/coreSpec.js new file mode 100644 index 0000000000..827669f270 --- /dev/null +++ b/core/js/tests/specs/coreSpec.js @@ -0,0 +1,70 @@ +/** +* ownCloud +* +* @author Vincent Petry +* @copyright 2014 Vincent Petry +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the License, or any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. If not, see . +* +*/ +describe('Core base tests', function() { + describe('Base values', function() { + it('Sets webroots', function() { + expect(OC.webroot).toBeDefined(); + expect(OC.appswebroots).toBeDefined(); + }); + }); + describe('Link functions', function() { + var TESTAPP = 'testapp'; + var TESTAPP_ROOT = OC.webroot + '/appsx/testapp'; + + beforeEach(function() { + OC.appswebroots[TESTAPP] = TESTAPP_ROOT; + }); + afterEach(function() { + // restore original array + delete OC.appswebroots[TESTAPP]; + }); + it('Generates correct links for core apps', function() { + expect(OC.linkTo('core', 'somefile.php')).toEqual(OC.webroot + '/core/somefile.php'); + expect(OC.linkTo('admin', 'somefile.php')).toEqual(OC.webroot + '/admin/somefile.php'); + }); + it('Generates correct links for regular apps', function() { + expect(OC.linkTo(TESTAPP, 'somefile.php')).toEqual(OC.webroot + '/index.php/apps/' + TESTAPP + '/somefile.php'); + }); + it('Generates correct remote links', function() { + expect(OC.linkToRemote('webdav')).toEqual(window.location.protocol + '//' + window.location.host + OC.webroot + '/remote.php/webdav'); + }); + describe('Images', function() { + it('Generates image path with given extension', function() { + var svgSupportStub = sinon.stub(window, 'SVGSupport', function() { return true; }); + expect(OC.imagePath('core', 'somefile.jpg')).toEqual(OC.webroot + '/core/img/somefile.jpg'); + expect(OC.imagePath(TESTAPP, 'somefile.jpg')).toEqual(TESTAPP_ROOT + '/img/somefile.jpg'); + svgSupportStub.restore(); + }); + it('Generates image path with svg extension when svg support exists', function() { + var svgSupportStub = sinon.stub(window, 'SVGSupport', function() { return true; }); + expect(OC.imagePath('core', 'somefile')).toEqual(OC.webroot + '/core/img/somefile.svg'); + expect(OC.imagePath(TESTAPP, 'somefile')).toEqual(TESTAPP_ROOT + '/img/somefile.svg'); + svgSupportStub.restore(); + }); + it('Generates image path with png ext when svg support is not available', function() { + var svgSupportStub = sinon.stub(window, 'SVGSupport', function() { return false; }); + expect(OC.imagePath('core', 'somefile')).toEqual(OC.webroot + '/core/img/somefile.png'); + expect(OC.imagePath(TESTAPP, 'somefile')).toEqual(TESTAPP_ROOT + '/img/somefile.png'); + svgSupportStub.restore(); + }); + }); + }); +}); diff --git a/lib/base.php b/lib/base.php index f30575c7b1..89f72bd897 100644 --- a/lib/base.php +++ b/lib/base.php @@ -293,6 +293,7 @@ class OC { public static function initTemplateEngine() { // Add the stuff we need always + // TODO: read from core/js/core.json OC_Util::addScript("jquery-1.10.0.min"); OC_Util::addScript("jquery-migrate-1.2.1.min"); OC_Util::addScript("jquery-ui-1.10.0.custom"); diff --git a/tests/karma.config.js b/tests/karma.config.js new file mode 100644 index 0000000000..cb2d261a4f --- /dev/null +++ b/tests/karma.config.js @@ -0,0 +1,138 @@ +/** +* ownCloud +* +* @author Vincent Petry +* @copyright 2014 Vincent Petry +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the License, or any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. If not, see . +* +*/ + +/** + * This node module is run by the karma executable to specify its configuration. + * + * The list of files from all needed JavaScript files including the ones from the + * apps to test, and the test specs will be passed as configuration object. + * + * Note that it is possible to test a single app by setting the KARMA_TESTSUITE + * environment variable to the apps name, for example "core" or "files_encryption". + * Multiple apps can be specified by separating them with space. + * + */ +module.exports = function(config) { + + // default apps to test when none is specified (TODO: read from filesystem ?) + var defaultApps = 'core files'; + var appsToTest = process.env.KARMA_TESTSUITE || defaultApps; + + // read core files from core.json, + // these are required by all apps so always need to be loaded + // note that the loading order is important that's why they + // are specified in a separate file + var corePath = 'core/js/'; + var coreFiles = require('../' + corePath + 'core.json').modules; + var testCore = false; + var files = []; + var index; + + // find out what apps to test from appsToTest + appsToTest = appsToTest.split(' '); + index = appsToTest.indexOf('core'); + if (index > -1) { + appsToTest.splice(index, 1); + testCore = true; + } + + // extra test libs + files.push(corePath + 'tests/lib/sinon-1.7.3.js'); + + // core mocks + files.push(corePath + 'tests/specHelper.js'); + + // add core files + for ( var i = 0; i < coreFiles.length; i++ ) { + files.push( corePath + coreFiles[i] ); + } + + // need to test the core app as well ? + if (testCore) { + // core tests + files.push(corePath + 'tests/specs/*.js'); + } + + for ( var i = 0; i < appsToTest.length; i++ ) { + // add app JS + files.push('apps/' + appsToTest[i] + '/js/*.js'); + // add test specs + files.push('apps/' + appsToTest[i] + '/tests/js/*.js'); + } + + config.set({ + + // base path, that will be used to resolve files and exclude + basePath: '..', + + + // frameworks to use + frameworks: ['jasmine'], + + // list of files / patterns to load in the browser + files: files, + + // list of files to exclude + exclude: [ + + ], + + // test results reporter to use + // possible values: 'dots', 'progress', 'junit', 'growl', 'coverage' + reporters: ['dots', 'junit'], + + junitReporter: { + outputFile: 'tests/autotest-results-js.xml' + }, + + // web server port + port: 9876, + + + // enable / disable colors in the output (reporters and logs) + colors: true, + + + // level of logging + // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG + logLevel: config.LOG_INFO, + + // enable / disable watching file and executing tests whenever any file changes + autoWatch: false, + + // Start these browsers, currently available: + // - Chrome + // - ChromeCanary + // - Firefox + // - Opera (has to be installed with `npm install karma-opera-launcher`) + // - Safari (only Mac; has to be installed with `npm install karma-safari-launcher`) + // - PhantomJS + // - IE (only Windows; has to be installed with `npm install karma-ie-launcher`) + browsers: ['PhantomJS'], + + // If browser does not capture in given timeout [ms], kill it + captureTimeout: 60000, + + // Continuous Integration mode + // if true, it capture browsers, run tests and exit + singleRun: false + }); +}; From 4f593f99b60ae5a966548d080482a8ce73e2c3f6 Mon Sep 17 00:00:00 2001 From: raghunayyar Date: Thu, 16 Jan 2014 23:35:30 +0530 Subject: [PATCH 060/181] Removes Bogus classes from previous commits. --- apps/files_trashbin/css/trash.css | 4 +--- apps/files_trashbin/templates/index.php | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/apps/files_trashbin/css/trash.css b/apps/files_trashbin/css/trash.css index b32c2df591..434836a2b8 100644 --- a/apps/files_trashbin/css/trash.css +++ b/apps/files_trashbin/css/trash.css @@ -1,5 +1,3 @@ #fileList td a.file, #fileList td a.file span { cursor: default; -} -.trash-controls { top: 45px; } -.trash-filestable { top: -35px !important; } /* To avoid the clashes with #filestable in files */ \ No newline at end of file +} \ No newline at end of file diff --git a/apps/files_trashbin/templates/index.php b/apps/files_trashbin/templates/index.php index 45851d7f49..f9264d4352 100644 --- a/apps/files_trashbin/templates/index.php +++ b/apps/files_trashbin/templates/index.php @@ -1,4 +1,4 @@ -
    +
    @@ -10,7 +10,7 @@ - +
    From 4726a2021b70f2ee70b4cb8817fd89a8532b848b Mon Sep 17 00:00:00 2001 From: Pellaeon Lin Date: Fri, 17 Jan 2014 17:10:42 +0800 Subject: [PATCH 061/181] Add $freeSpace and $uploadLimit to files_sharing --- apps/files_sharing/public.php | 4 ++++ apps/files_sharing/templates/public.php | 2 ++ 2 files changed, 6 insertions(+) diff --git a/apps/files_sharing/public.php b/apps/files_sharing/public.php index f4042f6524..540f2b004c 100644 --- a/apps/files_sharing/public.php +++ b/apps/files_sharing/public.php @@ -141,6 +141,8 @@ if (isset($path)) { OCP\Util::addScript('files', 'jquery.iframe-transport'); OCP\Util::addScript('files', 'jquery.fileupload'); $maxUploadFilesize=OCP\Util::maxUploadFilesize($path); + $freeSpace=OCP\Util::freeSpace($dir); + $uploadLimit=OCP\Util::uploadLimit(); $tmpl = new OCP\Template('files_sharing', 'public', 'base'); $tmpl->assign('uidOwner', $shareOwner); $tmpl->assign('displayName', \OCP\User::getDisplayName($shareOwner)); @@ -161,6 +163,8 @@ if (isset($path)) { $tmpl->assign('allowPublicUploadEnabled', $allowPublicUploadEnabled); $tmpl->assign('uploadMaxFilesize', $maxUploadFilesize); $tmpl->assign('uploadMaxHumanFilesize', OCP\Util::humanFileSize($maxUploadFilesize)); + $tmpl->assign('freeSpace', $freeSpace); + $tmpl->assign('uploadLimit', $uploadLimit); // PHP upload limit $urlLinkIdentifiers= (isset($token)?'&t='.$token:'') .(isset($_GET['dir'])?'&dir='.$_GET['dir']:'') diff --git a/apps/files_sharing/templates/public.php b/apps/files_sharing/templates/public.php index 1d527dca8e..124b4a1ae9 100644 --- a/apps/files_sharing/templates/public.php +++ b/apps/files_sharing/templates/public.php @@ -34,6 +34,8 @@ + + From ccadab96a686e78e3c9d7234b5c8907b5ae8b47a Mon Sep 17 00:00:00 2001 From: Jan-Christoph Borchardt Date: Fri, 17 Jan 2014 12:51:13 +0100 Subject: [PATCH 062/181] add icons for file list and picture view toggles --- core/img/actions/toggle-filelist.png | Bin 0 -> 208 bytes core/img/actions/toggle-filelist.svg | 135 +++++++++++++++++++++++++++ core/img/actions/toggle-pictures.png | Bin 0 -> 207 bytes core/img/actions/toggle-pictures.svg | 117 +++++++++++++++++++++++ 4 files changed, 252 insertions(+) create mode 100644 core/img/actions/toggle-filelist.png create mode 100644 core/img/actions/toggle-filelist.svg create mode 100644 core/img/actions/toggle-pictures.png create mode 100644 core/img/actions/toggle-pictures.svg diff --git a/core/img/actions/toggle-filelist.png b/core/img/actions/toggle-filelist.png new file mode 100644 index 0000000000000000000000000000000000000000..464ff0fe12643beea9be9432f3ec33136f0da6cd GIT binary patch literal 208 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR412s*bT?q$GojU3lKI>km!f2Inal6zjru0+UtM^~H wvVg5XGxc?=O7f>;!5@6*2%hiwFY%FWcWmKv$)w_&K!X`PUHx3vIVCg!01|>livR!s literal 0 HcmV?d00001 diff --git a/core/img/actions/toggle-filelist.svg b/core/img/actions/toggle-filelist.svg new file mode 100644 index 0000000000..0f75ad8e1c --- /dev/null +++ b/core/img/actions/toggle-filelist.svg @@ -0,0 +1,135 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/core/img/actions/toggle-pictures.png b/core/img/actions/toggle-pictures.png new file mode 100644 index 0000000000000000000000000000000000000000..a8e1bea1918f35c363bec8864c5a3ca1177d4415 GIT binary patch literal 207 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4)%6LrrLwQ()PUxs!jgcV$VMR#6ix@heKZ4TZjW)!oc9^>gTe~DWM4fqNGFD literal 0 HcmV?d00001 diff --git a/core/img/actions/toggle-pictures.svg b/core/img/actions/toggle-pictures.svg new file mode 100644 index 0000000000..9d9077ea6f --- /dev/null +++ b/core/img/actions/toggle-pictures.svg @@ -0,0 +1,117 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + From 1d380a201191c12c7b860b2a80a5db12d6bf781d Mon Sep 17 00:00:00 2001 From: Jan-Christoph Borchardt Date: Fri, 17 Jan 2014 13:27:46 +0100 Subject: [PATCH 063/181] optimize size of toggle icons --- core/img/actions/toggle-filelist.png | Bin 208 -> 195 bytes core/img/actions/toggle-filelist.svg | 142 ++------------------------- core/img/actions/toggle-pictures.png | Bin 207 -> 193 bytes core/img/actions/toggle-pictures.svg | 122 ++--------------------- 4 files changed, 16 insertions(+), 248 deletions(-) diff --git a/core/img/actions/toggle-filelist.png b/core/img/actions/toggle-filelist.png index 464ff0fe12643beea9be9432f3ec33136f0da6cd..45d363f1934f7a40e6a43644be8a4bd2b3f73a17 100644 GIT binary patch delta 121 zcmcb>c$jg5gai{a0|P_ST=7ppin-XyGlYYKCJkL{v`jR%zXxGnm)S{4w^c3)GvJ2y-tPED&gXGsaH(tr?OY?zi?#%TY+Zk>sFQI mPsf5k_|6eL-|=7KBiruS!sn7n#W#UAF?hQAxvX - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - + + + + + + + + + diff --git a/core/img/actions/toggle-pictures.png b/core/img/actions/toggle-pictures.png index a8e1bea1918f35c363bec8864c5a3ca1177d4415..8068d17e30d95532ff0923c9848ebd5cc3c8d8ef 100644 GIT binary patch delta 119 zcmX@lc#v^|gai{a0|P_ST=7ppin-XyGlYYK+pJ7S7=$kGMWGY diff --git a/core/img/actions/toggle-pictures.svg b/core/img/actions/toggle-pictures.svg index 9d9077ea6f..5205c0226d 100644 --- a/core/img/actions/toggle-pictures.svg +++ b/core/img/actions/toggle-pictures.svg @@ -1,117 +1,9 @@ - - - - - image/svg+xml - - - - - - - - - - - - - - - - - + + + + + + + From 3e803b5e366563e384abde0d6e6cb6eb010bf914 Mon Sep 17 00:00:00 2001 From: Jan-Christoph Borchardt Date: Fri, 17 Jan 2014 14:41:05 +0100 Subject: [PATCH 064/181] restrict zooming on mobile devices for the publicly accessible, optimized pages --- core/templates/layout.base.php | 2 +- core/templates/layout.guest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/templates/layout.base.php b/core/templates/layout.base.php index 8cd237deea..bae52a7323 100644 --- a/core/templates/layout.base.php +++ b/core/templates/layout.base.php @@ -11,7 +11,7 @@ getTitle()); ?> - + diff --git a/core/templates/layout.guest.php b/core/templates/layout.guest.php index 47ca5903da..6a96b17b10 100644 --- a/core/templates/layout.guest.php +++ b/core/templates/layout.guest.php @@ -11,7 +11,7 @@ getTitle()); ?> - + From b291fb9cd7e94009aba6023e88c5e970a4aa4e96 Mon Sep 17 00:00:00 2001 From: Jan-Christoph Borchardt Date: Fri, 17 Jan 2014 15:47:26 +0100 Subject: [PATCH 065/181] make sure there's enough room for the file actions --- apps/files/css/files.css | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apps/files/css/files.css b/apps/files/css/files.css index 4beb01a4e6..eb009cf0a1 100644 --- a/apps/files/css/files.css +++ b/apps/files/css/files.css @@ -65,6 +65,14 @@ top: 44px; width: 100%; } +/* make sure there's enough room for the file actions */ +#body-user #filestable { + min-width: 750px; +} +#body-user #controls { + min-width: 600px; +} + #filestable tbody tr { background-color:#fff; height:2.5em; } #filestable tbody tr:hover, tbody tr:active { background-color: rgb(240,240,240); From f0a5007e9a2162d6f9d51ee4abf8791af8c0f886 Mon Sep 17 00:00:00 2001 From: Morris Jobke Date: Fri, 17 Jan 2014 16:29:16 +0100 Subject: [PATCH 066/181] fix input element closing tag --- apps/files/templates/index.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/files/templates/index.php b/apps/files/templates/index.php index a69407805d..5188ca5628 100644 --- a/apps/files/templates/index.php +++ b/apps/files/templates/index.php @@ -32,7 +32,7 @@ - > + />
    @@ -50,7 +50,7 @@
    class="hidden">t('Nothing in here. Upload something!'))?>
    - + From 9edbd142a2100c05fb0a412f33c9ab37c1674160 Mon Sep 17 00:00:00 2001 From: raghunayyar Date: Sat, 18 Jan 2014 00:46:06 +0530 Subject: [PATCH 067/181] Removes Bogus Styles. --- apps/files/css/files.css | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/files/css/files.css b/apps/files/css/files.css index b93cc458dd..16ee2b9bca 100644 --- a/apps/files/css/files.css +++ b/apps/files/css/files.css @@ -115,8 +115,6 @@ table th#headerDate, table td.date { box-sizing: border-box; position: relative; min-width: 176px; - display: block; - height: 51px; } /* Multiselect bar */ From ce0cbbd7bc634927bce0b3b4929d0334cf0fe28f Mon Sep 17 00:00:00 2001 From: Morris Jobke Date: Sat, 18 Jan 2014 14:22:56 +0100 Subject: [PATCH 068/181] remove comment & add space --- core/css/styles.css | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/css/styles.css b/core/css/styles.css index 1fe40f987e..c77e7a99d3 100644 --- a/core/css/styles.css +++ b/core/css/styles.css @@ -229,7 +229,6 @@ input[type="submit"].enabled { -webkit-box-sizing: border-box; box-sizing: border-box; position: fixed; - /*top: 45px;*/ right: 0; left: 0; height: 44px; @@ -265,7 +264,7 @@ input[type="submit"].enabled { top: 45px; } #content-wrapper { - position:absolute; height:100%; width:100%; padding-left:80px;padding-top: 45px; + position:absolute; height:100%; width:100%; padding-left:80px; padding-top: 45px; -moz-box-sizing:border-box; box-sizing:border-box; } #leftcontent, .leftcontent { From fea1cc82e87ec46e3b124dbbee6ab2751dc4759f Mon Sep 17 00:00:00 2001 From: kondou Date: Sat, 18 Jan 2014 17:51:41 +0100 Subject: [PATCH 069/181] Keep the EOF-Newline --- apps/files_trashbin/css/trash.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/files_trashbin/css/trash.css b/apps/files_trashbin/css/trash.css index 434836a2b8..97819f4e80 100644 --- a/apps/files_trashbin/css/trash.css +++ b/apps/files_trashbin/css/trash.css @@ -1,3 +1,3 @@ #fileList td a.file, #fileList td a.file span { cursor: default; -} \ No newline at end of file +} From 80dead5a9fe26e14a8b3621eab9c867a27f994d3 Mon Sep 17 00:00:00 2001 From: Morris Jobke Date: Sat, 18 Jan 2014 22:59:49 +0100 Subject: [PATCH 070/181] fix double call of changeEmailAddress() --- settings/js/personal.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/settings/js/personal.js b/settings/js/personal.js index 010f0fc0a7..576a425ce5 100644 --- a/settings/js/personal.js +++ b/settings/js/personal.js @@ -164,6 +164,11 @@ $(document).ready(function(){ $('#email').keyup(function(){ if ($('#email').val() !== '' ){ + // if this is the enter key changeEmailAddress() is already invoked + // so it doesn't need to be triggered again + if(event.keyCode === 13) { + return; + } if(typeof timeout !== 'undefined'){ clearTimeout(timeout); } From 4ec6debe2b145b0df106c7e5a3f4ed0cf2885957 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Mon, 20 Jan 2014 17:27:03 +0100 Subject: [PATCH 071/181] remove unused variable --- apps/files_sharing/public.php | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/files_sharing/public.php b/apps/files_sharing/public.php index e3d6895543..490cea570b 100644 --- a/apps/files_sharing/public.php +++ b/apps/files_sharing/public.php @@ -159,7 +159,6 @@ if (isset($path)) { if ($linkItem['item_type'] !== 'folder') { $allowPublicUploadEnabled = false; } - $tmpl->assign('allowPublicUploadEnabled', $allowPublicUploadEnabled); $tmpl->assign('uploadMaxFilesize', $maxUploadFilesize); $tmpl->assign('uploadMaxHumanFilesize', OCP\Util::humanFileSize($maxUploadFilesize)); From 955530556550d2e753675142486ee91d5a9ce6fa Mon Sep 17 00:00:00 2001 From: Myles McNamara Date: Mon, 20 Jan 2014 11:58:01 -0500 Subject: [PATCH 072/181] change publicUploadButtonMock to public_upload Changed jQuery selector for public preview to public_upload to correctly show preview --- apps/files/js/files.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/files/js/files.js b/apps/files/js/files.js index fdaa3aa334..12e870f141 100644 --- a/apps/files/js/files.js +++ b/apps/files/js/files.js @@ -717,7 +717,7 @@ Files.lazyLoadPreview = function(path, mime, ready, width, height, etag) { console.warn('Files.lazyLoadPreview(): missing etag argument'); } - if ( $('#publicUploadButtonMock').length ) { + if ( $('#public_upload').length ) { urlSpec.t = $('#dirToken').val(); previewURL = OC.Router.generate('core_ajax_public_preview', urlSpec); } else { From f29bd1cb0b839f81bed0b87ae7900da2b1d0e474 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Tue, 21 Jan 2014 00:57:18 +0100 Subject: [PATCH 073/181] adding code coverage support --- build/package.json | 3 ++- tests/karma.config.js | 13 ++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/build/package.json b/build/package.json index 238ea6881a..c9ed7b96c6 100644 --- a/build/package.json +++ b/build/package.json @@ -13,7 +13,8 @@ "devDependencies": { "karma": "*", "karma-jasmine": "*", - "karma-junit-reporter": "*" + "karma-junit-reporter": "*", + "karma-coverage": "*" }, "engine": "node >= 0.8" } diff --git a/tests/karma.config.js b/tests/karma.config.js index cb2d261a4f..f73ade0f3c 100644 --- a/tests/karma.config.js +++ b/tests/karma.config.js @@ -97,7 +97,7 @@ module.exports = function(config) { // test results reporter to use // possible values: 'dots', 'progress', 'junit', 'growl', 'coverage' - reporters: ['dots', 'junit'], + reporters: ['dots', 'junit', 'coverage'], junitReporter: { outputFile: 'tests/autotest-results-js.xml' @@ -106,6 +106,17 @@ module.exports = function(config) { // web server port port: 9876, + preprocessors: { + 'apps/files/js/*.js': 'coverage' + }, + + coverageReporter: { + dir:'tests/karma-coverage', + reporters: [ + { type: 'html' }, + { type: 'cobertura' } + ] + }, // enable / disable colors in the output (reporters and logs) colors: true, From 0b89a45f11b820d7d40e5f4a3c476d42a0577f58 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Wed, 22 Jan 2014 11:10:23 +0100 Subject: [PATCH 074/181] fix size calculation of getAllVersions() --- apps/files_versions/lib/versions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/files_versions/lib/versions.php b/apps/files_versions/lib/versions.php index 8463bd9482..3dd0c5985e 100644 --- a/apps/files_versions/lib/versions.php +++ b/apps/files_versions/lib/versions.php @@ -402,7 +402,7 @@ class Storage { $result = array(); foreach ($versions as $key => $value) { - $size = $view->filesize($value['path']); + $size = $view->filesize(self::VERSIONS_ROOT.'/'.$value['path'].'.v'.$value['timestamp']); $filename = $value['path']; $result['all'][$key]['version'] = $value['timestamp']; From 8d36ddcf0397facb43ae871ef0fba564e50c92bf Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Wed, 22 Jan 2014 11:10:32 +0100 Subject: [PATCH 075/181] code clean-up --- apps/files_versions/ajax/getVersions.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/files_versions/ajax/getVersions.php b/apps/files_versions/ajax/getVersions.php index df29f40162..4cc1c42889 100644 --- a/apps/files_versions/ajax/getVersions.php +++ b/apps/files_versions/ajax/getVersions.php @@ -5,7 +5,8 @@ $source = $_GET['source']; $start = $_GET['start']; list ($uid, $filename) = OCA\Files_Versions\Storage::getUidAndFilename($source); $count = 5; //show the newest revisions -if( ($versions = OCA\Files_Versions\Storage::getVersions($uid, $filename, $source)) ) { +$versions = OCA\Files_Versions\Storage::getVersions($uid, $filename, $source); +if( $versions ) { $endReached = false; if (count($versions) <= $start+$count) { From a567f74d868df0ad70be18265876169e296ce0d9 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Wed, 22 Jan 2014 11:13:15 +0100 Subject: [PATCH 076/181] fix array order --- apps/files_versions/lib/versions.php | 7 +++---- apps/files_versions/tests/versions.php | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/apps/files_versions/lib/versions.php b/apps/files_versions/lib/versions.php index 3dd0c5985e..328ed4305f 100644 --- a/apps/files_versions/lib/versions.php +++ b/apps/files_versions/lib/versions.php @@ -264,7 +264,7 @@ class Storage { * @param string $uid user id from the owner of the file * @param string $filename file to find versions of, relative to the user files dir * @param string $userFullPath - * @returns array + * @returns array versions newest version first */ public static function getVersions($uid, $filename, $userFullPath = '') { $versions = array(); @@ -397,7 +397,8 @@ class Storage { } } - ksort($versions); + // newest version first + krsort($versions); $result = array(); @@ -428,8 +429,6 @@ class Storage { $size = 0; $toDelete = array(); // versions we want to delete - $versions = array_reverse($versions); // newest version first - $interval = 1; $step = Storage::$max_versions_per_interval[$interval]['step']; if (Storage::$max_versions_per_interval[$interval]['intervalEndsAfter'] == -1) { diff --git a/apps/files_versions/tests/versions.php b/apps/files_versions/tests/versions.php index 713f7796c9..25490aa1a0 100644 --- a/apps/files_versions/tests/versions.php +++ b/apps/files_versions/tests/versions.php @@ -40,7 +40,7 @@ class Test_Files_Versioning extends \PHPUnit_Framework_TestCase { $startTime = 5000000; $testClass = new VersionStorageToTest(); - list($deleted, $size) = $testClass->callProtectedGetExpireList($startTime, array_reverse($versions)); + list($deleted, $size) = $testClass->callProtectedGetExpireList($startTime, $versions); // we should have deleted 16 files each of the size 1 $this->assertEquals($sizeOfAllDeletedFiles, $size); From b578a3359eecb4113044a32fce3878eb94d10e20 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Wed, 22 Jan 2014 13:19:39 +0100 Subject: [PATCH 077/181] revert accidental 3rdparty commit --- 3rdparty | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rdparty b/3rdparty index dbe0025a42..7c2c94c904 160000 --- a/3rdparty +++ b/3rdparty @@ -1 +1 @@ -Subproject commit dbe0025a42773d363513fb2c80106306d5444b48 +Subproject commit 7c2c94c904c2721763e97d5bafd115f863080a60 From eaed786eed41673d2f5129a3711b41d9c7f3d09f Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Wed, 22 Jan 2014 16:54:17 +0100 Subject: [PATCH 078/181] add path relative to the files folder of the currently logged in user to the output of getFolderContent() --- apps/files_sharing/lib/cache.php | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/apps/files_sharing/lib/cache.php b/apps/files_sharing/lib/cache.php index 90440d08f4..425d51113b 100644 --- a/apps/files_sharing/lib/cache.php +++ b/apps/files_sharing/lib/cache.php @@ -127,7 +127,18 @@ class Shared_Cache extends Cache { return $files; } else { if ($cache = $this->getSourceCache($folder)) { - return $cache->getFolderContents($this->files[$folder]); + $sourceFolderContent = $cache->getFolderContents($this->files[$folder]); + foreach ($sourceFolderContent as $key => $c) { + $ownerPathParts = explode('/', \OC_Filesystem::normalizePath($c['path'])); + $userPathParts = explode('/', \OC_Filesystem::normalizePath($folder)); + $usersPath = 'files/Shared/'.$userPathParts[1]; + foreach (array_slice($ownerPathParts, 3) as $part) { + $usersPath .= '/'.$part; + } + $sourceFolderContent[$key]['usersPath'] = $usersPath; + } + + return $sourceFolderContent; } } return false; @@ -260,7 +271,7 @@ class Shared_Cache extends Cache { return $this->searchWithWhere($where, $value); } - + /** * The maximum number of placeholders that can be used in an SQL query. * Value MUST be <= 1000 for oracle: @@ -268,7 +279,7 @@ class Shared_Cache extends Cache { * FIXME we should get this from doctrine as other DBs allow a lot more placeholders */ const MAX_SQL_CHUNK_SIZE = 1000; - + /** * search for files with a custom where clause and value * the $wherevalue will be array_merge()d with the file id chunks @@ -282,16 +293,16 @@ class Shared_Cache extends Cache { $ids = $this->getAll(); $files = array(); - + // divide into chunks $chunks = array_chunk($ids, $chunksize); - + foreach ($chunks as $chunk) { $placeholders = join(',', array_fill(0, count($chunk), '?')); $sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`, `unencrypted_size`, `etag` FROM `*PREFIX*filecache` WHERE ' . $sqlwhere . ' `fileid` IN (' . $placeholders . ')'; - + $stmt = \OC_DB::prepare($sql); $result = $stmt->execute(array_merge(array($wherevalue), $chunk)); From b489d6b0af1577031de017b5b01bd76ed5c871e0 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Wed, 22 Jan 2014 16:55:04 +0100 Subject: [PATCH 079/181] fix infinite loop if folder and subfolder has the same name --- apps/files_encryption/lib/util.php | 52 ++++++++---------------------- 1 file changed, 13 insertions(+), 39 deletions(-) diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 8a5dfabeec..8816d4d649 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -2,9 +2,10 @@ /** * ownCloud * - * @author Sam Tuke, Frank Karlitschek + * @author Sam Tuke, Frank Karlitschek, Bjoern Schiessle * @copyright 2012 Sam Tuke , - * Frank Karlitschek + * Frank Karlitschek , + * Bjoern Schiessle * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE @@ -1360,59 +1361,32 @@ class Util { } } - /** * @brief go recursively through a dir and collect all files and sub files. * @param string $dir relative to the users files folder * @return array with list of files relative to the users files folder */ public function getAllFiles($dir) { - $result = array(); + $dirList = array($dir); - $content = $this->view->getDirectoryContent(\OC\Files\Filesystem::normalizePath( - $this->userFilesDir . '/' . $dir)); - - // handling for re shared folders - $pathSplit = explode('/', $dir); - - foreach ($content as $c) { - - $sharedPart = $pathSplit[sizeof($pathSplit) - 1]; - $targetPathSplit = array_reverse(explode('/', $c['path'])); - - $path = ''; - - // rebuild path - foreach ($targetPathSplit as $pathPart) { - - if ($pathPart !== $sharedPart) { - - $path = '/' . $pathPart . $path; + while ($dirList) { + $dir = array_pop($dirList); + $content = $this->view->getDirectoryContent(\OC\Files\Filesystem::normalizePath( + $this->userFilesDir . '/' . $dir)); + foreach ($content as $c) { + $usersPath = isset($c['usersPath']) ? $c['usersPath'] : $c['path']; + if ($c['type'] === 'dir') { + $dirList[] = substr($usersPath, strlen("files")); } else { - - break; - + $result[] = substr($usersPath, strlen("files")); } - } - $path = $dir . $path; - - if ($c['type'] === 'dir') { - - $result = array_merge($result, $this->getAllFiles($path)); - - } else { - - $result[] = $path; - - } } return $result; - } /** From ade726ad324efb16c65055ce2dd5683c3109c8d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Thu, 23 Jan 2014 01:08:42 +0100 Subject: [PATCH 080/181] focus link text only on click in the input field - closes #6817 --- apps/files_sharing/js/public.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/files_sharing/js/public.js b/apps/files_sharing/js/public.js index 31572f5ccf..d95f6348ac 100644 --- a/apps/files_sharing/js/public.js +++ b/apps/files_sharing/js/public.js @@ -56,6 +56,9 @@ $(document).ready(function() { }; }); - $('#directLink').focus(); + $(document).on('click', '#directLink', function() { + $(this).focus(); + $(this).select(); + }); }); From 6241655df4121619de42ba797ec076d9b6927568 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Thu, 23 Jan 2014 02:15:42 +0100 Subject: [PATCH 081/181] Bring mimetype list into alphabetical order. --- lib/private/mimetypes.list.php | 133 ++++++++++++++++----------------- 1 file changed, 66 insertions(+), 67 deletions(-) diff --git a/lib/private/mimetypes.list.php b/lib/private/mimetypes.list.php index 0822833696..72860d0e64 100644 --- a/lib/private/mimetypes.list.php +++ b/lib/private/mimetypes.list.php @@ -21,93 +21,92 @@ */ /** - * list of mimetypes by extension + * Array mapping file extensions to mimetypes (in alphabetical order). */ - return array( + 'ai' => 'application/illustrator', + 'avi'=>'video/x-msvideo', + 'bash' => 'text/x-shellscript', + 'blend'=>'application/x-blender', + 'cc' => 'text/x-c', + 'cdr' => 'application/coreldraw', + 'cpp' => 'text/x-c++src', 'css'=>'text/css', + 'c' => 'text/x-c', + 'c++' => 'text/x-c++src', + 'doc'=>'application/msword', + 'doc'=>'application/msword', + 'docx'=>'application/msword', + 'docx'=>'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'dv'=>'video/dv', + 'epub' => 'application/epub+zip', + 'exe'=>'application/x-ms-dos-executable', 'flac'=>'audio/flac', 'gif'=>'image/gif', - 'gzip'=>'application/x-gzip', 'gz'=>'application/x-gzip', + 'gzip'=>'application/x-gzip', 'html'=>'text/html', 'htm'=>'text/html', - 'ics'=>'text/calendar', 'ical'=>'text/calendar', + 'ics'=>'text/calendar', + 'impress' => 'text/impress', 'jpeg'=>'image/jpeg', 'jpg'=>'image/jpeg', 'js'=>'application/javascript', + 'keynote'=>'application/x-iwork-keynote-sffkey', + 'kra'=>'application/x-krita', + 'm2t'=>'video/mp2t', + 'm4v'=>'video/mp4', + 'markdown' => 'text/markdown', + 'mdown' => 'text/markdown', + 'md' => 'text/markdown', + 'mdwn' => 'text/markdown', + 'mobi' => 'application/x-mobipocket-ebook', + 'mov'=>'video/quicktime', + 'mp3'=>'audio/mpeg', + 'mp4'=>'video/mp4', + 'mpeg'=>'video/mpeg', + 'mpg'=>'video/mpeg', + 'msi'=>'application/x-msi', + 'numbers'=>'application/x-iwork-numbers-sffnumbers', + 'odg'=>'application/vnd.oasis.opendocument.graphics', + 'odp'=>'application/vnd.oasis.opendocument.presentation', + 'ods'=>'application/vnd.oasis.opendocument.spreadsheet', + 'odt'=>'application/vnd.oasis.opendocument.text', 'oga'=>'audio/ogg', 'ogg'=>'audio/ogg', 'ogv'=>'video/ogg', - 'pdf'=>'application/pdf', - 'png'=>'image/png', - 'svg'=>'image/svg+xml', - 'tar'=>'application/x-tar', - 'tgz'=>'application/x-compressed', - 'tar.gz'=>'application/x-compressed', - 'tif'=>'image/tiff', - 'tiff'=>'image/tiff', - 'txt'=>'text/plain', - 'zip'=>'application/zip', - 'wav'=>'audio/wav', - 'odt'=>'application/vnd.oasis.opendocument.text', - 'ods'=>'application/vnd.oasis.opendocument.spreadsheet', - 'odg'=>'application/vnd.oasis.opendocument.graphics', - 'odp'=>'application/vnd.oasis.opendocument.presentation', 'pages'=>'application/x-iwork-pages-sffpages', - 'numbers'=>'application/x-iwork-numbers-sffnumbers', - 'keynote'=>'application/x-iwork-keynote-sffkey', - 'kra'=>'application/x-krita', - 'mp3'=>'audio/mpeg', - 'doc'=>'application/msword', - 'docx'=>'application/msword', - 'xls'=>'application/msexcel', - 'xlsx'=>'application/msexcel', + 'pdf'=>'application/pdf', 'php'=>'application/x-php', - 'exe'=>'application/x-ms-dos-executable', - 'msi'=>'application/x-msi', 'pl'=>'application/x-pearl', - 'py'=>'application/x-python', - 'blend'=>'application/x-blender', - 'xcf'=>'application/x-gimp', - 'psd'=>'application/x-photoshop', - 'xml'=>'application/xml', - 'avi'=>'video/x-msvideo', - 'dv'=>'video/dv', - 'm2t'=>'video/mp2t', - 'mp4'=>'video/mp4', - 'm4v'=>'video/mp4', - 'mpg'=>'video/mpeg', - 'mpeg'=>'video/mpeg', - 'mov'=>'video/quicktime', - 'webm'=>'video/webm', - 'wmv'=>'video/x-ms-asf', - 'py'=>'text/x-script.python', - 'vcf' => 'text/vcard', - 'vcard' => 'text/vcard', - 'doc'=>'application/msword', - 'docx'=>'application/vnd.openxmlformats-officedocument.wordprocessingml.document', - 'xls'=>'application/msexcel', - 'xlsx'=>'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'png'=>'image/png', 'ppt'=>'application/mspowerpoint', 'pptx'=>'application/vnd.openxmlformats-officedocument.presentationml.presentation', - 'sgf' => 'application/sgf', - 'cdr' => 'application/coreldraw', - 'impress' => 'text/impress', - 'ai' => 'application/illustrator', - 'epub' => 'application/epub+zip', - 'mobi' => 'application/x-mobipocket-ebook', - 'md' => 'text/markdown', - 'markdown' => 'text/markdown', - 'mdown' => 'text/markdown', - 'mdwn' => 'text/markdown', + 'psd'=>'application/x-photoshop', + 'py'=>'application/x-python', + 'py'=>'text/x-script.python', 'reveal' => 'text/reveal', - 'c' => 'text/x-c', - 'cc' => 'text/x-c', - 'cpp' => 'text/x-c++src', - 'c++' => 'text/x-c++src', - 'sh' => 'text/x-shellscript', - 'bash' => 'text/x-shellscript', + 'sgf' => 'application/sgf', 'sh-lib' => 'text/x-shellscript', + 'sh' => 'text/x-shellscript', + 'svg'=>'image/svg+xml', + 'tar'=>'application/x-tar', + 'tar.gz'=>'application/x-compressed', + 'tgz'=>'application/x-compressed', + 'tiff'=>'image/tiff', + 'tif'=>'image/tiff', + 'txt'=>'text/plain', + 'vcard' => 'text/vcard', + 'vcf' => 'text/vcard', + 'wav'=>'audio/wav', + 'webm'=>'video/webm', + 'wmv'=>'video/x-ms-asf', + 'xcf'=>'application/x-gimp', + 'xls'=>'application/msexcel', + 'xls'=>'application/msexcel', + 'xlsx'=>'application/msexcel', + 'xlsx'=>'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'xml'=>'application/xml', + 'zip'=>'application/zip', ); From 689516ebd7a47847938420bf8715469b68fb3535 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Thu, 23 Jan 2014 02:22:46 +0100 Subject: [PATCH 082/181] Remove duplicate mimetypes while keeping previous behaviour. --- lib/private/mimetypes.list.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/lib/private/mimetypes.list.php b/lib/private/mimetypes.list.php index 72860d0e64..9db396e9fd 100644 --- a/lib/private/mimetypes.list.php +++ b/lib/private/mimetypes.list.php @@ -35,8 +35,6 @@ return array( 'c' => 'text/x-c', 'c++' => 'text/x-c++src', 'doc'=>'application/msword', - 'doc'=>'application/msword', - 'docx'=>'application/msword', 'docx'=>'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'dv'=>'video/dv', 'epub' => 'application/epub+zip', @@ -84,7 +82,6 @@ return array( 'ppt'=>'application/mspowerpoint', 'pptx'=>'application/vnd.openxmlformats-officedocument.presentationml.presentation', 'psd'=>'application/x-photoshop', - 'py'=>'application/x-python', 'py'=>'text/x-script.python', 'reveal' => 'text/reveal', 'sgf' => 'application/sgf', @@ -104,8 +101,6 @@ return array( 'wmv'=>'video/x-ms-asf', 'xcf'=>'application/x-gimp', 'xls'=>'application/msexcel', - 'xls'=>'application/msexcel', - 'xlsx'=>'application/msexcel', 'xlsx'=>'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'xml'=>'application/xml', 'zip'=>'application/zip', From 47ea7704ca796a23fc5e9ec8f4a7668d1bbe9446 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Thu, 23 Jan 2014 02:46:05 +0100 Subject: [PATCH 083/181] Fix icons for xml,ppt,dot,dotx files. --- lib/private/helper.php | 2 ++ lib/private/mimetypes.list.php | 2 ++ 2 files changed, 4 insertions(+) diff --git a/lib/private/helper.php b/lib/private/helper.php index 1c8d01c141..90ef704c3c 100644 --- a/lib/private/helper.php +++ b/lib/private/helper.php @@ -161,6 +161,7 @@ class OC_Helper { 'application/vnd.oasis.opendocument.text-template' => 'x-office/document', 'application/vnd.oasis.opendocument.text-web' => 'x-office/document', 'application/vnd.oasis.opendocument.text-master' => 'x-office/document', + 'application/mspowerpoint' => 'x-office/presentation', 'application/vnd.ms-powerpoint' => 'x-office/presentation', 'application/vnd.openxmlformats-officedocument.presentationml.presentation' => 'x-office/presentation', 'application/vnd.openxmlformats-officedocument.presentationml.template' => 'x-office/presentation', @@ -171,6 +172,7 @@ class OC_Helper { 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12' => 'x-office/presentation', 'application/vnd.oasis.opendocument.presentation' => 'x-office/presentation', 'application/vnd.oasis.opendocument.presentation-template' => 'x-office/presentation', + 'application/msexcel' => 'x-office/spreadsheet', 'application/vnd.ms-excel' => 'x-office/spreadsheet', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' => 'x-office/spreadsheet', 'application/vnd.openxmlformats-officedocument.spreadsheetml.template' => 'x-office/spreadsheet', diff --git a/lib/private/mimetypes.list.php b/lib/private/mimetypes.list.php index 9db396e9fd..1ad333b508 100644 --- a/lib/private/mimetypes.list.php +++ b/lib/private/mimetypes.list.php @@ -36,6 +36,8 @@ return array( 'c++' => 'text/x-c++src', 'doc'=>'application/msword', 'docx'=>'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'dot'=>'application/msword', + 'dotx'=>'application/vnd.openxmlformats-officedocument.wordprocessingml.template', 'dv'=>'video/dv', 'epub' => 'application/epub+zip', 'exe'=>'application/x-ms-dos-executable', From 96f194c0f6038444aae4270d2481a2ee1ccd7691 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Thu, 23 Jan 2014 03:06:14 +0100 Subject: [PATCH 084/181] Add icons for mdb and accdb files. --- lib/private/helper.php | 1 + lib/private/mimetypes.list.php | 2 ++ 2 files changed, 3 insertions(+) diff --git a/lib/private/helper.php b/lib/private/helper.php index 90ef704c3c..58bee9c630 100644 --- a/lib/private/helper.php +++ b/lib/private/helper.php @@ -182,6 +182,7 @@ class OC_Helper { 'application/vnd.ms-excel.sheet.binary.macroEnabled.12' => 'x-office/spreadsheet', 'application/vnd.oasis.opendocument.spreadsheet' => 'x-office/spreadsheet', 'application/vnd.oasis.opendocument.spreadsheet-template' => 'x-office/spreadsheet', + 'application/msaccess' => 'database', ); if (isset($alias[$mimetype])) { diff --git a/lib/private/mimetypes.list.php b/lib/private/mimetypes.list.php index 1ad333b508..40fb1d2d97 100644 --- a/lib/private/mimetypes.list.php +++ b/lib/private/mimetypes.list.php @@ -24,6 +24,7 @@ * Array mapping file extensions to mimetypes (in alphabetical order). */ return array( + 'accdb'=>'application/msaccess', 'ai' => 'application/illustrator', 'avi'=>'video/x-msvideo', 'bash' => 'text/x-shellscript', @@ -60,6 +61,7 @@ return array( 'markdown' => 'text/markdown', 'mdown' => 'text/markdown', 'md' => 'text/markdown', + 'mdb'=>'application/msaccess', 'mdwn' => 'text/markdown', 'mobi' => 'application/x-mobipocket-ebook', 'mov'=>'video/quicktime', From 421f24868a8cd5bdf8ef52a96948ddd00a8abbef Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Tue, 19 Nov 2013 23:16:20 +0100 Subject: [PATCH 085/181] Now using SFTP stream wrapper from phpseclib - Upgraded phpseclib to master version (post 0.3.5) - Now using fopen() on sftp URL for both read and write - Fixes #4063 --- .../files_external/3rdparty/phpseclib/AUTHORS | 4 +- .../3rdparty/phpseclib/README.md | 4 +- .../3rdparty/phpseclib/composer.json | 8 + .../phpseclib/phpseclib/Crypt/AES.php | 826 +----- .../phpseclib/phpseclib/Crypt/Base.php | 1989 ++++++++++++++ .../phpseclib/phpseclib/Crypt/Blowfish.php | 678 +++++ .../phpseclib/phpseclib/Crypt/DES.php | 2310 +++++++++-------- .../phpseclib/phpseclib/Crypt/Hash.php | 42 +- .../phpseclib/phpseclib/Crypt/RC2.php | 656 +++++ .../phpseclib/phpseclib/Crypt/RC4.php | 478 ++-- .../phpseclib/phpseclib/Crypt/RSA.php | 224 +- .../phpseclib/phpseclib/Crypt/Random.php | 20 +- .../phpseclib/phpseclib/Crypt/Rijndael.php | 1673 ++++++------ .../phpseclib/phpseclib/Crypt/TripleDES.php | 1012 ++------ .../phpseclib/phpseclib/Crypt/Twofish.php | 924 +++++++ .../phpseclib/phpseclib/File/ANSI.php | 92 +- .../phpseclib/phpseclib/File/ASN1.php | 113 +- .../phpseclib/phpseclib/File/X509.php | 230 +- .../phpseclib/phpseclib/Math/BigInteger.php | 385 +-- .../3rdparty/phpseclib/phpseclib/Net/SCP.php | 362 +++ .../3rdparty/phpseclib/phpseclib/Net/SFTP.php | 802 +++--- .../phpseclib/phpseclib/Net/SFTP/Stream.php | 771 ++++++ .../3rdparty/phpseclib/phpseclib/Net/SSH1.php | 73 +- .../3rdparty/phpseclib/phpseclib/Net/SSH2.php | 1043 ++++++-- apps/files_external/lib/sftp.php | 36 +- 25 files changed, 9867 insertions(+), 4888 deletions(-) create mode 100644 apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/Base.php create mode 100644 apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/Blowfish.php create mode 100755 apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/RC2.php create mode 100644 apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/Twofish.php create mode 100644 apps/files_external/3rdparty/phpseclib/phpseclib/Net/SCP.php create mode 100644 apps/files_external/3rdparty/phpseclib/phpseclib/Net/SFTP/Stream.php diff --git a/apps/files_external/3rdparty/phpseclib/AUTHORS b/apps/files_external/3rdparty/phpseclib/AUTHORS index 7bae8ab94e..e175f9f22c 100644 --- a/apps/files_external/3rdparty/phpseclib/AUTHORS +++ b/apps/files_external/3rdparty/phpseclib/AUTHORS @@ -1,3 +1,5 @@ phpseclib Lead Developer: TerraFrost (Jim Wigginton) -phpseclib Developers: monnerat (Patrick Monnerat) \ No newline at end of file +phpseclib Developers: monnerat (Patrick Monnerat) + bantu (Andreas Fischer) + petrich (Hans-Jürgen Petrich) diff --git a/apps/files_external/3rdparty/phpseclib/README.md b/apps/files_external/3rdparty/phpseclib/README.md index fbd58bd82b..e90b12f4a6 100644 --- a/apps/files_external/3rdparty/phpseclib/README.md +++ b/apps/files_external/3rdparty/phpseclib/README.md @@ -4,9 +4,9 @@ MIT-licensed pure-PHP implementations of an arbitrary-precision integer arithmetic library, fully PKCS#1 (v2.1) compliant RSA, DES, 3DES, RC4, Rijndael, -AES, SSH-1, SSH-2, SFTP, and X.509 +AES, Blowfish, Twofish, SSH-1, SSH-2, SFTP, and X.509 -* [Download (0.3.1)](http://sourceforge.net/projects/phpseclib/files/phpseclib0.3.1.zip/download) +* [Download (0.3.5)](http://sourceforge.net/projects/phpseclib/files/phpseclib0.3.5.zip/download) * [Browse Git](https://github.com/phpseclib/phpseclib) * [Documentation](http://phpseclib.sourceforge.net/) * [Support](http://www.frostjedi.com/phpbb/viewforum.php?f=46) diff --git a/apps/files_external/3rdparty/phpseclib/composer.json b/apps/files_external/3rdparty/phpseclib/composer.json index 11008cd81d..79c92b52e4 100644 --- a/apps/files_external/3rdparty/phpseclib/composer.json +++ b/apps/files_external/3rdparty/phpseclib/composer.json @@ -43,6 +43,14 @@ "File": "phpseclib/", "Math": "phpseclib/", "Net": "phpseclib/" + }, + "files": [ + "phpseclib/Crypt/Random.php" + ] + }, + "extra": { + "branch-alias": { + "dev-master": "0.3-dev" } } } diff --git a/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/AES.php b/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/AES.php index bc05adf67a..81fa2feab6 100644 --- a/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/AES.php +++ b/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/AES.php @@ -4,13 +4,13 @@ /** * Pure-PHP implementation of AES. * - * Uses mcrypt, if available, and an internal implementation, otherwise. + * Uses mcrypt, if available/possible, and an internal implementation, otherwise. * * PHP versions 4 and 5 * * If {@link Crypt_AES::setKeyLength() setKeyLength()} isn't called, it'll be calculated from * {@link Crypt_AES::setKey() setKey()}. ie. if the key is 128-bits, the key length will be 128-bits. If it's 136-bits - * it'll be null-padded to 160-bits and 160 bits will be the key length until {@link Crypt_Rijndael::setKey() setKey()} + * it'll be null-padded to 192-bits and 192 bits will be the key length until {@link Crypt_AES::setKey() setKey()} * is called, again, at which point, it'll be recalculated. * * Since Crypt_AES extends Crypt_Rijndael, some functions are available to be called that, in the context of AES, don't @@ -42,10 +42,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -59,7 +59,6 @@ * @author Jim Wigginton * @copyright MMVIII Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @version $Id: AES.php,v 1.7 2010/02/09 06:10:25 terrafrost Exp $ * @link http://phpseclib.sourceforge.net */ @@ -67,7 +66,7 @@ * Include Crypt_Rijndael */ if (!class_exists('Crypt_Rijndael')) { - require_once 'Rijndael.php'; + require_once('Rijndael.php'); } /**#@+ @@ -82,31 +81,31 @@ if (!class_exists('Crypt_Rijndael')) { * * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29 */ -define('CRYPT_AES_MODE_CTR', -1); +define('CRYPT_AES_MODE_CTR', CRYPT_MODE_CTR); /** * Encrypt / decrypt using the Electronic Code Book mode. * * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29 */ -define('CRYPT_AES_MODE_ECB', 1); +define('CRYPT_AES_MODE_ECB', CRYPT_MODE_ECB); /** * Encrypt / decrypt using the Code Book Chaining mode. * * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29 */ -define('CRYPT_AES_MODE_CBC', 2); +define('CRYPT_AES_MODE_CBC', CRYPT_MODE_CBC); /** * Encrypt / decrypt using the Cipher Feedback mode. * * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29 */ -define('CRYPT_AES_MODE_CFB', 3); +define('CRYPT_AES_MODE_CFB', CRYPT_MODE_CFB); /** * Encrypt / decrypt using the Cipher Feedback mode. * * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29 */ -define('CRYPT_AES_MODE_OFB', 4); +define('CRYPT_AES_MODE_OFB', CRYPT_MODE_OFB); /**#@-*/ /**#@+ @@ -116,11 +115,11 @@ define('CRYPT_AES_MODE_OFB', 4); /** * Toggles the internal implementation */ -define('CRYPT_AES_MODE_INTERNAL', 1); +define('CRYPT_AES_MODE_INTERNAL', CRYPT_MODE_INTERNAL); /** * Toggles the mcrypt implementation */ -define('CRYPT_AES_MODE_MCRYPT', 2); +define('CRYPT_AES_MODE_MCRYPT', CRYPT_MODE_MCRYPT); /**#@-*/ /** @@ -133,195 +132,41 @@ define('CRYPT_AES_MODE_MCRYPT', 2); */ class Crypt_AES extends Crypt_Rijndael { /** - * mcrypt resource for encryption + * The namespace used by the cipher for its constants. * - * The mcrypt resource can be recreated every time something needs to be created or it can be created just once. - * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode. - * - * @see Crypt_AES::encrypt() + * @see Crypt_Base::const_namespace * @var String * @access private */ - var $enmcrypt; - - /** - * mcrypt resource for decryption - * - * The mcrypt resource can be recreated every time something needs to be created or it can be created just once. - * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode. - * - * @see Crypt_AES::decrypt() - * @var String - * @access private - */ - var $demcrypt; - - /** - * mcrypt resource for CFB mode - * - * @see Crypt_AES::encrypt() - * @see Crypt_AES::decrypt() - * @var String - * @access private - */ - var $ecb; - - /** - * The SubByte S-Box - * - * @see Crypt_AES::_encryptBlock() - * @var Array - * @access intern - */ - var $sbox = array( - 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, - 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, - 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, - 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, - 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, - 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, - 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, - 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, - 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, - 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, - 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, - 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, - 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, - 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, - 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, - 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16 - ); - - /** - * The inverse SubByte S-Box - * - * @see Crypt_AES::_decryptBlock() - * @var Array - * @access intern - */ - var $isbox = array( - 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB, - 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, - 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, - 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25, - 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, - 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, - 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06, - 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, - 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, - 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E, - 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, - 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, - 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F, - 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, - 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, - 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D - ); + var $const_namespace = 'AES'; /** * Default Constructor. * - * Determines whether or not the mcrypt extension should be used. $mode should only, at present, be - * CRYPT_AES_MODE_ECB or CRYPT_AES_MODE_CBC. If not explictly set, CRYPT_AES_MODE_CBC will be used. + * Determines whether or not the mcrypt extension should be used. * + * $mode could be: + * + * - CRYPT_AES_MODE_ECB + * + * - CRYPT_AES_MODE_CBC + * + * - CRYPT_AES_MODE_CTR + * + * - CRYPT_AES_MODE_CFB + * + * - CRYPT_AES_MODE_OFB + * + * If not explictly set, CRYPT_AES_MODE_CBC will be used. + * + * @see Crypt_Rijndael::Crypt_Rijndael() + * @see Crypt_Base::Crypt_Base() * @param optional Integer $mode - * @return Crypt_AES * @access public */ function Crypt_AES($mode = CRYPT_AES_MODE_CBC) { - if ( !defined('CRYPT_AES_MODE') ) { - switch (true) { - case extension_loaded('mcrypt') && in_array('rijndael-128', mcrypt_list_algorithms()): - define('CRYPT_AES_MODE', CRYPT_AES_MODE_MCRYPT); - break; - default: - define('CRYPT_AES_MODE', CRYPT_AES_MODE_INTERNAL); - } - } - - switch ( CRYPT_AES_MODE ) { - case CRYPT_AES_MODE_MCRYPT: - switch ($mode) { - case CRYPT_AES_MODE_ECB: - $this->paddable = true; - $this->mode = MCRYPT_MODE_ECB; - break; - case CRYPT_AES_MODE_CTR: - // ctr doesn't have a constant associated with it even though it appears to be fairly widely - // supported. in lieu of knowing just how widely supported it is, i've, for now, opted not to - // include a compatibility layer. the layer has been implemented but, for now, is commented out. - $this->mode = 'ctr'; - //$this->mode = in_array('ctr', mcrypt_list_modes()) ? 'ctr' : CRYPT_AES_MODE_CTR; - break; - case CRYPT_AES_MODE_CFB: - $this->mode = 'ncfb'; - break; - case CRYPT_AES_MODE_OFB: - $this->mode = MCRYPT_MODE_NOFB; - break; - case CRYPT_AES_MODE_CBC: - default: - $this->paddable = true; - $this->mode = MCRYPT_MODE_CBC; - } - - break; - default: - switch ($mode) { - case CRYPT_AES_MODE_ECB: - $this->paddable = true; - $this->mode = CRYPT_RIJNDAEL_MODE_ECB; - break; - case CRYPT_AES_MODE_CTR: - $this->mode = CRYPT_RIJNDAEL_MODE_CTR; - break; - case CRYPT_AES_MODE_CFB: - $this->mode = CRYPT_RIJNDAEL_MODE_CFB; - break; - case CRYPT_AES_MODE_OFB: - $this->mode = CRYPT_RIJNDAEL_MODE_OFB; - break; - case CRYPT_AES_MODE_CBC: - default: - $this->paddable = true; - $this->mode = CRYPT_RIJNDAEL_MODE_CBC; - } - } - - if (CRYPT_AES_MODE == CRYPT_AES_MODE_INTERNAL) { - parent::Crypt_Rijndael($this->mode); - } - } - - /** - * Extended Crypt_Rijndael::_setup() - * - * Optimizing the key schedule arrays ($w, $dw) for _encryptBlock() and _decryptBlock() after Crypt_Rijndael::_setup() - * - * @see Crypt_Rijndael::_setup() - * @access private - */ - function _setup() - { - if (!$this->changed) { - return; - } - - $this->w = $this->dw = array(); - parent::_setup(); - - $this->dw = array_reverse($this->dw); - $w = array_pop($this->w); - $dw = array_pop($this->dw); - foreach ($this->w as $r => $wr) { - foreach ($wr as $c => $wc) { - $w[] = $wc; - $dw[] = $this->dw[$r][$c]; - } - } - $this->w = $w; - $this->dw = $dw; + parent::Crypt_Rijndael($mode); } /** @@ -329,6 +174,7 @@ class Crypt_AES extends Crypt_Rijndael { * * Since Crypt_AES extends Crypt_Rijndael, this function is, technically, available, but it doesn't do anything. * + * @see Crypt_Rijndael::setBlockLength() * @access public * @param Integer $length */ @@ -336,610 +182,6 @@ class Crypt_AES extends Crypt_Rijndael { { return; } - - /** - * Sets the initialization vector. (optional) - * - * SetIV is not required when CRYPT_RIJNDAEL_MODE_ECB is being used. If not explictly set, it'll be assumed - * to be all zero's. - * - * @access public - * @param String $iv - */ - function setIV($iv) - { - parent::setIV($iv); - if ( CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT ) { - $this->changed = true; - } - } - - /** - * Encrypts a message. - * - * $plaintext will be padded with up to 16 additional bytes. Other AES implementations may or may not pad in the - * same manner. Other common approaches to padding and the reasons why it's necessary are discussed in the following - * URL: - * - * {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html} - * - * An alternative to padding is to, separately, send the length of the file. This is what SSH, in fact, does. - * strlen($plaintext) will still need to be a multiple of 16, however, arbitrary values can be added to make it that - * length. - * - * @see Crypt_AES::decrypt() - * @access public - * @param String $plaintext - */ - function encrypt($plaintext) - { - if ( CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT ) { - $this->_mcryptSetup(); - - // re: http://phpseclib.sourceforge.net/cfb-demo.phps - // using mcrypt's default handing of CFB the above would output two different things. using phpseclib's - // rewritten CFB implementation the above outputs the same thing twice. - if ($this->mode == 'ncfb' && $this->continuousBuffer) { - $iv = &$this->encryptIV; - $pos = &$this->enbuffer['pos']; - $len = strlen($plaintext); - $ciphertext = ''; - $i = 0; - if ($pos) { - $orig_pos = $pos; - $max = 16 - $pos; - if ($len >= $max) { - $i = $max; - $len-= $max; - $pos = 0; - } else { - $i = $len; - $pos+= $len; - $len = 0; - } - $ciphertext = substr($iv, $orig_pos) ^ $plaintext; - $iv = substr_replace($iv, $ciphertext, $orig_pos, $i); - $this->enbuffer['enmcrypt_init'] = true; - } - if ($len >= 16) { - if ($this->enbuffer['enmcrypt_init'] === false || $len > 280) { - if ($this->enbuffer['enmcrypt_init'] === true) { - mcrypt_generic_init($this->enmcrypt, $this->key, $iv); - $this->enbuffer['enmcrypt_init'] = false; - } - $ciphertext.= mcrypt_generic($this->enmcrypt, substr($plaintext, $i, $len - $len % 16)); - $iv = substr($ciphertext, -16); - $len%= 16; - } else { - while ($len >= 16) { - $iv = mcrypt_generic($this->ecb, $iv) ^ substr($plaintext, $i, 16); - $ciphertext.= $iv; - $len-= 16; - $i+= 16; - } - } - } - - if ($len) { - $iv = mcrypt_generic($this->ecb, $iv); - $block = $iv ^ substr($plaintext, -$len); - $iv = substr_replace($iv, $block, 0, $len); - $ciphertext.= $block; - $pos = $len; - } - - return $ciphertext; - } - - if ($this->paddable) { - $plaintext = $this->_pad($plaintext); - } - - $ciphertext = mcrypt_generic($this->enmcrypt, $plaintext); - - if (!$this->continuousBuffer) { - mcrypt_generic_init($this->enmcrypt, $this->key, $this->iv); - } - - return $ciphertext; - } - - return parent::encrypt($plaintext); - } - - /** - * Decrypts a message. - * - * If strlen($ciphertext) is not a multiple of 16, null bytes will be added to the end of the string until it is. - * - * @see Crypt_AES::encrypt() - * @access public - * @param String $ciphertext - */ - function decrypt($ciphertext) - { - if ( CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT ) { - $this->_mcryptSetup(); - - if ($this->mode == 'ncfb' && $this->continuousBuffer) { - $iv = &$this->decryptIV; - $pos = &$this->debuffer['pos']; - $len = strlen($ciphertext); - $plaintext = ''; - $i = 0; - if ($pos) { - $orig_pos = $pos; - $max = 16 - $pos; - if ($len >= $max) { - $i = $max; - $len-= $max; - $pos = 0; - } else { - $i = $len; - $pos+= $len; - $len = 0; - } - // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize - $plaintext = substr($iv, $orig_pos) ^ $ciphertext; - $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i); - } - if ($len >= 16) { - $cb = substr($ciphertext, $i, $len - $len % 16); - $plaintext.= mcrypt_generic($this->ecb, $iv . $cb) ^ $cb; - $iv = substr($cb, -16); - $len%= 16; - } - if ($len) { - $iv = mcrypt_generic($this->ecb, $iv); - $plaintext.= $iv ^ substr($ciphertext, -$len); - $iv = substr_replace($iv, substr($ciphertext, -$len), 0, $len); - $pos = $len; - } - - return $plaintext; - } - - if ($this->paddable) { - // we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic : - // "The data is padded with "\0" to make sure the length of the data is n * blocksize." - $ciphertext = str_pad($ciphertext, (strlen($ciphertext) + 15) & 0xFFFFFFF0, chr(0)); - } - - $plaintext = mdecrypt_generic($this->demcrypt, $ciphertext); - - if (!$this->continuousBuffer) { - mcrypt_generic_init($this->demcrypt, $this->key, $this->iv); - } - - return $this->paddable ? $this->_unpad($plaintext) : $plaintext; - } - - return parent::decrypt($ciphertext); - } - - /** - * Setup mcrypt - * - * Validates all the variables. - * - * @access private - */ - function _mcryptSetup() - { - if (!$this->changed) { - return; - } - - if (!$this->explicit_key_length) { - // this just copied from Crypt_Rijndael::_setup() - $length = strlen($this->key) >> 2; - if ($length > 8) { - $length = 8; - } else if ($length < 4) { - $length = 4; - } - $this->Nk = $length; - $this->key_size = $length << 2; - } - - switch ($this->Nk) { - case 4: // 128 - $this->key_size = 16; - break; - case 5: // 160 - case 6: // 192 - $this->key_size = 24; - break; - case 7: // 224 - case 8: // 256 - $this->key_size = 32; - } - - $this->key = str_pad(substr($this->key, 0, $this->key_size), $this->key_size, chr(0)); - $this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($this->iv, 0, 16), 16, chr(0)); - - if (!isset($this->enmcrypt)) { - $mode = $this->mode; - //$mode = $this->mode == CRYPT_AES_MODE_CTR ? MCRYPT_MODE_ECB : $this->mode; - - $this->demcrypt = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', $mode, ''); - $this->enmcrypt = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', $mode, ''); - - if ($mode == 'ncfb') { - $this->ecb = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_ECB, ''); - } - - } // else should mcrypt_generic_deinit be called? - - mcrypt_generic_init($this->demcrypt, $this->key, $this->iv); - mcrypt_generic_init($this->enmcrypt, $this->key, $this->iv); - - if ($this->mode == 'ncfb') { - mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"); - } - - $this->changed = false; - } - - /** - * Encrypts a block - * - * Optimized over Crypt_Rijndael's implementation by means of loop unrolling. - * - * @see Crypt_Rijndael::_encryptBlock() - * @access private - * @param String $in - * @return String - */ - function _encryptBlock($in) - { - $state = unpack('N*', $in); - - $sbox = $this->sbox; - $w = $this->w; - $t0 = $this->t0; - $t1 = $this->t1; - $t2 = $this->t2; - $t3 = $this->t3; - - // addRoundKey - $s0 = $state[1] ^ $w[4]; - $s1 = $state[2] ^ $w[5]; - $s2 = $state[3] ^ $w[6]; - $s3 = $state[4] ^ $w[7]; - - // shiftRows + subWord + mixColumns + addRoundKey - $e0 = $t0[($s0 >> 24) & 0xff] ^ $t1[($s1 >> 16) & 0xff] ^ $t2[($s2 >> 8) & 0xff] ^ $t3[$s3 & 0xff] ^ $w[8]; - $e1 = $t0[($s1 >> 24) & 0xff] ^ $t1[($s2 >> 16) & 0xff] ^ $t2[($s3 >> 8) & 0xff] ^ $t3[$s0 & 0xff] ^ $w[9]; - $e2 = $t0[($s2 >> 24) & 0xff] ^ $t1[($s3 >> 16) & 0xff] ^ $t2[($s0 >> 8) & 0xff] ^ $t3[$s1 & 0xff] ^ $w[10]; - $e3 = $t0[($s3 >> 24) & 0xff] ^ $t1[($s0 >> 16) & 0xff] ^ $t2[($s1 >> 8) & 0xff] ^ $t3[$s2 & 0xff] ^ $w[11]; - - $s0 = $t0[($e0 >> 24) & 0xff] ^ $t1[($e1 >> 16) & 0xff] ^ $t2[($e2 >> 8) & 0xff] ^ $t3[$e3 & 0xff] ^ $w[12]; - $s1 = $t0[($e1 >> 24) & 0xff] ^ $t1[($e2 >> 16) & 0xff] ^ $t2[($e3 >> 8) & 0xff] ^ $t3[$e0 & 0xff] ^ $w[13]; - $s2 = $t0[($e2 >> 24) & 0xff] ^ $t1[($e3 >> 16) & 0xff] ^ $t2[($e0 >> 8) & 0xff] ^ $t3[$e1 & 0xff] ^ $w[14]; - $s3 = $t0[($e3 >> 24) & 0xff] ^ $t1[($e0 >> 16) & 0xff] ^ $t2[($e1 >> 8) & 0xff] ^ $t3[$e2 & 0xff] ^ $w[15]; - - $e0 = $t0[($s0 >> 24) & 0xff] ^ $t1[($s1 >> 16) & 0xff] ^ $t2[($s2 >> 8) & 0xff] ^ $t3[$s3 & 0xff] ^ $w[16]; - $e1 = $t0[($s1 >> 24) & 0xff] ^ $t1[($s2 >> 16) & 0xff] ^ $t2[($s3 >> 8) & 0xff] ^ $t3[$s0 & 0xff] ^ $w[17]; - $e2 = $t0[($s2 >> 24) & 0xff] ^ $t1[($s3 >> 16) & 0xff] ^ $t2[($s0 >> 8) & 0xff] ^ $t3[$s1 & 0xff] ^ $w[18]; - $e3 = $t0[($s3 >> 24) & 0xff] ^ $t1[($s0 >> 16) & 0xff] ^ $t2[($s1 >> 8) & 0xff] ^ $t3[$s2 & 0xff] ^ $w[19]; - - $s0 = $t0[($e0 >> 24) & 0xff] ^ $t1[($e1 >> 16) & 0xff] ^ $t2[($e2 >> 8) & 0xff] ^ $t3[$e3 & 0xff] ^ $w[20]; - $s1 = $t0[($e1 >> 24) & 0xff] ^ $t1[($e2 >> 16) & 0xff] ^ $t2[($e3 >> 8) & 0xff] ^ $t3[$e0 & 0xff] ^ $w[21]; - $s2 = $t0[($e2 >> 24) & 0xff] ^ $t1[($e3 >> 16) & 0xff] ^ $t2[($e0 >> 8) & 0xff] ^ $t3[$e1 & 0xff] ^ $w[22]; - $s3 = $t0[($e3 >> 24) & 0xff] ^ $t1[($e0 >> 16) & 0xff] ^ $t2[($e1 >> 8) & 0xff] ^ $t3[$e2 & 0xff] ^ $w[23]; - - $e0 = $t0[($s0 >> 24) & 0xff] ^ $t1[($s1 >> 16) & 0xff] ^ $t2[($s2 >> 8) & 0xff] ^ $t3[$s3 & 0xff] ^ $w[24]; - $e1 = $t0[($s1 >> 24) & 0xff] ^ $t1[($s2 >> 16) & 0xff] ^ $t2[($s3 >> 8) & 0xff] ^ $t3[$s0 & 0xff] ^ $w[25]; - $e2 = $t0[($s2 >> 24) & 0xff] ^ $t1[($s3 >> 16) & 0xff] ^ $t2[($s0 >> 8) & 0xff] ^ $t3[$s1 & 0xff] ^ $w[26]; - $e3 = $t0[($s3 >> 24) & 0xff] ^ $t1[($s0 >> 16) & 0xff] ^ $t2[($s1 >> 8) & 0xff] ^ $t3[$s2 & 0xff] ^ $w[27]; - - $s0 = $t0[($e0 >> 24) & 0xff] ^ $t1[($e1 >> 16) & 0xff] ^ $t2[($e2 >> 8) & 0xff] ^ $t3[$e3 & 0xff] ^ $w[28]; - $s1 = $t0[($e1 >> 24) & 0xff] ^ $t1[($e2 >> 16) & 0xff] ^ $t2[($e3 >> 8) & 0xff] ^ $t3[$e0 & 0xff] ^ $w[29]; - $s2 = $t0[($e2 >> 24) & 0xff] ^ $t1[($e3 >> 16) & 0xff] ^ $t2[($e0 >> 8) & 0xff] ^ $t3[$e1 & 0xff] ^ $w[30]; - $s3 = $t0[($e3 >> 24) & 0xff] ^ $t1[($e0 >> 16) & 0xff] ^ $t2[($e1 >> 8) & 0xff] ^ $t3[$e2 & 0xff] ^ $w[31]; - - $e0 = $t0[($s0 >> 24) & 0xff] ^ $t1[($s1 >> 16) & 0xff] ^ $t2[($s2 >> 8) & 0xff] ^ $t3[$s3 & 0xff] ^ $w[32]; - $e1 = $t0[($s1 >> 24) & 0xff] ^ $t1[($s2 >> 16) & 0xff] ^ $t2[($s3 >> 8) & 0xff] ^ $t3[$s0 & 0xff] ^ $w[33]; - $e2 = $t0[($s2 >> 24) & 0xff] ^ $t1[($s3 >> 16) & 0xff] ^ $t2[($s0 >> 8) & 0xff] ^ $t3[$s1 & 0xff] ^ $w[34]; - $e3 = $t0[($s3 >> 24) & 0xff] ^ $t1[($s0 >> 16) & 0xff] ^ $t2[($s1 >> 8) & 0xff] ^ $t3[$s2 & 0xff] ^ $w[35]; - - $s0 = $t0[($e0 >> 24) & 0xff] ^ $t1[($e1 >> 16) & 0xff] ^ $t2[($e2 >> 8) & 0xff] ^ $t3[$e3 & 0xff] ^ $w[36]; - $s1 = $t0[($e1 >> 24) & 0xff] ^ $t1[($e2 >> 16) & 0xff] ^ $t2[($e3 >> 8) & 0xff] ^ $t3[$e0 & 0xff] ^ $w[37]; - $s2 = $t0[($e2 >> 24) & 0xff] ^ $t1[($e3 >> 16) & 0xff] ^ $t2[($e0 >> 8) & 0xff] ^ $t3[$e1 & 0xff] ^ $w[38]; - $s3 = $t0[($e3 >> 24) & 0xff] ^ $t1[($e0 >> 16) & 0xff] ^ $t2[($e1 >> 8) & 0xff] ^ $t3[$e2 & 0xff] ^ $w[39]; - - $e0 = $t0[($s0 >> 24) & 0xff] ^ $t1[($s1 >> 16) & 0xff] ^ $t2[($s2 >> 8) & 0xff] ^ $t3[$s3 & 0xff] ^ $w[40]; - $e1 = $t0[($s1 >> 24) & 0xff] ^ $t1[($s2 >> 16) & 0xff] ^ $t2[($s3 >> 8) & 0xff] ^ $t3[$s0 & 0xff] ^ $w[41]; - $e2 = $t0[($s2 >> 24) & 0xff] ^ $t1[($s3 >> 16) & 0xff] ^ $t2[($s0 >> 8) & 0xff] ^ $t3[$s1 & 0xff] ^ $w[42]; - $e3 = $t0[($s3 >> 24) & 0xff] ^ $t1[($s0 >> 16) & 0xff] ^ $t2[($s1 >> 8) & 0xff] ^ $t3[$s2 & 0xff] ^ $w[43]; - - switch ($this->Nr) { - case 10: - break; - - case 14: - $s0 = $t0[($e0 >> 24) & 0xff] ^ $t1[($e1 >> 16) & 0xff] ^ $t2[($e2 >> 8) & 0xff] ^ $t3[$e3 & 0xff] ^ $w[44]; - $s1 = $t0[($e1 >> 24) & 0xff] ^ $t1[($e2 >> 16) & 0xff] ^ $t2[($e3 >> 8) & 0xff] ^ $t3[$e0 & 0xff] ^ $w[45]; - $s2 = $t0[($e2 >> 24) & 0xff] ^ $t1[($e3 >> 16) & 0xff] ^ $t2[($e0 >> 8) & 0xff] ^ $t3[$e1 & 0xff] ^ $w[46]; - $s3 = $t0[($e3 >> 24) & 0xff] ^ $t1[($e0 >> 16) & 0xff] ^ $t2[($e1 >> 8) & 0xff] ^ $t3[$e2 & 0xff] ^ $w[47]; - - $e0 = $t0[($s0 >> 24) & 0xff] ^ $t1[($s1 >> 16) & 0xff] ^ $t2[($s2 >> 8) & 0xff] ^ $t3[$s3 & 0xff] ^ $w[48]; - $e1 = $t0[($s1 >> 24) & 0xff] ^ $t1[($s2 >> 16) & 0xff] ^ $t2[($s3 >> 8) & 0xff] ^ $t3[$s0 & 0xff] ^ $w[49]; - $e2 = $t0[($s2 >> 24) & 0xff] ^ $t1[($s3 >> 16) & 0xff] ^ $t2[($s0 >> 8) & 0xff] ^ $t3[$s1 & 0xff] ^ $w[50]; - $e3 = $t0[($s3 >> 24) & 0xff] ^ $t1[($s0 >> 16) & 0xff] ^ $t2[($s1 >> 8) & 0xff] ^ $t3[$s2 & 0xff] ^ $w[51]; - - $s0 = $t0[($e0 >> 24) & 0xff] ^ $t1[($e1 >> 16) & 0xff] ^ $t2[($e2 >> 8) & 0xff] ^ $t3[$e3 & 0xff] ^ $w[52]; - $s1 = $t0[($e1 >> 24) & 0xff] ^ $t1[($e2 >> 16) & 0xff] ^ $t2[($e3 >> 8) & 0xff] ^ $t3[$e0 & 0xff] ^ $w[53]; - $s2 = $t0[($e2 >> 24) & 0xff] ^ $t1[($e3 >> 16) & 0xff] ^ $t2[($e0 >> 8) & 0xff] ^ $t3[$e1 & 0xff] ^ $w[54]; - $s3 = $t0[($e3 >> 24) & 0xff] ^ $t1[($e0 >> 16) & 0xff] ^ $t2[($e1 >> 8) & 0xff] ^ $t3[$e2 & 0xff] ^ $w[55]; - - $e0 = $t0[($s0 >> 24) & 0xff] ^ $t1[($s1 >> 16) & 0xff] ^ $t2[($s2 >> 8) & 0xff] ^ $t3[$s3 & 0xff] ^ $w[56]; - $e1 = $t0[($s1 >> 24) & 0xff] ^ $t1[($s2 >> 16) & 0xff] ^ $t2[($s3 >> 8) & 0xff] ^ $t3[$s0 & 0xff] ^ $w[57]; - $e2 = $t0[($s2 >> 24) & 0xff] ^ $t1[($s3 >> 16) & 0xff] ^ $t2[($s0 >> 8) & 0xff] ^ $t3[$s1 & 0xff] ^ $w[58]; - $e3 = $t0[($s3 >> 24) & 0xff] ^ $t1[($s0 >> 16) & 0xff] ^ $t2[($s1 >> 8) & 0xff] ^ $t3[$s2 & 0xff] ^ $w[59]; - break; - - case 12: - $s0 = $t0[($e0 >> 24) & 0xff] ^ $t1[($e1 >> 16) & 0xff] ^ $t2[($e2 >> 8) & 0xff] ^ $t3[$e3 & 0xff] ^ $w[44]; - $s1 = $t0[($e1 >> 24) & 0xff] ^ $t1[($e2 >> 16) & 0xff] ^ $t2[($e3 >> 8) & 0xff] ^ $t3[$e0 & 0xff] ^ $w[45]; - $s2 = $t0[($e2 >> 24) & 0xff] ^ $t1[($e3 >> 16) & 0xff] ^ $t2[($e0 >> 8) & 0xff] ^ $t3[$e1 & 0xff] ^ $w[46]; - $s3 = $t0[($e3 >> 24) & 0xff] ^ $t1[($e0 >> 16) & 0xff] ^ $t2[($e1 >> 8) & 0xff] ^ $t3[$e2 & 0xff] ^ $w[47]; - - $e0 = $t0[($s0 >> 24) & 0xff] ^ $t1[($s1 >> 16) & 0xff] ^ $t2[($s2 >> 8) & 0xff] ^ $t3[$s3 & 0xff] ^ $w[48]; - $e1 = $t0[($s1 >> 24) & 0xff] ^ $t1[($s2 >> 16) & 0xff] ^ $t2[($s3 >> 8) & 0xff] ^ $t3[$s0 & 0xff] ^ $w[49]; - $e2 = $t0[($s2 >> 24) & 0xff] ^ $t1[($s3 >> 16) & 0xff] ^ $t2[($s0 >> 8) & 0xff] ^ $t3[$s1 & 0xff] ^ $w[50]; - $e3 = $t0[($s3 >> 24) & 0xff] ^ $t1[($s0 >> 16) & 0xff] ^ $t2[($s1 >> 8) & 0xff] ^ $t3[$s2 & 0xff] ^ $w[51]; - break; - - case 13: - $s0 = $t0[($e0 >> 24) & 0xff] ^ $t1[($e1 >> 16) & 0xff] ^ $t2[($e2 >> 8) & 0xff] ^ $t3[$e3 & 0xff] ^ $w[44]; - $s1 = $t0[($e1 >> 24) & 0xff] ^ $t1[($e2 >> 16) & 0xff] ^ $t2[($e3 >> 8) & 0xff] ^ $t3[$e0 & 0xff] ^ $w[45]; - $s2 = $t0[($e2 >> 24) & 0xff] ^ $t1[($e3 >> 16) & 0xff] ^ $t2[($e0 >> 8) & 0xff] ^ $t3[$e1 & 0xff] ^ $w[46]; - $s3 = $t0[($e3 >> 24) & 0xff] ^ $t1[($e0 >> 16) & 0xff] ^ $t2[($e1 >> 8) & 0xff] ^ $t3[$e2 & 0xff] ^ $w[47]; - - $e0 = $t0[($s0 >> 24) & 0xff] ^ $t1[($s1 >> 16) & 0xff] ^ $t2[($s2 >> 8) & 0xff] ^ $t3[$s3 & 0xff] ^ $w[48]; - $e1 = $t0[($s1 >> 24) & 0xff] ^ $t1[($s2 >> 16) & 0xff] ^ $t2[($s3 >> 8) & 0xff] ^ $t3[$s0 & 0xff] ^ $w[49]; - $e2 = $t0[($s2 >> 24) & 0xff] ^ $t1[($s3 >> 16) & 0xff] ^ $t2[($s0 >> 8) & 0xff] ^ $t3[$s1 & 0xff] ^ $w[50]; - $e3 = $t0[($s3 >> 24) & 0xff] ^ $t1[($s0 >> 16) & 0xff] ^ $t2[($s1 >> 8) & 0xff] ^ $t3[$s2 & 0xff] ^ $w[51]; - - $s0 = $t0[($e0 >> 24) & 0xff] ^ $t1[($e1 >> 16) & 0xff] ^ $t2[($e2 >> 8) & 0xff] ^ $t3[$e3 & 0xff] ^ $w[52]; - $s1 = $t0[($e1 >> 24) & 0xff] ^ $t1[($e2 >> 16) & 0xff] ^ $t2[($e3 >> 8) & 0xff] ^ $t3[$e0 & 0xff] ^ $w[53]; - $s2 = $t0[($e2 >> 24) & 0xff] ^ $t1[($e3 >> 16) & 0xff] ^ $t2[($e0 >> 8) & 0xff] ^ $t3[$e1 & 0xff] ^ $w[54]; - $e3 = $t0[($e3 >> 24) & 0xff] ^ $t1[($e0 >> 16) & 0xff] ^ $t2[($e1 >> 8) & 0xff] ^ $t3[$e2 & 0xff] ^ $w[55]; - // Note: Here we skip $s3 but using $e3 - - $e0 = $s0; - $e1 = $s1; - $e2 = $s2; - // $e3 = $s3; - break; - - default: // 11 - $s0 = $t0[($e0 >> 24) & 0xff] ^ $t1[($e1 >> 16) & 0xff] ^ $t2[($e2 >> 8) & 0xff] ^ $t3[$e3 & 0xff] ^ $w[44]; - $s1 = $t0[($e1 >> 24) & 0xff] ^ $t1[($e2 >> 16) & 0xff] ^ $t2[($e3 >> 8) & 0xff] ^ $t3[$e0 & 0xff] ^ $w[45]; - $s2 = $t0[($e2 >> 24) & 0xff] ^ $t1[($e3 >> 16) & 0xff] ^ $t2[($e0 >> 8) & 0xff] ^ $t3[$e1 & 0xff] ^ $w[46]; - $e3 = $t0[($e3 >> 24) & 0xff] ^ $t1[($e0 >> 16) & 0xff] ^ $t2[($e1 >> 8) & 0xff] ^ $t3[$e2 & 0xff] ^ $w[47]; - // Note: Here we skip $s3 but using $e3 - - $e0 = $s0; - $e1 = $s1; - $e2 = $s2; - // $e3 = $s3; - } - - // subWord - $e0 = $sbox[$e0 & 0xff] | ($sbox[($e0 >> 8) & 0xff] << 8) | ($sbox[($e0 >> 16) & 0xff] << 16) | ($sbox[($e0 >> 24) & 0xff] << 24); - $e1 = $sbox[$e1 & 0xff] | ($sbox[($e1 >> 8) & 0xff] << 8) | ($sbox[($e1 >> 16) & 0xff] << 16) | ($sbox[($e1 >> 24) & 0xff] << 24); - $e2 = $sbox[$e2 & 0xff] | ($sbox[($e2 >> 8) & 0xff] << 8) | ($sbox[($e2 >> 16) & 0xff] << 16) | ($sbox[($e2 >> 24) & 0xff] << 24); - $e3 = $sbox[$e3 & 0xff] | ($sbox[($e3 >> 8) & 0xff] << 8) | ($sbox[($e3 >> 16) & 0xff] << 16) | ($sbox[($e3 >> 24) & 0xff] << 24); - - // shiftRows + addRoundKey - return pack('N*', - ($e0 & 0xFF000000) ^ ($e1 & 0x00FF0000) ^ ($e2 & 0x0000FF00) ^ ($e3 & 0x000000FF) ^ $w[0], - ($e1 & 0xFF000000) ^ ($e2 & 0x00FF0000) ^ ($e3 & 0x0000FF00) ^ ($e0 & 0x000000FF) ^ $w[1], - ($e2 & 0xFF000000) ^ ($e3 & 0x00FF0000) ^ ($e0 & 0x0000FF00) ^ ($e1 & 0x000000FF) ^ $w[2], - ($e3 & 0xFF000000) ^ ($e0 & 0x00FF0000) ^ ($e1 & 0x0000FF00) ^ ($e2 & 0x000000FF) ^ $w[3] - ); - } - - /** - * Decrypts a block - * - * Optimized over Crypt_Rijndael's implementation by means of loop unrolling. - * - * @see Crypt_Rijndael::_decryptBlock() - * @access private - * @param String $in - * @return String - */ - function _decryptBlock($in) - { - $state = unpack('N*', $in); - - $sbox = $this->isbox; - $dw = $this->dw; - $dt0 = $this->dt0; - $dt1 = $this->dt1; - $dt2 = $this->dt2; - $dt3 = $this->dt3; - - // addRoundKey - $s0 = $state[1] ^ $dw[4]; - $s1 = $state[2] ^ $dw[5]; - $s2 = $state[3] ^ $dw[6]; - $s3 = $state[4] ^ $dw[7]; - - // invShiftRows + invSubBytes + invMixColumns + addRoundKey - $e0 = $dt0[($s0 >> 24) & 0xff] ^ $dt1[($s3 >> 16) & 0xff] ^ $dt2[($s2 >> 8) & 0xff] ^ $dt3[$s1 & 0xff] ^ $dw[8]; - $e1 = $dt0[($s1 >> 24) & 0xff] ^ $dt1[($s0 >> 16) & 0xff] ^ $dt2[($s3 >> 8) & 0xff] ^ $dt3[$s2 & 0xff] ^ $dw[9]; - $e2 = $dt0[($s2 >> 24) & 0xff] ^ $dt1[($s1 >> 16) & 0xff] ^ $dt2[($s0 >> 8) & 0xff] ^ $dt3[$s3 & 0xff] ^ $dw[10]; - $e3 = $dt0[($s3 >> 24) & 0xff] ^ $dt1[($s2 >> 16) & 0xff] ^ $dt2[($s1 >> 8) & 0xff] ^ $dt3[$s0 & 0xff] ^ $dw[11]; - - $s0 = $dt0[($e0 >> 24) & 0xff] ^ $dt1[($e3 >> 16) & 0xff] ^ $dt2[($e2 >> 8) & 0xff] ^ $dt3[$e1 & 0xff] ^ $dw[12]; - $s1 = $dt0[($e1 >> 24) & 0xff] ^ $dt1[($e0 >> 16) & 0xff] ^ $dt2[($e3 >> 8) & 0xff] ^ $dt3[$e2 & 0xff] ^ $dw[13]; - $s2 = $dt0[($e2 >> 24) & 0xff] ^ $dt1[($e1 >> 16) & 0xff] ^ $dt2[($e0 >> 8) & 0xff] ^ $dt3[$e3 & 0xff] ^ $dw[14]; - $s3 = $dt0[($e3 >> 24) & 0xff] ^ $dt1[($e2 >> 16) & 0xff] ^ $dt2[($e1 >> 8) & 0xff] ^ $dt3[$e0 & 0xff] ^ $dw[15]; - - $e0 = $dt0[($s0 >> 24) & 0xff] ^ $dt1[($s3 >> 16) & 0xff] ^ $dt2[($s2 >> 8) & 0xff] ^ $dt3[$s1 & 0xff] ^ $dw[16]; - $e1 = $dt0[($s1 >> 24) & 0xff] ^ $dt1[($s0 >> 16) & 0xff] ^ $dt2[($s3 >> 8) & 0xff] ^ $dt3[$s2 & 0xff] ^ $dw[17]; - $e2 = $dt0[($s2 >> 24) & 0xff] ^ $dt1[($s1 >> 16) & 0xff] ^ $dt2[($s0 >> 8) & 0xff] ^ $dt3[$s3 & 0xff] ^ $dw[18]; - $e3 = $dt0[($s3 >> 24) & 0xff] ^ $dt1[($s2 >> 16) & 0xff] ^ $dt2[($s1 >> 8) & 0xff] ^ $dt3[$s0 & 0xff] ^ $dw[19]; - - $s0 = $dt0[($e0 >> 24) & 0xff] ^ $dt1[($e3 >> 16) & 0xff] ^ $dt2[($e2 >> 8) & 0xff] ^ $dt3[$e1 & 0xff] ^ $dw[20]; - $s1 = $dt0[($e1 >> 24) & 0xff] ^ $dt1[($e0 >> 16) & 0xff] ^ $dt2[($e3 >> 8) & 0xff] ^ $dt3[$e2 & 0xff] ^ $dw[21]; - $s2 = $dt0[($e2 >> 24) & 0xff] ^ $dt1[($e1 >> 16) & 0xff] ^ $dt2[($e0 >> 8) & 0xff] ^ $dt3[$e3 & 0xff] ^ $dw[22]; - $s3 = $dt0[($e3 >> 24) & 0xff] ^ $dt1[($e2 >> 16) & 0xff] ^ $dt2[($e1 >> 8) & 0xff] ^ $dt3[$e0 & 0xff] ^ $dw[23]; - - $e0 = $dt0[($s0 >> 24) & 0xff] ^ $dt1[($s3 >> 16) & 0xff] ^ $dt2[($s2 >> 8) & 0xff] ^ $dt3[$s1 & 0xff] ^ $dw[24]; - $e1 = $dt0[($s1 >> 24) & 0xff] ^ $dt1[($s0 >> 16) & 0xff] ^ $dt2[($s3 >> 8) & 0xff] ^ $dt3[$s2 & 0xff] ^ $dw[25]; - $e2 = $dt0[($s2 >> 24) & 0xff] ^ $dt1[($s1 >> 16) & 0xff] ^ $dt2[($s0 >> 8) & 0xff] ^ $dt3[$s3 & 0xff] ^ $dw[26]; - $e3 = $dt0[($s3 >> 24) & 0xff] ^ $dt1[($s2 >> 16) & 0xff] ^ $dt2[($s1 >> 8) & 0xff] ^ $dt3[$s0 & 0xff] ^ $dw[27]; - - $s0 = $dt0[($e0 >> 24) & 0xff] ^ $dt1[($e3 >> 16) & 0xff] ^ $dt2[($e2 >> 8) & 0xff] ^ $dt3[$e1 & 0xff] ^ $dw[28]; - $s1 = $dt0[($e1 >> 24) & 0xff] ^ $dt1[($e0 >> 16) & 0xff] ^ $dt2[($e3 >> 8) & 0xff] ^ $dt3[$e2 & 0xff] ^ $dw[29]; - $s2 = $dt0[($e2 >> 24) & 0xff] ^ $dt1[($e1 >> 16) & 0xff] ^ $dt2[($e0 >> 8) & 0xff] ^ $dt3[$e3 & 0xff] ^ $dw[30]; - $s3 = $dt0[($e3 >> 24) & 0xff] ^ $dt1[($e2 >> 16) & 0xff] ^ $dt2[($e1 >> 8) & 0xff] ^ $dt3[$e0 & 0xff] ^ $dw[31]; - - $e0 = $dt0[($s0 >> 24) & 0xff] ^ $dt1[($s3 >> 16) & 0xff] ^ $dt2[($s2 >> 8) & 0xff] ^ $dt3[$s1 & 0xff] ^ $dw[32]; - $e1 = $dt0[($s1 >> 24) & 0xff] ^ $dt1[($s0 >> 16) & 0xff] ^ $dt2[($s3 >> 8) & 0xff] ^ $dt3[$s2 & 0xff] ^ $dw[33]; - $e2 = $dt0[($s2 >> 24) & 0xff] ^ $dt1[($s1 >> 16) & 0xff] ^ $dt2[($s0 >> 8) & 0xff] ^ $dt3[$s3 & 0xff] ^ $dw[34]; - $e3 = $dt0[($s3 >> 24) & 0xff] ^ $dt1[($s2 >> 16) & 0xff] ^ $dt2[($s1 >> 8) & 0xff] ^ $dt3[$s0 & 0xff] ^ $dw[35]; - - $s0 = $dt0[($e0 >> 24) & 0xff] ^ $dt1[($e3 >> 16) & 0xff] ^ $dt2[($e2 >> 8) & 0xff] ^ $dt3[$e1 & 0xff] ^ $dw[36]; - $s1 = $dt0[($e1 >> 24) & 0xff] ^ $dt1[($e0 >> 16) & 0xff] ^ $dt2[($e3 >> 8) & 0xff] ^ $dt3[$e2 & 0xff] ^ $dw[37]; - $s2 = $dt0[($e2 >> 24) & 0xff] ^ $dt1[($e1 >> 16) & 0xff] ^ $dt2[($e0 >> 8) & 0xff] ^ $dt3[$e3 & 0xff] ^ $dw[38]; - $s3 = $dt0[($e3 >> 24) & 0xff] ^ $dt1[($e2 >> 16) & 0xff] ^ $dt2[($e1 >> 8) & 0xff] ^ $dt3[$e0 & 0xff] ^ $dw[39]; - - $e0 = $dt0[($s0 >> 24) & 0xff] ^ $dt1[($s3 >> 16) & 0xff] ^ $dt2[($s2 >> 8) & 0xff] ^ $dt3[$s1 & 0xff] ^ $dw[40]; - $e1 = $dt0[($s1 >> 24) & 0xff] ^ $dt1[($s0 >> 16) & 0xff] ^ $dt2[($s3 >> 8) & 0xff] ^ $dt3[$s2 & 0xff] ^ $dw[41]; - $e2 = $dt0[($s2 >> 24) & 0xff] ^ $dt1[($s1 >> 16) & 0xff] ^ $dt2[($s0 >> 8) & 0xff] ^ $dt3[$s3 & 0xff] ^ $dw[42]; - $e3 = $dt0[($s3 >> 24) & 0xff] ^ $dt1[($s2 >> 16) & 0xff] ^ $dt2[($s1 >> 8) & 0xff] ^ $dt3[$s0 & 0xff] ^ $dw[43]; - - switch ($this->Nr) { - case 10: - break; - - case 14: - $s0 = $dt0[($e0 >> 24) & 0xff] ^ $dt1[($e3 >> 16) & 0xff] ^ $dt2[($e2 >> 8) & 0xff] ^ $dt3[$e1 & 0xff] ^ $dw[44]; - $s1 = $dt0[($e1 >> 24) & 0xff] ^ $dt1[($e0 >> 16) & 0xff] ^ $dt2[($e3 >> 8) & 0xff] ^ $dt3[$e2 & 0xff] ^ $dw[45]; - $s2 = $dt0[($e2 >> 24) & 0xff] ^ $dt1[($e1 >> 16) & 0xff] ^ $dt2[($e0 >> 8) & 0xff] ^ $dt3[$e3 & 0xff] ^ $dw[46]; - $s3 = $dt0[($e3 >> 24) & 0xff] ^ $dt1[($e2 >> 16) & 0xff] ^ $dt2[($e1 >> 8) & 0xff] ^ $dt3[$e0 & 0xff] ^ $dw[47]; - - $e0 = $dt0[($s0 >> 24) & 0xff] ^ $dt1[($s3 >> 16) & 0xff] ^ $dt2[($s2 >> 8) & 0xff] ^ $dt3[$s1 & 0xff] ^ $dw[48]; - $e1 = $dt0[($s1 >> 24) & 0xff] ^ $dt1[($s0 >> 16) & 0xff] ^ $dt2[($s3 >> 8) & 0xff] ^ $dt3[$s2 & 0xff] ^ $dw[49]; - $e2 = $dt0[($s2 >> 24) & 0xff] ^ $dt1[($s1 >> 16) & 0xff] ^ $dt2[($s0 >> 8) & 0xff] ^ $dt3[$s3 & 0xff] ^ $dw[50]; - $e3 = $dt0[($s3 >> 24) & 0xff] ^ $dt1[($s2 >> 16) & 0xff] ^ $dt2[($s1 >> 8) & 0xff] ^ $dt3[$s0 & 0xff] ^ $dw[51]; - - $s0 = $dt0[($e0 >> 24) & 0xff] ^ $dt1[($e3 >> 16) & 0xff] ^ $dt2[($e2 >> 8) & 0xff] ^ $dt3[$e1 & 0xff] ^ $dw[52]; - $s1 = $dt0[($e1 >> 24) & 0xff] ^ $dt1[($e0 >> 16) & 0xff] ^ $dt2[($e3 >> 8) & 0xff] ^ $dt3[$e2 & 0xff] ^ $dw[53]; - $s2 = $dt0[($e2 >> 24) & 0xff] ^ $dt1[($e1 >> 16) & 0xff] ^ $dt2[($e0 >> 8) & 0xff] ^ $dt3[$e3 & 0xff] ^ $dw[54]; - $s3 = $dt0[($e3 >> 24) & 0xff] ^ $dt1[($e2 >> 16) & 0xff] ^ $dt2[($e1 >> 8) & 0xff] ^ $dt3[$e0 & 0xff] ^ $dw[55]; - - $e0 = $dt0[($s0 >> 24) & 0xff] ^ $dt1[($s3 >> 16) & 0xff] ^ $dt2[($s2 >> 8) & 0xff] ^ $dt3[$s1 & 0xff] ^ $dw[56]; - $e1 = $dt0[($s1 >> 24) & 0xff] ^ $dt1[($s0 >> 16) & 0xff] ^ $dt2[($s3 >> 8) & 0xff] ^ $dt3[$s2 & 0xff] ^ $dw[57]; - $e2 = $dt0[($s2 >> 24) & 0xff] ^ $dt1[($s1 >> 16) & 0xff] ^ $dt2[($s0 >> 8) & 0xff] ^ $dt3[$s3 & 0xff] ^ $dw[58]; - $e3 = $dt0[($s3 >> 24) & 0xff] ^ $dt1[($s2 >> 16) & 0xff] ^ $dt2[($s1 >> 8) & 0xff] ^ $dt3[$s0 & 0xff] ^ $dw[59]; - break; - - case 12: - $s0 = $dt0[($e0 >> 24) & 0xff] ^ $dt1[($e3 >> 16) & 0xff] ^ $dt2[($e2 >> 8) & 0xff] ^ $dt3[$e1 & 0xff] ^ $dw[44]; - $s1 = $dt0[($e1 >> 24) & 0xff] ^ $dt1[($e0 >> 16) & 0xff] ^ $dt2[($e3 >> 8) & 0xff] ^ $dt3[$e2 & 0xff] ^ $dw[45]; - $s2 = $dt0[($e2 >> 24) & 0xff] ^ $dt1[($e1 >> 16) & 0xff] ^ $dt2[($e0 >> 8) & 0xff] ^ $dt3[$e3 & 0xff] ^ $dw[46]; - $s3 = $dt0[($e3 >> 24) & 0xff] ^ $dt1[($e2 >> 16) & 0xff] ^ $dt2[($e1 >> 8) & 0xff] ^ $dt3[$e0 & 0xff] ^ $dw[47]; - - $e0 = $dt0[($s0 >> 24) & 0xff] ^ $dt1[($s3 >> 16) & 0xff] ^ $dt2[($s2 >> 8) & 0xff] ^ $dt3[$s1 & 0xff] ^ $dw[48]; - $e1 = $dt0[($s1 >> 24) & 0xff] ^ $dt1[($s0 >> 16) & 0xff] ^ $dt2[($s3 >> 8) & 0xff] ^ $dt3[$s2 & 0xff] ^ $dw[49]; - $e2 = $dt0[($s2 >> 24) & 0xff] ^ $dt1[($s1 >> 16) & 0xff] ^ $dt2[($s0 >> 8) & 0xff] ^ $dt3[$s3 & 0xff] ^ $dw[50]; - $e3 = $dt0[($s3 >> 24) & 0xff] ^ $dt1[($s2 >> 16) & 0xff] ^ $dt2[($s1 >> 8) & 0xff] ^ $dt3[$s0 & 0xff] ^ $dw[51]; - break; - - case 13: - $s0 = $dt0[($e0 >> 24) & 0xff] ^ $dt1[($e3 >> 16) & 0xff] ^ $dt2[($e2 >> 8) & 0xff] ^ $dt3[$e1 & 0xff] ^ $dw[44]; - $s1 = $dt0[($e1 >> 24) & 0xff] ^ $dt1[($e0 >> 16) & 0xff] ^ $dt2[($e3 >> 8) & 0xff] ^ $dt3[$e2 & 0xff] ^ $dw[45]; - $s2 = $dt0[($e2 >> 24) & 0xff] ^ $dt1[($e1 >> 16) & 0xff] ^ $dt2[($e0 >> 8) & 0xff] ^ $dt3[$e3 & 0xff] ^ $dw[46]; - $s3 = $dt0[($e3 >> 24) & 0xff] ^ $dt1[($e2 >> 16) & 0xff] ^ $dt2[($e1 >> 8) & 0xff] ^ $dt3[$e0 & 0xff] ^ $dw[47]; - - $e0 = $dt0[($s0 >> 24) & 0xff] ^ $dt1[($s3 >> 16) & 0xff] ^ $dt2[($s2 >> 8) & 0xff] ^ $dt3[$s1 & 0xff] ^ $dw[48]; - $e1 = $dt0[($s1 >> 24) & 0xff] ^ $dt1[($s0 >> 16) & 0xff] ^ $dt2[($s3 >> 8) & 0xff] ^ $dt3[$s2 & 0xff] ^ $dw[49]; - $e2 = $dt0[($s2 >> 24) & 0xff] ^ $dt1[($s1 >> 16) & 0xff] ^ $dt2[($s0 >> 8) & 0xff] ^ $dt3[$s3 & 0xff] ^ $dw[50]; - $e3 = $dt0[($s3 >> 24) & 0xff] ^ $dt1[($s2 >> 16) & 0xff] ^ $dt2[($s1 >> 8) & 0xff] ^ $dt3[$s0 & 0xff] ^ $dw[51]; - - $s0 = $dt0[($e0 >> 24) & 0xff] ^ $dt1[($e3 >> 16) & 0xff] ^ $dt2[($e2 >> 8) & 0xff] ^ $dt3[$e1 & 0xff] ^ $dw[52]; - $s1 = $dt0[($e1 >> 24) & 0xff] ^ $dt1[($e0 >> 16) & 0xff] ^ $dt2[($e3 >> 8) & 0xff] ^ $dt3[$e2 & 0xff] ^ $dw[53]; - $s2 = $dt0[($e2 >> 24) & 0xff] ^ $dt1[($e1 >> 16) & 0xff] ^ $dt2[($e0 >> 8) & 0xff] ^ $dt3[$e3 & 0xff] ^ $dw[54]; - $e3 = $dt0[($e3 >> 24) & 0xff] ^ $dt1[($e2 >> 16) & 0xff] ^ $dt2[($e1 >> 8) & 0xff] ^ $dt3[$e0 & 0xff] ^ $dw[55]; - // Note: Here we skip $s3 but using $e3 - - $e0 = $s0; - $e1 = $s1; - $e2 = $s2; - // $e3 = $s3; - break; - - default: // 11 - $s0 = $dt0[($e0 >> 24) & 0xff] ^ $dt1[($e3 >> 16) & 0xff] ^ $dt2[($e2 >> 8) & 0xff] ^ $dt3[$e1 & 0xff] ^ $dw[44]; - $s1 = $dt0[($e1 >> 24) & 0xff] ^ $dt1[($e0 >> 16) & 0xff] ^ $dt2[($e3 >> 8) & 0xff] ^ $dt3[$e2 & 0xff] ^ $dw[45]; - $s2 = $dt0[($e2 >> 24) & 0xff] ^ $dt1[($e1 >> 16) & 0xff] ^ $dt2[($e0 >> 8) & 0xff] ^ $dt3[$e3 & 0xff] ^ $dw[46]; - $e3 = $dt0[($e3 >> 24) & 0xff] ^ $dt1[($e2 >> 16) & 0xff] ^ $dt2[($e1 >> 8) & 0xff] ^ $dt3[$e0 & 0xff] ^ $dw[47]; - // Note: Here we skip $s3 but using $e3 - - $e0 = $s0; - $e1 = $s1; - $e2 = $s2; - // $e3 = $s3; - } - - // invSubWord - $e0 = $sbox[$e0 & 0xff] | ($sbox[($e0 >> 8) & 0xff] << 8) | ($sbox[($e0 >> 16) & 0xff] << 16) | ($sbox[($e0 >> 24) & 0xff] << 24); - $e1 = $sbox[$e1 & 0xff] | ($sbox[($e1 >> 8) & 0xff] << 8) | ($sbox[($e1 >> 16) & 0xff] << 16) | ($sbox[($e1 >> 24) & 0xff] << 24); - $e2 = $sbox[$e2 & 0xff] | ($sbox[($e2 >> 8) & 0xff] << 8) | ($sbox[($e2 >> 16) & 0xff] << 16) | ($sbox[($e2 >> 24) & 0xff] << 24); - $e3 = $sbox[$e3 & 0xff] | ($sbox[($e3 >> 8) & 0xff] << 8) | ($sbox[($e3 >> 16) & 0xff] << 16) | ($sbox[($e3 >> 24) & 0xff] << 24); - - // invShiftRows + addRoundKey - return pack('N*', - ($e0 & 0xFF000000) ^ ($e3 & 0x00FF0000) ^ ($e2 & 0x0000FF00) ^ ($e1 & 0x000000FF) ^ $dw[0], - ($e1 & 0xFF000000) ^ ($e0 & 0x00FF0000) ^ ($e3 & 0x0000FF00) ^ ($e2 & 0x000000FF) ^ $dw[1], - ($e2 & 0xFF000000) ^ ($e1 & 0x00FF0000) ^ ($e0 & 0x0000FF00) ^ ($e3 & 0x000000FF) ^ $dw[2], - ($e3 & 0xFF000000) ^ ($e2 & 0x00FF0000) ^ ($e1 & 0x0000FF00) ^ ($e0 & 0x000000FF) ^ $dw[3] - ); - } - - /** - * Treat consecutive "packets" as if they are a continuous buffer. - * - * The default behavior. - * - * @see Crypt_Rijndael::disableContinuousBuffer() - * @access public - */ - function enableContinuousBuffer() - { - parent::enableContinuousBuffer(); - - if (CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT) { - $this->enbuffer['enmcrypt_init'] = true; - $this->debuffer['demcrypt_init'] = true; - } - } - - /** - * Treat consecutive packets as if they are a discontinuous buffer. - * - * The default behavior. - * - * @see Crypt_Rijndael::enableContinuousBuffer() - * @access public - */ - function disableContinuousBuffer() - { - parent::disableContinuousBuffer(); - - if (CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT) { - mcrypt_generic_init($this->enmcrypt, $this->key, $this->iv); - mcrypt_generic_init($this->demcrypt, $this->key, $this->iv); - } - } } // vim: ts=4:sw=4:et: diff --git a/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/Base.php b/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/Base.php new file mode 100644 index 0000000000..7c650ca729 --- /dev/null +++ b/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/Base.php @@ -0,0 +1,1989 @@ + + * @author Hans-Juergen Petrich + * @copyright MMVII Jim Wigginton + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @version 1.0.1 + * @link http://phpseclib.sourceforge.net + */ + +/**#@+ + * @access public + * @see Crypt_Base::encrypt() + * @see Crypt_Base::decrypt() + */ +/** + * Encrypt / decrypt using the Counter mode. + * + * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29 + */ +define('CRYPT_MODE_CTR', -1); +/** + * Encrypt / decrypt using the Electronic Code Book mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29 + */ +define('CRYPT_MODE_ECB', 1); +/** + * Encrypt / decrypt using the Code Book Chaining mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29 + */ +define('CRYPT_MODE_CBC', 2); +/** + * Encrypt / decrypt using the Cipher Feedback mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29 + */ +define('CRYPT_MODE_CFB', 3); +/** + * Encrypt / decrypt using the Output Feedback mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29 + */ +define('CRYPT_MODE_OFB', 4); +/** + * Encrypt / decrypt using streaming mode. + * + */ +define('CRYPT_MODE_STREAM', 5); +/**#@-*/ + +/**#@+ + * @access private + * @see Crypt_Base::Crypt_Base() + */ +/** + * Base value for the internal implementation $engine switch + */ +define('CRYPT_MODE_INTERNAL', 1); +/** + * Base value for the mcrypt implementation $engine switch + */ +define('CRYPT_MODE_MCRYPT', 2); +/**#@-*/ + +/** + * Base Class for all Crypt_* cipher classes + * + * @author Jim Wigginton + * @author Hans-Juergen Petrich + * @version 1.0.0 + * @access public + * @package Crypt_Base + */ +class Crypt_Base { + /** + * The Encryption Mode + * + * @see Crypt_Base::Crypt_Base() + * @var Integer + * @access private + */ + var $mode; + + /** + * The Block Length of the block cipher + * + * @var Integer + * @access private + */ + var $block_size = 16; + + /** + * The Key + * + * @see Crypt_Base::setKey() + * @var String + * @access private + */ + var $key = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; + + /** + * The Initialization Vector + * + * @see Crypt_Base::setIV() + * @var String + * @access private + */ + var $iv; + + /** + * A "sliding" Initialization Vector + * + * @see Crypt_Base::enableContinuousBuffer() + * @see Crypt_Base::_clearBuffers() + * @var String + * @access private + */ + var $encryptIV; + + /** + * A "sliding" Initialization Vector + * + * @see Crypt_Base::enableContinuousBuffer() + * @see Crypt_Base::_clearBuffers() + * @var String + * @access private + */ + var $decryptIV; + + /** + * Continuous Buffer status + * + * @see Crypt_Base::enableContinuousBuffer() + * @var Boolean + * @access private + */ + var $continuousBuffer = false; + + /** + * Encryption buffer for CTR, OFB and CFB modes + * + * @see Crypt_Base::encrypt() + * @see Crypt_Base::_clearBuffers() + * @var Array + * @access private + */ + var $enbuffer; + + /** + * Decryption buffer for CTR, OFB and CFB modes + * + * @see Crypt_Base::decrypt() + * @see Crypt_Base::_clearBuffers() + * @var Array + * @access private + */ + var $debuffer; + + /** + * mcrypt resource for encryption + * + * The mcrypt resource can be recreated every time something needs to be created or it can be created just once. + * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode. + * + * @see Crypt_Base::encrypt() + * @var Resource + * @access private + */ + var $enmcrypt; + + /** + * mcrypt resource for decryption + * + * The mcrypt resource can be recreated every time something needs to be created or it can be created just once. + * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode. + * + * @see Crypt_Base::decrypt() + * @var Resource + * @access private + */ + var $demcrypt; + + /** + * Does the enmcrypt resource need to be (re)initialized? + * + * @see Crypt_Twofish::setKey() + * @see Crypt_Twofish::setIV() + * @var Boolean + * @access private + */ + var $enchanged = true; + + /** + * Does the demcrypt resource need to be (re)initialized? + * + * @see Crypt_Twofish::setKey() + * @see Crypt_Twofish::setIV() + * @var Boolean + * @access private + */ + var $dechanged = true; + + /** + * mcrypt resource for CFB mode + * + * mcrypt's CFB mode, in (and only in) buffered context, + * is broken, so phpseclib implements the CFB mode by it self, + * even when the mcrypt php extension is available. + * + * In order to do the CFB-mode work (fast) phpseclib + * use a separate ECB-mode mcrypt resource. + * + * @link http://phpseclib.sourceforge.net/cfb-demo.phps + * @see Crypt_Base::encrypt() + * @see Crypt_Base::decrypt() + * @see Crypt_Base::_setupMcrypt() + * @var Resource + * @access private + */ + var $ecb; + + /** + * Optimizing value while CFB-encrypting + * + * Only relevant if $continuousBuffer enabled + * and $engine == CRYPT_MODE_MCRYPT + * + * It's faster to re-init $enmcrypt if + * $buffer bytes > $cfb_init_len than + * using the $ecb resource furthermore. + * + * This value depends of the choosen cipher + * and the time it would be needed for it's + * initialization [by mcrypt_generic_init()] + * which, typically, depends on the complexity + * on its internaly Key-expanding algorithm. + * + * @see Crypt_Base::encrypt() + * @var Integer + * @access private + */ + var $cfb_init_len = 600; + + /** + * Does internal cipher state need to be (re)initialized? + * + * @see setKey() + * @see setIV() + * @see disableContinuousBuffer() + * @var Boolean + * @access private + */ + var $changed = true; + + /** + * Padding status + * + * @see Crypt_Base::enablePadding() + * @var Boolean + * @access private + */ + var $padding = true; + + /** + * Is the mode one that is paddable? + * + * @see Crypt_Base::Crypt_Base() + * @var Boolean + * @access private + */ + var $paddable = false; + + /** + * Holds which crypt engine internaly should be use, + * which will be determined automatically on __construct() + * + * Currently available $engines are: + * - CRYPT_MODE_MCRYPT (fast, php-extension: mcrypt, extension_loaded('mcrypt') required) + * - CRYPT_MODE_INTERNAL (slower, pure php-engine, no php-extension required) + * + * In the pipeline... maybe. But currently not available: + * - CRYPT_MODE_OPENSSL (very fast, php-extension: openssl, extension_loaded('openssl') required) + * + * If possible, CRYPT_MODE_MCRYPT will be used for each cipher. + * Otherwise CRYPT_MODE_INTERNAL + * + * @see Crypt_Base::encrypt() + * @see Crypt_Base::decrypt() + * @var Integer + * @access private + */ + var $engine; + + /** + * The mcrypt specific name of the cipher + * + * Only used if $engine == CRYPT_MODE_MCRYPT + * + * @link http://www.php.net/mcrypt_module_open + * @link http://www.php.net/mcrypt_list_algorithms + * @see Crypt_Base::_setupMcrypt() + * @var String + * @access private + */ + var $cipher_name_mcrypt; + + /** + * The default password key_size used by setPassword() + * + * @see Crypt_Base::setPassword() + * @var Integer + * @access private + */ + var $password_key_size = 32; + + /** + * The default salt used by setPassword() + * + * @see Crypt_Base::setPassword() + * @var String + * @access private + */ + var $password_default_salt = 'phpseclib/salt'; + + /** + * The namespace used by the cipher for its constants. + * + * ie: AES.php is using CRYPT_AES_MODE_* for its constants + * so $const_namespace is AES + * + * DES.php is using CRYPT_DES_MODE_* for its constants + * so $const_namespace is DES... and so on + * + * All CRYPT_<$const_namespace>_MODE_* are aliases of + * the generic CRYPT_MODE_* constants, so both could be used + * for each cipher. + * + * Example: + * $aes = new Crypt_AES(CRYPT_AES_MODE_CFB); // $aes will operate in cfb mode + * $aes = new Crypt_AES(CRYPT_MODE_CFB); // identical + * + * @see Crypt_Base::Crypt_Base() + * @var String + * @access private + */ + var $const_namespace; + + /** + * The name of the performance-optimized callback function + * + * Used by encrypt() / decrypt() + * only if $engine == CRYPT_MODE_INTERNAL + * + * @see Crypt_Base::encrypt() + * @see Crypt_Base::decrypt() + * @see Crypt_Base::_setupInlineCrypt() + * @see Crypt_Base::$use_inline_crypt + * @var Callback + * @access private + */ + var $inline_crypt; + + /** + * Holds whether performance-optimized $inline_crypt() can/should be used. + * + * @see Crypt_Base::encrypt() + * @see Crypt_Base::decrypt() + * @see Crypt_Base::inline_crypt + * @var mixed + * @access private + */ + var $use_inline_crypt; + + /** + * Default Constructor. + * + * Determines whether or not the mcrypt extension should be used. + * + * $mode could be: + * + * - CRYPT_MODE_ECB + * + * - CRYPT_MODE_CBC + * + * - CRYPT_MODE_CTR + * + * - CRYPT_MODE_CFB + * + * - CRYPT_MODE_OFB + * + * (or the alias constants of the choosen cipher, for example for AES: CRYPT_AES_MODE_ECB or CRYPT_AES_MODE_CBC ...) + * + * If not explictly set, CRYPT_MODE_CBC will be used. + * + * @param optional Integer $mode + * @access public + */ + function Crypt_Base($mode = CRYPT_MODE_CBC) + { + $const_crypt_mode = 'CRYPT_' . $this->const_namespace . '_MODE'; + + // Determining the availibility of mcrypt support for the cipher + if (!defined($const_crypt_mode)) { + switch (true) { + case extension_loaded('mcrypt') && in_array($this->cipher_name_mcrypt, mcrypt_list_algorithms()): + define($const_crypt_mode, CRYPT_MODE_MCRYPT); + break; + default: + define($const_crypt_mode, CRYPT_MODE_INTERNAL); + } + } + + // Determining which internal $engine should be used. + // The fastes possible first. + switch (true) { + case empty($this->cipher_name_mcrypt): // The cipher module has no mcrypt-engine support at all so we force CRYPT_MODE_INTERNAL + $this->engine = CRYPT_MODE_INTERNAL; + break; + case constant($const_crypt_mode) == CRYPT_MODE_MCRYPT: + $this->engine = CRYPT_MODE_MCRYPT; + break; + default: + $this->engine = CRYPT_MODE_INTERNAL; + } + + // $mode dependent settings + switch ($mode) { + case CRYPT_MODE_ECB: + $this->paddable = true; + $this->mode = $mode; + break; + case CRYPT_MODE_CTR: + case CRYPT_MODE_CFB: + case CRYPT_MODE_OFB: + case CRYPT_MODE_STREAM: + $this->mode = $mode; + break; + case CRYPT_MODE_CBC: + default: + $this->paddable = true; + $this->mode = CRYPT_MODE_CBC; + } + + // Determining whether inline crypting can be used by the cipher + if ($this->use_inline_crypt !== false && function_exists('create_function')) { + $this->use_inline_crypt = true; + } + } + + /** + * Sets the initialization vector. (optional) + * + * SetIV is not required when CRYPT_MODE_ECB (or ie for AES: CRYPT_AES_MODE_ECB) is being used. If not explictly set, it'll be assumed + * to be all zero's. + * + * Note: Could, but not must, extend by the child Crypt_* class + * + * @access public + * @param String $iv + */ + function setIV($iv) + { + if ($this->mode == CRYPT_MODE_ECB) { + return; + } + + $this->iv = $iv; + $this->changed = true; + } + + /** + * Sets the key. + * + * The min/max length(s) of the key depends on the cipher which is used. + * If the key not fits the length(s) of the cipher it will paded with null bytes + * up to the closest valid key length. If the key is more than max length, + * we trim the excess bits. + * + * If the key is not explicitly set, it'll be assumed to be all null bytes. + * + * Note: Could, but not must, extend by the child Crypt_* class + * + * @access public + * @param String $key + */ + function setKey($key) + { + $this->key = $key; + $this->changed = true; + } + + /** + * Sets the password. + * + * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows: + * {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2}: + * $hash, $salt, $count, $dkLen + * + * Where $hash (default = sha1) currently supports the following hashes: see: Crypt/Hash.php + * + * Note: Could, but not must, extend by the child Crypt_* class + * + * @see Crypt/Hash.php + * @param String $password + * @param optional String $method + * @access public + */ + function setPassword($password, $method = 'pbkdf2') + { + $key = ''; + + switch ($method) { + default: // 'pbkdf2' + $func_args = func_get_args(); + + // Hash function + $hash = isset($func_args[2]) ? $func_args[2] : 'sha1'; + + // WPA and WPA2 use the SSID as the salt + $salt = isset($func_args[3]) ? $func_args[3] : $this->password_default_salt; + + // RFC2898#section-4.2 uses 1,000 iterations by default + // WPA and WPA2 use 4,096. + $count = isset($func_args[4]) ? $func_args[4] : 1000; + + // Keylength + $dkLen = isset($func_args[5]) ? $func_args[5] : $this->password_key_size; + + // Determining if php[>=5.5.0]'s hash_pbkdf2() function avail- and useable + switch (true) { + case !function_exists('hash_pbkdf2'): + case !function_exists('hash_algos'): + case !in_array($hash, hash_algos()): + if (!class_exists('Crypt_Hash')) { + require_once('Crypt/Hash.php'); + } + $i = 1; + while (strlen($key) < $dkLen) { + $hmac = new Crypt_Hash(); + $hmac->setHash($hash); + $hmac->setKey($password); + $f = $u = $hmac->hash($salt . pack('N', $i++)); + for ($j = 2; $j <= $count; ++$j) { + $u = $hmac->hash($u); + $f^= $u; + } + $key.= $f; + } + $key = substr($key, 0, $dkLen); + break; + default: + $key = hash_pbkdf2($hash, $password, $salt, $count, $dkLen, true); + } + } + + $this->setKey($key); + } + + /** + * Encrypts a message. + * + * $plaintext will be padded with additional bytes such that it's length is a multiple of the block size. Other cipher + * implementations may or may not pad in the same manner. Other common approaches to padding and the reasons why it's + * necessary are discussed in the following + * URL: + * + * {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html} + * + * An alternative to padding is to, separately, send the length of the file. This is what SSH, in fact, does. + * strlen($plaintext) will still need to be a multiple of the block size, however, arbitrary values can be added to make it that + * length. + * + * Note: Could, but not must, extend by the child Crypt_* class + * + * @see Crypt_Base::decrypt() + * @access public + * @param String $plaintext + * @return String $cipertext + */ + function encrypt($plaintext) + { + if ($this->engine == CRYPT_MODE_MCRYPT) { + if ($this->changed) { + $this->_setupMcrypt(); + $this->changed = false; + } + if ($this->enchanged) { + mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV); + $this->enchanged = false; + } + + // re: {@link http://phpseclib.sourceforge.net/cfb-demo.phps} + // using mcrypt's default handing of CFB the above would output two different things. using phpseclib's + // rewritten CFB implementation the above outputs the same thing twice. + if ($this->mode == CRYPT_MODE_CFB && $this->continuousBuffer) { + $block_size = $this->block_size; + $iv = &$this->encryptIV; + $pos = &$this->enbuffer['pos']; + $len = strlen($plaintext); + $ciphertext = ''; + $i = 0; + if ($pos) { + $orig_pos = $pos; + $max = $block_size - $pos; + if ($len >= $max) { + $i = $max; + $len-= $max; + $pos = 0; + } else { + $i = $len; + $pos+= $len; + $len = 0; + } + $ciphertext = substr($iv, $orig_pos) ^ $plaintext; + $iv = substr_replace($iv, $ciphertext, $orig_pos, $i); + $this->enbuffer['enmcrypt_init'] = true; + } + if ($len >= $block_size) { + if ($this->enbuffer['enmcrypt_init'] === false || $len > $this->cfb_init_len) { + if ($this->enbuffer['enmcrypt_init'] === true) { + mcrypt_generic_init($this->enmcrypt, $this->key, $iv); + $this->enbuffer['enmcrypt_init'] = false; + } + $ciphertext.= mcrypt_generic($this->enmcrypt, substr($plaintext, $i, $len - $len % $block_size)); + $iv = substr($ciphertext, -$block_size); + $len%= $block_size; + } else { + while ($len >= $block_size) { + $iv = mcrypt_generic($this->ecb, $iv) ^ substr($plaintext, $i, $block_size); + $ciphertext.= $iv; + $len-= $block_size; + $i+= $block_size; + } + } + } + + if ($len) { + $iv = mcrypt_generic($this->ecb, $iv); + $block = $iv ^ substr($plaintext, -$len); + $iv = substr_replace($iv, $block, 0, $len); + $ciphertext.= $block; + $pos = $len; + } + + return $ciphertext; + } + + if ($this->paddable) { + $plaintext = $this->_pad($plaintext); + } + + $ciphertext = mcrypt_generic($this->enmcrypt, $plaintext); + + if (!$this->continuousBuffer) { + mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV); + } + + return $ciphertext; + } + + if ($this->changed) { + $this->_setup(); + $this->changed = false; + } + if ($this->use_inline_crypt) { + $inline = $this->inline_crypt; + return $inline('encrypt', $this, $plaintext); + } + if ($this->paddable) { + $plaintext = $this->_pad($plaintext); + } + + $buffer = &$this->enbuffer; + $block_size = $this->block_size; + $ciphertext = ''; + switch ($this->mode) { + case CRYPT_MODE_ECB: + for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { + $ciphertext.= $this->_encryptBlock(substr($plaintext, $i, $block_size)); + } + break; + case CRYPT_MODE_CBC: + $xor = $this->encryptIV; + for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { + $block = substr($plaintext, $i, $block_size); + $block = $this->_encryptBlock($block ^ $xor); + $xor = $block; + $ciphertext.= $block; + } + if ($this->continuousBuffer) { + $this->encryptIV = $xor; + } + break; + case CRYPT_MODE_CTR: + $xor = $this->encryptIV; + if (strlen($buffer['encrypted'])) { + for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { + $block = substr($plaintext, $i, $block_size); + if (strlen($block) > strlen($buffer['encrypted'])) { + $buffer['encrypted'].= $this->_encryptBlock($this->_generateXor($xor, $block_size)); + } + $key = $this->_stringShift($buffer['encrypted'], $block_size); + $ciphertext.= $block ^ $key; + } + } else { + for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { + $block = substr($plaintext, $i, $block_size); + $key = $this->_encryptBlock($this->_generateXor($xor, $block_size)); + $ciphertext.= $block ^ $key; + } + } + if ($this->continuousBuffer) { + $this->encryptIV = $xor; + if ($start = strlen($plaintext) % $block_size) { + $buffer['encrypted'] = substr($key, $start) . $buffer['encrypted']; + } + } + break; + case CRYPT_MODE_CFB: + // cfb loosely routines inspired by openssl's: + // {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1} + if ($this->continuousBuffer) { + $iv = &$this->encryptIV; + $pos = &$buffer['pos']; + } else { + $iv = $this->encryptIV; + $pos = 0; + } + $len = strlen($plaintext); + $i = 0; + if ($pos) { + $orig_pos = $pos; + $max = $block_size - $pos; + if ($len >= $max) { + $i = $max; + $len-= $max; + $pos = 0; + } else { + $i = $len; + $pos+= $len; + $len = 0; + } + // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize + $ciphertext = substr($iv, $orig_pos) ^ $plaintext; + $iv = substr_replace($iv, $ciphertext, $orig_pos, $i); + } + while ($len >= $block_size) { + $iv = $this->_encryptBlock($iv) ^ substr($plaintext, $i, $block_size); + $ciphertext.= $iv; + $len-= $block_size; + $i+= $block_size; + } + if ($len) { + $iv = $this->_encryptBlock($iv); + $block = $iv ^ substr($plaintext, $i); + $iv = substr_replace($iv, $block, 0, $len); + $ciphertext.= $block; + $pos = $len; + } + break; + case CRYPT_MODE_OFB: + $xor = $this->encryptIV; + if (strlen($buffer['xor'])) { + for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { + $block = substr($plaintext, $i, $block_size); + if (strlen($block) > strlen($buffer['xor'])) { + $xor = $this->_encryptBlock($xor); + $buffer['xor'].= $xor; + } + $key = $this->_stringShift($buffer['xor'], $block_size); + $ciphertext.= $block ^ $key; + } + } else { + for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { + $xor = $this->_encryptBlock($xor); + $ciphertext.= substr($plaintext, $i, $block_size) ^ $xor; + } + $key = $xor; + } + if ($this->continuousBuffer) { + $this->encryptIV = $xor; + if ($start = strlen($plaintext) % $block_size) { + $buffer['xor'] = substr($key, $start) . $buffer['xor']; + } + } + break; + case CRYPT_MODE_STREAM: + $ciphertext = $this->_encryptBlock($plaintext); + break; + } + + return $ciphertext; + } + + /** + * Decrypts a message. + * + * If strlen($ciphertext) is not a multiple of the block size, null bytes will be added to the end of the string until + * it is. + * + * Note: Could, but not must, extend by the child Crypt_* class + * + * @see Crypt_Base::encrypt() + * @access public + * @param String $ciphertext + * @return String $plaintext + */ + function decrypt($ciphertext) + { + if ($this->engine == CRYPT_MODE_MCRYPT) { + $block_size = $this->block_size; + if ($this->changed) { + $this->_setupMcrypt(); + $this->changed = false; + } + if ($this->dechanged) { + mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV); + $this->dechanged = false; + } + + if ($this->mode == CRYPT_MODE_CFB && $this->continuousBuffer) { + $iv = &$this->decryptIV; + $pos = &$this->debuffer['pos']; + $len = strlen($ciphertext); + $plaintext = ''; + $i = 0; + if ($pos) { + $orig_pos = $pos; + $max = $block_size - $pos; + if ($len >= $max) { + $i = $max; + $len-= $max; + $pos = 0; + } else { + $i = $len; + $pos+= $len; + $len = 0; + } + // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize + $plaintext = substr($iv, $orig_pos) ^ $ciphertext; + $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i); + } + if ($len >= $block_size) { + $cb = substr($ciphertext, $i, $len - $len % $block_size); + $plaintext.= mcrypt_generic($this->ecb, $iv . $cb) ^ $cb; + $iv = substr($cb, -$block_size); + $len%= $block_size; + } + if ($len) { + $iv = mcrypt_generic($this->ecb, $iv); + $plaintext.= $iv ^ substr($ciphertext, -$len); + $iv = substr_replace($iv, substr($ciphertext, -$len), 0, $len); + $pos = $len; + } + + return $plaintext; + } + + if ($this->paddable) { + // we pad with chr(0) since that's what mcrypt_generic does. to quote from {@link http://www.php.net/function.mcrypt-generic}: + // "The data is padded with "\0" to make sure the length of the data is n * blocksize." + $ciphertext = str_pad($ciphertext, strlen($ciphertext) + ($block_size - strlen($ciphertext) % $block_size) % $block_size, chr(0)); + } + + $plaintext = mdecrypt_generic($this->demcrypt, $ciphertext); + + if (!$this->continuousBuffer) { + mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV); + } + + return $this->paddable ? $this->_unpad($plaintext) : $plaintext; + } + + if ($this->changed) { + $this->_setup(); + $this->changed = false; + } + if ($this->use_inline_crypt) { + $inline = $this->inline_crypt; + return $inline('decrypt', $this, $ciphertext); + } + + $block_size = $this->block_size; + if ($this->paddable) { + // we pad with chr(0) since that's what mcrypt_generic does [...] + $ciphertext = str_pad($ciphertext, strlen($ciphertext) + ($block_size - strlen($ciphertext) % $block_size) % $block_size, chr(0)); + } + + $buffer = &$this->debuffer; + $plaintext = ''; + switch ($this->mode) { + case CRYPT_MODE_ECB: + for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { + $plaintext.= $this->_decryptBlock(substr($ciphertext, $i, $block_size)); + } + break; + case CRYPT_MODE_CBC: + $xor = $this->decryptIV; + for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { + $block = substr($ciphertext, $i, $block_size); + $plaintext.= $this->_decryptBlock($block) ^ $xor; + $xor = $block; + } + if ($this->continuousBuffer) { + $this->decryptIV = $xor; + } + break; + case CRYPT_MODE_CTR: + $xor = $this->decryptIV; + if (strlen($buffer['ciphertext'])) { + for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { + $block = substr($ciphertext, $i, $block_size); + if (strlen($block) > strlen($buffer['ciphertext'])) { + $buffer['ciphertext'].= $this->_encryptBlock($this->_generateXor($xor, $block_size)); + } + $key = $this->_stringShift($buffer['ciphertext'], $block_size); + $plaintext.= $block ^ $key; + } + } else { + for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { + $block = substr($ciphertext, $i, $block_size); + $key = $this->_encryptBlock($this->_generateXor($xor, $block_size)); + $plaintext.= $block ^ $key; + } + } + if ($this->continuousBuffer) { + $this->decryptIV = $xor; + if ($start = strlen($ciphertext) % $block_size) { + $buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext']; + } + } + break; + case CRYPT_MODE_CFB: + if ($this->continuousBuffer) { + $iv = &$this->decryptIV; + $pos = &$buffer['pos']; + } else { + $iv = $this->decryptIV; + $pos = 0; + } + $len = strlen($ciphertext); + $i = 0; + if ($pos) { + $orig_pos = $pos; + $max = $block_size - $pos; + if ($len >= $max) { + $i = $max; + $len-= $max; + $pos = 0; + } else { + $i = $len; + $pos+= $len; + $len = 0; + } + // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize + $plaintext = substr($iv, $orig_pos) ^ $ciphertext; + $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i); + } + while ($len >= $block_size) { + $iv = $this->_encryptBlock($iv); + $cb = substr($ciphertext, $i, $block_size); + $plaintext.= $iv ^ $cb; + $iv = $cb; + $len-= $block_size; + $i+= $block_size; + } + if ($len) { + $iv = $this->_encryptBlock($iv); + $plaintext.= $iv ^ substr($ciphertext, $i); + $iv = substr_replace($iv, substr($ciphertext, $i), 0, $len); + $pos = $len; + } + break; + case CRYPT_MODE_OFB: + $xor = $this->decryptIV; + if (strlen($buffer['xor'])) { + for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { + $block = substr($ciphertext, $i, $block_size); + if (strlen($block) > strlen($buffer['xor'])) { + $xor = $this->_encryptBlock($xor); + $buffer['xor'].= $xor; + } + $key = $this->_stringShift($buffer['xor'], $block_size); + $plaintext.= $block ^ $key; + } + } else { + for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { + $xor = $this->_encryptBlock($xor); + $plaintext.= substr($ciphertext, $i, $block_size) ^ $xor; + } + $key = $xor; + } + if ($this->continuousBuffer) { + $this->decryptIV = $xor; + if ($start = strlen($ciphertext) % $block_size) { + $buffer['xor'] = substr($key, $start) . $buffer['xor']; + } + } + break; + case CRYPT_MODE_STREAM: + $plaintext = $this->_decryptBlock($ciphertext); + break; + } + return $this->paddable ? $this->_unpad($plaintext) : $plaintext; + } + + /** + * Pad "packets". + * + * Block ciphers working by encrypting between their specified [$this->]block_size at a time + * If you ever need to encrypt or decrypt something that isn't of the proper length, it becomes necessary to + * pad the input so that it is of the proper length. + * + * Padding is enabled by default. Sometimes, however, it is undesirable to pad strings. Such is the case in SSH, + * where "packets" are padded with random bytes before being encrypted. Unpad these packets and you risk stripping + * away characters that shouldn't be stripped away. (SSH knows how many bytes are added because the length is + * transmitted separately) + * + * @see Crypt_Base::disablePadding() + * @access public + */ + function enablePadding() + { + $this->padding = true; + } + + /** + * Do not pad packets. + * + * @see Crypt_Base::enablePadding() + * @access public + */ + function disablePadding() + { + $this->padding = false; + } + + /** + * Treat consecutive "packets" as if they are a continuous buffer. + * + * Say you have a 32-byte plaintext $plaintext. Using the default behavior, the two following code snippets + * will yield different outputs: + * + * + * echo $rijndael->encrypt(substr($plaintext, 0, 16)); + * echo $rijndael->encrypt(substr($plaintext, 16, 16)); + * + * + * echo $rijndael->encrypt($plaintext); + * + * + * The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates + * another, as demonstrated with the following: + * + * + * $rijndael->encrypt(substr($plaintext, 0, 16)); + * echo $rijndael->decrypt($rijndael->encrypt(substr($plaintext, 16, 16))); + * + * + * echo $rijndael->decrypt($rijndael->encrypt(substr($plaintext, 16, 16))); + * + * + * With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different + * outputs. The reason is due to the fact that the initialization vector's change after every encryption / + * decryption round when the continuous buffer is enabled. When it's disabled, they remain constant. + * + * Put another way, when the continuous buffer is enabled, the state of the Crypt_*() object changes after each + * encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that + * continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them), + * however, they are also less intuitive and more likely to cause you problems. + * + * Note: Could, but not must, extend by the child Crypt_* class + * + * @see Crypt_Base::disableContinuousBuffer() + * @access public + */ + function enableContinuousBuffer() + { + if ($this->mode == CRYPT_MODE_ECB) { + return; + } + + $this->continuousBuffer = true; + } + + /** + * Treat consecutive packets as if they are a discontinuous buffer. + * + * The default behavior. + * + * Note: Could, but not must, extend by the child Crypt_* class + * + * @see Crypt_Base::enableContinuousBuffer() + * @access public + */ + function disableContinuousBuffer() + { + if ($this->mode == CRYPT_MODE_ECB) { + return; + } + if (!$this->continuousBuffer) { + return; + } + + $this->continuousBuffer = false; + $this->changed = true; + } + + /** + * Encrypts a block + * + * Note: Must extend by the child Crypt_* class + * + * @access private + * @param String $in + * @return String + */ + function _encryptBlock($in) + { + user_error((version_compare(PHP_VERSION, '5.0.0', '>=') ? __METHOD__ : __FUNCTION__) . '() must extend by class ' . get_class($this), E_USER_ERROR); + } + + /** + * Decrypts a block + * + * Note: Must extend by the child Crypt_* class + * + * @access private + * @param String $in + * @return String + */ + function _decryptBlock($in) + { + user_error((version_compare(PHP_VERSION, '5.0.0', '>=') ? __METHOD__ : __FUNCTION__) . '() must extend by class ' . get_class($this), E_USER_ERROR); + } + + /** + * Setup the key (expansion) + * + * Only used if $engine == CRYPT_MODE_INTERNAL + * + * Note: Must extend by the child Crypt_* class + * + * @see Crypt_Base::_setup() + * @access private + */ + function _setupKey() + { + user_error((version_compare(PHP_VERSION, '5.0.0', '>=') ? __METHOD__ : __FUNCTION__) . '() must extend by class ' . get_class($this), E_USER_ERROR); + } + + /** + * Setup the CRYPT_MODE_INTERNAL $engine + * + * (re)init, if necessary, the internal cipher $engine and flush all $buffers + * Used (only) if $engine == CRYPT_MODE_INTERNAL + * + * _setup() will be called each time if $changed === true + * typically this happens when using one or more of following public methods: + * + * - setKey() + * + * - setIV() + * + * - disableContinuousBuffer() + * + * - First run of encrypt() / decrypt() with no init-settings + * + * Internally: _setup() is called always before(!) en/decryption. + * + * Note: Could, but not must, extend by the child Crypt_* class + * + * @see setKey() + * @see setIV() + * @see disableContinuousBuffer() + * @access private + */ + function _setup() + { + $this->_clearBuffers(); + $this->_setupKey(); + + if ($this->use_inline_crypt) { + $this->_setupInlineCrypt(); + } + } + + /** + * Setup the CRYPT_MODE_MCRYPT $engine + * + * (re)init, if necessary, the (ext)mcrypt resources and flush all $buffers + * Used (only) if $engine = CRYPT_MODE_MCRYPT + * + * _setupMcrypt() will be called each time if $changed === true + * typically this happens when using one or more of following public methods: + * + * - setKey() + * + * - setIV() + * + * - disableContinuousBuffer() + * + * - First run of encrypt() / decrypt() + * + * + * Note: Could, but not must, extend by the child Crypt_* class + * + * @see setKey() + * @see setIV() + * @see disableContinuousBuffer() + * @access private + */ + function _setupMcrypt() + { + $this->_clearBuffers(); + $this->enchanged = $this->dechanged = true; + + if (!isset($this->enmcrypt)) { + static $mcrypt_modes = array( + CRYPT_MODE_CTR => 'ctr', + CRYPT_MODE_ECB => MCRYPT_MODE_ECB, + CRYPT_MODE_CBC => MCRYPT_MODE_CBC, + CRYPT_MODE_CFB => 'ncfb', + CRYPT_MODE_OFB => MCRYPT_MODE_NOFB, + CRYPT_MODE_STREAM => MCRYPT_MODE_STREAM, + ); + + $this->demcrypt = mcrypt_module_open($this->cipher_name_mcrypt, '', $mcrypt_modes[$this->mode], ''); + $this->enmcrypt = mcrypt_module_open($this->cipher_name_mcrypt, '', $mcrypt_modes[$this->mode], ''); + + // we need the $ecb mcrypt resource (only) in MODE_CFB with enableContinuousBuffer() + // to workaround mcrypt's broken ncfb implementation in buffered mode + // see: {@link http://phpseclib.sourceforge.net/cfb-demo.phps} + if ($this->mode == CRYPT_MODE_CFB) { + $this->ecb = mcrypt_module_open($this->cipher_name_mcrypt, '', MCRYPT_MODE_ECB, ''); + } + + } // else should mcrypt_generic_deinit be called? + + if ($this->mode == CRYPT_MODE_CFB) { + mcrypt_generic_init($this->ecb, $this->key, str_repeat("\0", $this->block_size)); + } + } + + /** + * Pads a string + * + * Pads a string using the RSA PKCS padding standards so that its length is a multiple of the blocksize. + * $this->block_size - (strlen($text) % $this->block_size) bytes are added, each of which is equal to + * chr($this->block_size - (strlen($text) % $this->block_size) + * + * If padding is disabled and $text is not a multiple of the blocksize, the string will be padded regardless + * and padding will, hence forth, be enabled. + * + * @see Crypt_Base::_unpad() + * @param String $text + * @access private + * @return String + */ + function _pad($text) + { + $length = strlen($text); + + if (!$this->padding) { + if ($length % $this->block_size == 0) { + return $text; + } else { + user_error("The plaintext's length ($length) is not a multiple of the block size ({$this->block_size})"); + $this->padding = true; + } + } + + $pad = $this->block_size - ($length % $this->block_size); + + return str_pad($text, $length + $pad, chr($pad)); + } + + /** + * Unpads a string. + * + * If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong + * and false will be returned. + * + * @see Crypt_Base::_pad() + * @param String $text + * @access private + * @return String + */ + function _unpad($text) + { + if (!$this->padding) { + return $text; + } + + $length = ord($text[strlen($text) - 1]); + + if (!$length || $length > $this->block_size) { + return false; + } + + return substr($text, 0, -$length); + } + + /** + * Clears internal buffers + * + * Clearing/resetting the internal buffers is done everytime + * after disableContinuousBuffer() or on cipher $engine (re)init + * ie after setKey() or setIV() + * + * Note: Could, but not must, extend by the child Crypt_* class + * + * @access public + */ + function _clearBuffers() + { + $this->enbuffer = array('encrypted' => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true); + $this->debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0, 'demcrypt_init' => true); + + // mcrypt's handling of invalid's $iv: + // $this->encryptIV = $this->decryptIV = strlen($this->iv) == $this->block_size ? $this->iv : str_repeat("\0", $this->block_size); + $this->encryptIV = $this->decryptIV = str_pad(substr($this->iv, 0, $this->block_size), $this->block_size, "\0"); + } + + /** + * String Shift + * + * Inspired by array_shift + * + * @param String $string + * @param optional Integer $index + * @access private + * @return String + */ + function _stringShift(&$string, $index = 1) + { + $substr = substr($string, 0, $index); + $string = substr($string, $index); + return $substr; + } + + /** + * Generate CTR XOR encryption key + * + * Encrypt the output of this and XOR it against the ciphertext / plaintext to get the + * plaintext / ciphertext in CTR mode. + * + * @see Crypt_Base::decrypt() + * @see Crypt_Base::encrypt() + * @param String $iv + * @param Integer $length + * @access private + * @return String $xor + */ + function _generateXor(&$iv, $length) + { + $xor = ''; + $block_size = $this->block_size; + $num_blocks = floor(($length + ($block_size - 1)) / $block_size); + for ($i = 0; $i < $num_blocks; $i++) { + $xor.= $iv; + for ($j = 4; $j <= $block_size; $j+= 4) { + $temp = substr($iv, -$j, 4); + switch ($temp) { + case "\xFF\xFF\xFF\xFF": + $iv = substr_replace($iv, "\x00\x00\x00\x00", -$j, 4); + break; + case "\x7F\xFF\xFF\xFF": + $iv = substr_replace($iv, "\x80\x00\x00\x00", -$j, 4); + break 2; + default: + extract(unpack('Ncount', $temp)); + $iv = substr_replace($iv, pack('N', $count + 1), -$j, 4); + break 2; + } + } + } + + return $xor; + } + + /** + * Setup the performance-optimized function for de/encrypt() + * + * Stores the created (or existing) callback function-name + * in $this->inline_crypt + * + * Internally for phpseclib developers: + * + * _setupInlineCrypt() would be called only if: + * + * - $engine == CRYPT_MODE_INTERNAL and + * + * - $use_inline_crypt === true + * + * - each time on _setup(), after(!) _setupKey() + * + * + * This ensures that _setupInlineCrypt() has allways a + * full ready2go initializated internal cipher $engine state + * where, for example, the keys allready expanded, + * keys/block_size calculated and such. + * + * It is, each time if called, the responsibility of _setupInlineCrypt(): + * + * - to set $this->inline_crypt to a valid and fully working callback function + * as a (faster) replacement for encrypt() / decrypt() + * + * - NOT to create unlimited callback functions (for memory reasons!) + * no matter how often _setupInlineCrypt() would be called. At some + * point of amount they must be generic re-useable. + * + * - the code of _setupInlineCrypt() it self, + * and the generated callback code, + * must be, in following order: + * - 100% safe + * - 100% compatible to encrypt()/decrypt() + * - using only php5+ features/lang-constructs/php-extensions if + * compatibility (down to php4) or fallback is provided + * - readable/maintainable/understandable/commented and... not-cryptic-styled-code :-) + * - >= 10% faster than encrypt()/decrypt() [which is, by the way, + * the reason for the existence of _setupInlineCrypt() :-)] + * - memory-nice + * - short (as good as possible) + * + * Note: - _setupInlineCrypt() is using _createInlineCryptFunction() to create the full callback function code. + * - In case of using inline crypting, _setupInlineCrypt() must extend by the child Crypt_* class. + * - The following variable names are reserved: + * - $_* (all variable names prefixed with an underscore) + * - $self (object reference to it self. Do not use $this, but $self instead) + * - $in (the content of $in has to en/decrypt by the generated code) + * - The callback function should not use the 'return' statement, but en/decrypt'ing the content of $in only + * + * + * @see Crypt_Base::_setup() + * @see Crypt_Base::_createInlineCryptFunction() + * @see Crypt_Base::encrypt() + * @see Crypt_Base::decrypt() + * @access private + */ + function _setupInlineCrypt() + { + // If a Crypt_* class providing inline crypting it must extend _setupInlineCrypt() + + // If, for any reason, an extending Crypt_Base() Crypt_* class + // not using inline crypting then it must be ensured that: $this->use_inline_crypt = false + // ie in the class var declaration of $use_inline_crypt in general for the Crypt_* class, + // in the constructor at object instance-time + // or, if it's runtime-specific, at runtime + + $this->use_inline_crypt = false; + } + + /** + * Creates the performance-optimized function for en/decrypt() + * + * Internally for phpseclib developers: + * + * _createInlineCryptFunction(): + * + * - merge the $cipher_code [setup'ed by _setupInlineCrypt()] + * with the current [$this->]mode of operation code + * + * - create the $inline function, which called by encrypt() / decrypt() + * as its replacement to speed up the en/decryption operations. + * + * - return the name of the created $inline callback function + * + * - used to speed up en/decryption + * + * + * + * The main reason why can speed up things [up to 50%] this way are: + * + * - using variables more effective then regular. + * (ie no use of expensive arrays but integers $k_0, $k_1 ... + * or even, for example, the pure $key[] values hardcoded) + * + * - avoiding 1000's of function calls of ie _encryptBlock() + * but inlining the crypt operations. + * in the mode of operation for() loop. + * + * - full loop unroll the (sometimes key-dependent) rounds + * avoiding this way ++$i counters and runtime-if's etc... + * + * The basic code architectur of the generated $inline en/decrypt() + * lambda function, in pseudo php, is: + * + * + * +----------------------------------------------------------------------------------------------+ + * | callback $inline = create_function: | + * | lambda_function_0001_crypt_ECB($action, $text) | + * | { | + * | INSERT PHP CODE OF: | + * | $cipher_code['init_crypt']; // general init code. | + * | // ie: $sbox'es declarations used for | + * | // encrypt and decrypt'ing. | + * | | + * | switch ($action) { | + * | case 'encrypt': | + * | INSERT PHP CODE OF: | + * | $cipher_code['init_encrypt']; // encrypt sepcific init code. | + * | ie: specified $key or $box | + * | declarations for encrypt'ing. | + * | | + * | foreach ($ciphertext) { | + * | $in = $block_size of $ciphertext; | + * | | + * | INSERT PHP CODE OF: | + * | $cipher_code['encrypt_block']; // encrypt's (string) $in, which is always: | + * | // strlen($in) == $this->block_size | + * | // here comes the cipher algorithm in action | + * | // for encryption. | + * | // $cipher_code['encrypt_block'] has to | + * | // encrypt the content of the $in variable | + * | | + * | $plaintext .= $in; | + * | } | + * | return $plaintext; | + * | | + * | case 'decrypt': | + * | INSERT PHP CODE OF: | + * | $cipher_code['init_decrypt']; // decrypt sepcific init code | + * | ie: specified $key or $box | + * | declarations for decrypt'ing. | + * | foreach ($plaintext) { | + * | $in = $block_size of $plaintext; | + * | | + * | INSERT PHP CODE OF: | + * | $cipher_code['decrypt_block']; // decrypt's (string) $in, which is always | + * | // strlen($in) == $this->block_size | + * | // here comes the cipher algorithm in action | + * | // for decryption. | + * | // $cipher_code['decrypt_block'] has to | + * | // decrypt the content of the $in variable | + * | $ciphertext .= $in; | + * | } | + * | return $ciphertext; | + * | } | + * | } | + * +----------------------------------------------------------------------------------------------+ + * + * + * See also the Crypt_*::_setupInlineCrypt()'s for + * productive inline $cipher_code's how they works. + * + * Structure of: + * + * $cipher_code = array( + * 'init_crypt' => (string) '', // optional + * 'init_encrypt' => (string) '', // optional + * 'init_decrypt' => (string) '', // optional + * 'encrypt_block' => (string) '', // required + * 'decrypt_block' => (string) '' // required + * ); + * + * + * @see Crypt_Base::_setupInlineCrypt() + * @see Crypt_Base::encrypt() + * @see Crypt_Base::decrypt() + * @param Array $cipher_code + * @access private + * @return String (the name of the created callback function) + */ + function _createInlineCryptFunction($cipher_code) + { + $block_size = $this->block_size; + + // optional + $init_crypt = isset($cipher_code['init_crypt']) ? $cipher_code['init_crypt'] : ''; + $init_encrypt = isset($cipher_code['init_encrypt']) ? $cipher_code['init_encrypt'] : ''; + $init_decrypt = isset($cipher_code['init_decrypt']) ? $cipher_code['init_decrypt'] : ''; + // required + $encrypt_block = $cipher_code['encrypt_block']; + $decrypt_block = $cipher_code['decrypt_block']; + + // Generating mode of operation inline code, + // merged with the $cipher_code algorithm + // for encrypt- and decryption. + switch ($this->mode) { + case CRYPT_MODE_ECB: + $encrypt = $init_encrypt . ' + $_ciphertext = ""; + $_text = $self->_pad($_text); + $_plaintext_len = strlen($_text); + + for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') { + $in = substr($_text, $_i, '.$block_size.'); + '.$encrypt_block.' + $_ciphertext.= $in; + } + + return $_ciphertext; + '; + + $decrypt = $init_decrypt . ' + $_plaintext = ""; + $_text = str_pad($_text, strlen($_text) + ('.$block_size.' - strlen($_text) % '.$block_size.') % '.$block_size.', chr(0)); + $_ciphertext_len = strlen($_text); + + for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') { + $in = substr($_text, $_i, '.$block_size.'); + '.$decrypt_block.' + $_plaintext.= $in; + } + + return $self->_unpad($_plaintext); + '; + break; + case CRYPT_MODE_CTR: + $encrypt = $init_encrypt . ' + $_ciphertext = ""; + $_plaintext_len = strlen($_text); + $_xor = $self->encryptIV; + $_buffer = &$self->enbuffer; + + if (strlen($_buffer["encrypted"])) { + for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') { + $_block = substr($_text, $_i, '.$block_size.'); + if (strlen($_block) > strlen($_buffer["encrypted"])) { + $in = $self->_generateXor($_xor, '.$block_size.'); + '.$encrypt_block.' + $_buffer["encrypted"].= $in; + } + $_key = $self->_stringShift($_buffer["encrypted"], '.$block_size.'); + $_ciphertext.= $_block ^ $_key; + } + } else { + for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') { + $_block = substr($_text, $_i, '.$block_size.'); + $in = $self->_generateXor($_xor, '.$block_size.'); + '.$encrypt_block.' + $_key = $in; + $_ciphertext.= $_block ^ $_key; + } + } + if ($self->continuousBuffer) { + $self->encryptIV = $_xor; + if ($_start = $_plaintext_len % '.$block_size.') { + $_buffer["encrypted"] = substr($_key, $_start) . $_buffer["encrypted"]; + } + } + + return $_ciphertext; + '; + + $decrypt = $init_encrypt . ' + $_plaintext = ""; + $_ciphertext_len = strlen($_text); + $_xor = $self->decryptIV; + $_buffer = &$self->debuffer; + + if (strlen($_buffer["ciphertext"])) { + for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') { + $_block = substr($_text, $_i, '.$block_size.'); + if (strlen($_block) > strlen($_buffer["ciphertext"])) { + $in = $self->_generateXor($_xor, '.$block_size.'); + '.$encrypt_block.' + $_buffer["ciphertext"].= $in; + } + $_key = $self->_stringShift($_buffer["ciphertext"], '.$block_size.'); + $_plaintext.= $_block ^ $_key; + } + } else { + for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') { + $_block = substr($_text, $_i, '.$block_size.'); + $in = $self->_generateXor($_xor, '.$block_size.'); + '.$encrypt_block.' + $_key = $in; + $_plaintext.= $_block ^ $_key; + } + } + if ($self->continuousBuffer) { + $self->decryptIV = $_xor; + if ($_start = $_ciphertext_len % '.$block_size.') { + $_buffer["ciphertext"] = substr($_key, $_start) . $_buffer["ciphertext"]; + } + } + + return $_plaintext; + '; + break; + case CRYPT_MODE_CFB: + $encrypt = $init_encrypt . ' + $_ciphertext = ""; + $_buffer = &$self->enbuffer; + + if ($self->continuousBuffer) { + $_iv = &$self->encryptIV; + $_pos = &$_buffer["pos"]; + } else { + $_iv = $self->encryptIV; + $_pos = 0; + } + $_len = strlen($_text); + $_i = 0; + if ($_pos) { + $_orig_pos = $_pos; + $_max = '.$block_size.' - $_pos; + if ($_len >= $_max) { + $_i = $_max; + $_len-= $_max; + $_pos = 0; + } else { + $_i = $_len; + $_pos+= $_len; + $_len = 0; + } + $_ciphertext = substr($_iv, $_orig_pos) ^ $_text; + $_iv = substr_replace($_iv, $_ciphertext, $_orig_pos, $_i); + } + while ($_len >= '.$block_size.') { + $in = $_iv; + '.$encrypt_block.'; + $_iv = $in ^ substr($_text, $_i, '.$block_size.'); + $_ciphertext.= $_iv; + $_len-= '.$block_size.'; + $_i+= '.$block_size.'; + } + if ($_len) { + $in = $_iv; + '.$encrypt_block.' + $_iv = $in; + $_block = $_iv ^ substr($_text, $_i); + $_iv = substr_replace($_iv, $_block, 0, $_len); + $_ciphertext.= $_block; + $_pos = $_len; + } + return $_ciphertext; + '; + + $decrypt = $init_encrypt . ' + $_plaintext = ""; + $_buffer = &$self->debuffer; + + if ($self->continuousBuffer) { + $_iv = &$self->decryptIV; + $_pos = &$_buffer["pos"]; + } else { + $_iv = $self->decryptIV; + $_pos = 0; + } + $_len = strlen($_text); + $_i = 0; + if ($_pos) { + $_orig_pos = $_pos; + $_max = '.$block_size.' - $_pos; + if ($_len >= $_max) { + $_i = $_max; + $_len-= $_max; + $_pos = 0; + } else { + $_i = $_len; + $_pos+= $_len; + $_len = 0; + } + $_plaintext = substr($_iv, $_orig_pos) ^ $_text; + $_iv = substr_replace($_iv, substr($_text, 0, $_i), $_orig_pos, $_i); + } + while ($_len >= '.$block_size.') { + $in = $_iv; + '.$encrypt_block.' + $_iv = $in; + $cb = substr($_text, $_i, '.$block_size.'); + $_plaintext.= $_iv ^ $cb; + $_iv = $cb; + $_len-= '.$block_size.'; + $_i+= '.$block_size.'; + } + if ($_len) { + $in = $_iv; + '.$encrypt_block.' + $_iv = $in; + $_plaintext.= $_iv ^ substr($_text, $_i); + $_iv = substr_replace($_iv, substr($_text, $_i), 0, $_len); + $_pos = $_len; + } + + return $_plaintext; + '; + break; + case CRYPT_MODE_OFB: + $encrypt = $init_encrypt . ' + $_ciphertext = ""; + $_plaintext_len = strlen($_text); + $_xor = $self->encryptIV; + $_buffer = &$self->enbuffer; + + if (strlen($_buffer["xor"])) { + for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') { + $_block = substr($_text, $_i, '.$block_size.'); + if (strlen($_block) > strlen($_buffer["xor"])) { + $in = $_xor; + '.$encrypt_block.' + $_xor = $in; + $_buffer["xor"].= $_xor; + } + $_key = $self->_stringShift($_buffer["xor"], '.$block_size.'); + $_ciphertext.= $_block ^ $_key; + } + } else { + for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') { + $in = $_xor; + '.$encrypt_block.' + $_xor = $in; + $_ciphertext.= substr($_text, $_i, '.$block_size.') ^ $_xor; + } + $_key = $_xor; + } + if ($self->continuousBuffer) { + $self->encryptIV = $_xor; + if ($_start = $_plaintext_len % '.$block_size.') { + $_buffer["xor"] = substr($_key, $_start) . $_buffer["xor"]; + } + } + return $_ciphertext; + '; + + $decrypt = $init_encrypt . ' + $_plaintext = ""; + $_ciphertext_len = strlen($_text); + $_xor = $self->decryptIV; + $_buffer = &$self->debuffer; + + if (strlen($_buffer["xor"])) { + for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') { + $_block = substr($_text, $_i, '.$block_size.'); + if (strlen($_block) > strlen($_buffer["xor"])) { + $in = $_xor; + '.$encrypt_block.' + $_xor = $in; + $_buffer["xor"].= $_xor; + } + $_key = $self->_stringShift($_buffer["xor"], '.$block_size.'); + $_plaintext.= $_block ^ $_key; + } + } else { + for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') { + $in = $_xor; + '.$encrypt_block.' + $_xor = $in; + $_plaintext.= substr($_text, $_i, '.$block_size.') ^ $_xor; + } + $_key = $_xor; + } + if ($self->continuousBuffer) { + $self->decryptIV = $_xor; + if ($_start = $_ciphertext_len % '.$block_size.') { + $_buffer["xor"] = substr($_key, $_start) . $_buffer["xor"]; + } + } + return $_plaintext; + '; + break; + case CRYPT_MODE_STREAM: + $encrypt = $init_encrypt . ' + $_ciphertext = ""; + '.$encrypt_block.' + return $_ciphertext; + '; + $decrypt = $init_decrypt . ' + $_plaintext = ""; + '.$decrypt_block.' + return $_plaintext; + '; + break; + // case CRYPT_MODE_CBC: + default: + $encrypt = $init_encrypt . ' + $_ciphertext = ""; + $_text = $self->_pad($_text); + $_plaintext_len = strlen($_text); + + $in = $self->encryptIV; + + for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') { + $in = substr($_text, $_i, '.$block_size.') ^ $in; + '.$encrypt_block.' + $_ciphertext.= $in; + } + + if ($self->continuousBuffer) { + $self->encryptIV = $in; + } + + return $_ciphertext; + '; + + $decrypt = $init_decrypt . ' + $_plaintext = ""; + $_text = str_pad($_text, strlen($_text) + ('.$block_size.' - strlen($_text) % '.$block_size.') % '.$block_size.', chr(0)); + $_ciphertext_len = strlen($_text); + + $_iv = $self->decryptIV; + + for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') { + $in = $_block = substr($_text, $_i, '.$block_size.'); + '.$decrypt_block.' + $_plaintext.= $in ^ $_iv; + $_iv = $_block; + } + + if ($self->continuousBuffer) { + $self->decryptIV = $_iv; + } + + return $self->_unpad($_plaintext); + '; + break; + } + + // Create the $inline function and return its name as string. Ready to run! + return create_function('$_action, &$self, $_text', $init_crypt . 'if ($_action == "encrypt") { ' . $encrypt . ' } else { ' . $decrypt . ' }'); + } + + /** + * Holds the lambda_functions table (classwide) + * + * Each name of the lambda function, created from + * _setupInlineCrypt() && _createInlineCryptFunction() + * is stored, classwide (!), here for reusing. + * + * The string-based index of $function is a classwide + * uniqe value representing, at least, the $mode of + * operation (or more... depends of the optimizing level) + * for which $mode the lambda function was created. + * + * @access private + * @return &Array + */ + function &_getLambdaFunctions() + { + static $functions = array(); + return $functions; + } +} + +// vim: ts=4:sw=4:et: +// vim6: fdl=1: diff --git a/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/Blowfish.php b/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/Blowfish.php new file mode 100644 index 0000000000..c8ef67e8f7 --- /dev/null +++ b/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/Blowfish.php @@ -0,0 +1,678 @@ + + * setKey('12345678901234567890123456789012'); + * + * $plaintext = str_repeat('a', 1024); + * + * echo $blowfish->decrypt($blowfish->encrypt($plaintext)); + * ?> + * + * + * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @category Crypt + * @package Crypt_Blowfish + * @author Jim Wigginton + * @author Hans-Juergen Petrich + * @copyright MMVII Jim Wigginton + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @version 1.0 + * @link http://phpseclib.sourceforge.net + */ + +/** + * Include Crypt_Base + * + * Base cipher class + */ +if (!class_exists('Crypt_Base')) { + require_once('Base.php'); +} + +/**#@+ + * @access public + * @see Crypt_Blowfish::encrypt() + * @see Crypt_Blowfish::decrypt() + */ +/** + * Encrypt / decrypt using the Counter mode. + * + * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29 + */ +define('CRYPT_BLOWFISH_MODE_CTR', CRYPT_MODE_CTR); +/** + * Encrypt / decrypt using the Electronic Code Book mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29 + */ +define('CRYPT_BLOWFISH_MODE_ECB', CRYPT_MODE_ECB); +/** + * Encrypt / decrypt using the Code Book Chaining mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29 + */ +define('CRYPT_BLOWFISH_MODE_CBC', CRYPT_MODE_CBC); +/** + * Encrypt / decrypt using the Cipher Feedback mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29 + */ +define('CRYPT_BLOWFISH_MODE_CFB', CRYPT_MODE_CFB); +/** + * Encrypt / decrypt using the Cipher Feedback mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29 + */ +define('CRYPT_BLOWFISH_MODE_OFB', CRYPT_MODE_OFB); +/**#@-*/ + +/**#@+ + * @access private + * @see Crypt_Blowfish::Crypt_Blowfish() + */ +/** + * Toggles the internal implementation + */ +define('CRYPT_BLOWFISH_MODE_INTERNAL', CRYPT_MODE_INTERNAL); +/** + * Toggles the mcrypt implementation + */ +define('CRYPT_BLOWFISH_MODE_MCRYPT', CRYPT_MODE_MCRYPT); +/**#@-*/ + +/** + * Pure-PHP implementation of Blowfish. + * + * @author Jim Wigginton + * @author Hans-Juergen Petrich + * @version 1.0 + * @access public + * @package Crypt_Blowfish + */ +class Crypt_Blowfish extends Crypt_Base { + /** + * Block Length of the cipher + * + * @see Crypt_Base::block_size + * @var Integer + * @access private + */ + var $block_size = 8; + + /** + * The default password key_size used by setPassword() + * + * @see Crypt_Base::password_key_size + * @see Crypt_Base::setPassword() + * @var Integer + * @access private + */ + var $password_key_size = 56; + + /** + * The namespace used by the cipher for its constants. + * + * @see Crypt_Base::const_namespace + * @var String + * @access private + */ + var $const_namespace = 'BLOWFISH'; + + /** + * The mcrypt specific name of the cipher + * + * @see Crypt_Base::cipher_name_mcrypt + * @var String + * @access private + */ + var $cipher_name_mcrypt = 'blowfish'; + + /** + * Optimizing value while CFB-encrypting + * + * @see Crypt_Base::cfb_init_len + * @var Integer + * @access private + */ + var $cfb_init_len = 500; + + /** + * The fixed subkeys boxes ($sbox0 - $sbox3) with 256 entries each + * + * S-Box 1 + * + * @access private + * @var array + */ + var $sbox0 = array ( + 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99, + 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, + 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, + 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e, + 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, + 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, + 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677, + 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, + 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, + 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0, + 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, + 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, + 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d, + 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, + 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, + 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09, + 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, + 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, + 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82, + 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, + 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, + 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8, + 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, + 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, + 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1, + 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, + 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, + 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af, + 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, + 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, + 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915, + 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a + ); + + /** + * S-Box 1 + * + * @access private + * @var array + */ + var $sbox1 = array( + 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266, + 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, + 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, + 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1, + 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, + 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, + 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7, + 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, + 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, + 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87, + 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, + 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, + 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509, + 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, + 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, + 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960, + 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, + 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, + 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf, + 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, + 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, + 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281, + 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, + 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, + 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0, + 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, + 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, + 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061, + 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, + 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, + 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340, + 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7 + ); + + /** + * S-Box 2 + * + * @access private + * @var array + */ + var $sbox2 = array( + 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068, + 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, + 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, + 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb, + 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, + 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, + 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb, + 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, + 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, + 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc, + 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, + 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, + 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728, + 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, + 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, + 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b, + 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, + 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, + 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9, + 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, + 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, + 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61, + 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, + 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, + 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633, + 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, + 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, + 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62, + 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, + 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, + 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c, + 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0 + ); + + /** + * S-Box 3 + * + * @access private + * @var array + */ + var $sbox3 = array( + 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe, + 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, + 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, + 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22, + 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, + 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, + 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51, + 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, + 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, + 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd, + 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, + 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, + 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32, + 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, + 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, + 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47, + 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, + 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048, + 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd, + 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, + 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, + 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525, + 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, + 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, + 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d, + 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, + 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, + 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a, + 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, + 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, + 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9, + 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6 + ); + + /** + * P-Array consists of 18 32-bit subkeys + * + * @var array $parray + * @access private + */ + var $parray = array( + 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0, + 0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, + 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b + ); + + /** + * The BCTX-working Array + * + * Holds the expanded key [p] and the key-depended s-boxes [sb] + * + * @var array $bctx + * @access private + */ + var $bctx; + + /** + * Holds the last used key + * + * @var Array + * @access private + */ + var $kl; + + /** + * Default Constructor. + * + * Determines whether or not the mcrypt extension should be used. + * + * $mode could be: + * + * - CRYPT_BLOWFISH_MODE_ECB + * + * - CRYPT_BLOWFISH_MODE_CBC + * + * - CRYPT_BLOWFISH_MODE_CTR + * + * - CRYPT_BLOWFISH_MODE_CFB + * + * - CRYPT_BLOWFISH_MODE_OFB + * + * If not explictly set, CRYPT_BLOWFISH_MODE_CBC will be used. + * + * @see Crypt_Base::Crypt_Base() + * @param optional Integer $mode + * @access public + */ + function Crypt_Blowfish($mode = CRYPT_BLOWFISH_MODE_CBC) + { + parent::Crypt_Base($mode); + } + + /** + * Sets the key. + * + * Keys can be of any length. Blowfish, itself, requires the use of a key between 32 and max. 448-bits long. + * If the key is less than 32-bits we NOT fill the key to 32bit but let the key as it is to be compatible + * with mcrypt because mcrypt act this way with blowfish key's < 32 bits. + * + * If the key is more than 448-bits, we trim the excess bits. + * + * If the key is not explicitly set, or empty, it'll be assumed a 128 bits key to be all null bytes. + * + * @access public + * @see Crypt_Base::setKey() + * @param String $key + */ + function setKey($key) + { + $keylength = strlen($key); + + if (!$keylength) { + $key = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; + } + elseif ($keylength > 56) { + $key = substr($key, 0, 56); + } + + parent::setKey($key); + } + + /** + * Setup the key (expansion) + * + * @see Crypt_Base::_setupKey() + * @access private + */ + function _setupKey() + { + if (isset($this->kl['key']) && $this->key === $this->kl['key']) { + // already expanded + return; + } + $this->kl = array('key' => $this->key); + + /* key-expanding p[] and S-Box building sb[] */ + $this->bctx = array( + 'p' => array(), + 'sb' => array( + $this->sbox0, + $this->sbox1, + $this->sbox2, + $this->sbox3 + ) + ); + + // unpack binary string in unsigned chars + $key = array_values(unpack('C*', $this->key)); + $keyl = count($key); + for ($j = 0, $i = 0; $i < 18; ++$i) { + // xor P1 with the first 32-bits of the key, xor P2 with the second 32-bits ... + for ($data = 0, $k = 0; $k < 4; ++$k) { + $data = ($data << 8) | $key[$j]; + if (++$j >= $keyl) { + $j = 0; + } + } + $this->bctx['p'][] = $this->parray[$i] ^ $data; + } + + // encrypt the zero-string, replace P1 and P2 with the encrypted data, + // encrypt P3 and P4 with the new P1 and P2, do it with all P-array and subkeys + $data = "\0\0\0\0\0\0\0\0"; + for ($i = 0; $i < 18; $i += 2) { + list($l, $r) = array_values(unpack('N*', $data = $this->_encryptBlock($data))); + $this->bctx['p'][$i ] = $l; + $this->bctx['p'][$i + 1] = $r; + } + for ($i = 0; $i < 4; ++$i) { + for ($j = 0; $j < 256; $j += 2) { + list($l, $r) = array_values(unpack('N*', $data = $this->_encryptBlock($data))); + $this->bctx['sb'][$i][$j ] = $l; + $this->bctx['sb'][$i][$j + 1] = $r; + } + } + } + + /** + * Encrypts a block + * + * @access private + * @param String $in + * @return String + */ + function _encryptBlock($in) + { + $p = $this->bctx["p"]; + // extract($this->bctx["sb"], EXTR_PREFIX_ALL, "sb"); // slower + $sb_0 = $this->bctx["sb"][0]; + $sb_1 = $this->bctx["sb"][1]; + $sb_2 = $this->bctx["sb"][2]; + $sb_3 = $this->bctx["sb"][3]; + + $in = unpack("N*", $in); + $l = $in[1]; + $r = $in[2]; + + for ($i = 0; $i < 16; $i+= 2) { + $l^= $p[$i]; + $r^= ($sb_0[$l >> 24 & 0xff] + + $sb_1[$l >> 16 & 0xff] ^ + $sb_2[$l >> 8 & 0xff]) + + $sb_3[$l & 0xff]; + + $r^= $p[$i + 1]; + $l^= ($sb_0[$r >> 24 & 0xff] + + $sb_1[$r >> 16 & 0xff] ^ + $sb_2[$r >> 8 & 0xff]) + + $sb_3[$r & 0xff]; + } + return pack("N*", $r ^ $p[17], $l ^ $p[16]); + } + + /** + * Decrypts a block + * + * @access private + * @param String $in + * @return String + */ + function _decryptBlock($in) + { + $p = $this->bctx["p"]; + $sb_0 = $this->bctx["sb"][0]; + $sb_1 = $this->bctx["sb"][1]; + $sb_2 = $this->bctx["sb"][2]; + $sb_3 = $this->bctx["sb"][3]; + + $in = unpack("N*", $in); + $l = $in[1]; + $r = $in[2]; + + for ($i = 17; $i > 2; $i-= 2) { + $l^= $p[$i]; + $r^= ($sb_0[$l >> 24 & 0xff] + + $sb_1[$l >> 16 & 0xff] ^ + $sb_2[$l >> 8 & 0xff]) + + $sb_3[$l & 0xff]; + + $r^= $p[$i - 1]; + $l^= ($sb_0[$r >> 24 & 0xff] + + $sb_1[$r >> 16 & 0xff] ^ + $sb_2[$r >> 8 & 0xff]) + + $sb_3[$r & 0xff]; + } + + return pack("N*", $r ^ $p[0], $l ^ $p[1]); + } + + /** + * Setup the performance-optimized function for de/encrypt() + * + * @see Crypt_Base::_setupInlineCrypt() + * @access private + */ + function _setupInlineCrypt() + { + $lambda_functions =& Crypt_Blowfish::_getLambdaFunctions(); + + // We create max. 10 hi-optimized code for memory reason. Means: For each $key one ultra fast inline-crypt function. + // After that, we'll still create very fast optimized code but not the hi-ultimative code, for each $mode one. + $gen_hi_opt_code = (bool)( count($lambda_functions) < 10); + + switch (true) { + case $gen_hi_opt_code: + $code_hash = md5(str_pad("Crypt_Blowfish, {$this->mode}, ", 32, "\0") . $this->key); + break; + default: + $code_hash = "Crypt_Blowfish, {$this->mode}"; + } + + if (!isset($lambda_functions[$code_hash])) { + switch (true) { + case $gen_hi_opt_code: + $p = $this->bctx['p']; + $init_crypt = ' + static $sb_0, $sb_1, $sb_2, $sb_3; + if (!$sb_0) { + $sb_0 = $self->bctx["sb"][0]; + $sb_1 = $self->bctx["sb"][1]; + $sb_2 = $self->bctx["sb"][2]; + $sb_3 = $self->bctx["sb"][3]; + } + '; + break; + default: + $p = array(); + for ($i = 0; $i < 18; ++$i) { + $p[] = '$p_' . $i; + } + $init_crypt = ' + list($sb_0, $sb_1, $sb_2, $sb_3) = $self->bctx["sb"]; + list(' . implode(',', $p) . ') = $self->bctx["p"]; + + '; + } + + // Generating encrypt code: + $encrypt_block = ' + $in = unpack("N*", $in); + $l = $in[1]; + $r = $in[2]; + '; + for ($i = 0; $i < 16; $i+= 2) { + $encrypt_block.= ' + $l^= ' . $p[$i] . '; + $r^= ($sb_0[$l >> 24 & 0xff] + + $sb_1[$l >> 16 & 0xff] ^ + $sb_2[$l >> 8 & 0xff]) + + $sb_3[$l & 0xff]; + + $r^= ' . $p[$i + 1] . '; + $l^= ($sb_0[$r >> 24 & 0xff] + + $sb_1[$r >> 16 & 0xff] ^ + $sb_2[$r >> 8 & 0xff]) + + $sb_3[$r & 0xff]; + '; + } + $encrypt_block.= ' + $in = pack("N*", + $r ^ ' . $p[17] . ', + $l ^ ' . $p[16] . ' + ); + '; + + // Generating decrypt code: + $decrypt_block = ' + $in = unpack("N*", $in); + $l = $in[1]; + $r = $in[2]; + '; + + for ($i = 17; $i > 2; $i-= 2) { + $decrypt_block.= ' + $l^= ' . $p[$i] . '; + $r^= ($sb_0[$l >> 24 & 0xff] + + $sb_1[$l >> 16 & 0xff] ^ + $sb_2[$l >> 8 & 0xff]) + + $sb_3[$l & 0xff]; + + $r^= ' . $p[$i - 1] . '; + $l^= ($sb_0[$r >> 24 & 0xff] + + $sb_1[$r >> 16 & 0xff] ^ + $sb_2[$r >> 8 & 0xff]) + + $sb_3[$r & 0xff]; + '; + } + + $decrypt_block.= ' + $in = pack("N*", + $r ^ ' . $p[0] . ', + $l ^ ' . $p[1] . ' + ); + '; + + $lambda_functions[$code_hash] = $this->_createInlineCryptFunction( + array( + 'init_crypt' => $init_crypt, + 'init_encrypt' => '', + 'init_decrypt' => '', + 'encrypt_block' => $encrypt_block, + 'decrypt_block' => $decrypt_block + ) + ); + } + $this->inline_crypt = $lambda_functions[$code_hash]; + } +} + +// vim: ts=4:sw=4:et: +// vim6: fdl=1: diff --git a/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/DES.php b/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/DES.php index 1197a50ab7..8b04210659 100644 --- a/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/DES.php +++ b/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/DES.php @@ -39,10 +39,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -56,21 +56,29 @@ * @author Jim Wigginton * @copyright MMVII Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @version $Id: DES.php,v 1.12 2010/02/09 06:10:26 terrafrost Exp $ * @link http://phpseclib.sourceforge.net */ +/** + * Include Crypt_Base + * + * Base cipher class + */ +if (!class_exists('Crypt_Base')) { + require_once('Base.php'); +} + /**#@+ * @access private - * @see Crypt_DES::_prepareKey() + * @see Crypt_DES::_setupKey() * @see Crypt_DES::_processBlock() */ /** - * Contains array_reverse($keys[CRYPT_DES_DECRYPT]) + * Contains $keys[CRYPT_DES_ENCRYPT] */ define('CRYPT_DES_ENCRYPT', 0); /** - * Contains array_reverse($keys[CRYPT_DES_ENCRYPT]) + * Contains $keys[CRYPT_DES_DECRYPT] */ define('CRYPT_DES_DECRYPT', 1); /**#@-*/ @@ -87,31 +95,31 @@ define('CRYPT_DES_DECRYPT', 1); * * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29 */ -define('CRYPT_DES_MODE_CTR', -1); +define('CRYPT_DES_MODE_CTR', CRYPT_MODE_CTR); /** * Encrypt / decrypt using the Electronic Code Book mode. * * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29 */ -define('CRYPT_DES_MODE_ECB', 1); +define('CRYPT_DES_MODE_ECB', CRYPT_MODE_ECB); /** * Encrypt / decrypt using the Code Book Chaining mode. * * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29 */ -define('CRYPT_DES_MODE_CBC', 2); +define('CRYPT_DES_MODE_CBC', CRYPT_MODE_CBC); /** * Encrypt / decrypt using the Cipher Feedback mode. * * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29 */ -define('CRYPT_DES_MODE_CFB', 3); +define('CRYPT_DES_MODE_CFB', CRYPT_MODE_CFB); /** * Encrypt / decrypt using the Cipher Feedback mode. * * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29 */ -define('CRYPT_DES_MODE_OFB', 4); +define('CRYPT_DES_MODE_OFB', CRYPT_MODE_OFB); /**#@-*/ /**#@+ @@ -121,11 +129,11 @@ define('CRYPT_DES_MODE_OFB', 4); /** * Toggles the internal implementation */ -define('CRYPT_DES_MODE_INTERNAL', 1); +define('CRYPT_DES_MODE_INTERNAL', CRYPT_MODE_INTERNAL); /** * Toggles the mcrypt implementation */ -define('CRYPT_DES_MODE_MCRYPT', 2); +define('CRYPT_DES_MODE_MCRYPT', CRYPT_MODE_MCRYPT); /**#@-*/ /** @@ -136,217 +144,550 @@ define('CRYPT_DES_MODE_MCRYPT', 2); * @access public * @package Crypt_DES */ -class Crypt_DES { +class Crypt_DES extends Crypt_Base { /** - * The Key Schedule + * Block Length of the cipher * - * @see Crypt_DES::setKey() - * @var Array - * @access private - */ - var $keys = "\0\0\0\0\0\0\0\0"; - - /** - * The Encryption Mode - * - * @see Crypt_DES::Crypt_DES() + * @see Crypt_Base::block_size * @var Integer * @access private */ - var $mode; + var $block_size = 8; /** - * Continuous Buffer status + * The Key * - * @see Crypt_DES::enableContinuousBuffer() - * @var Boolean - * @access private - */ - var $continuousBuffer = false; - - /** - * Padding status - * - * @see Crypt_DES::enablePadding() - * @var Boolean - * @access private - */ - var $padding = true; - - /** - * The Initialization Vector - * - * @see Crypt_DES::setIV() + * @see Crypt_Base::key + * @see setKey() * @var String * @access private */ - var $iv = "\0\0\0\0\0\0\0\0"; + var $key = "\0\0\0\0\0\0\0\0"; /** - * A "sliding" Initialization Vector + * The default password key_size used by setPassword() * - * @see Crypt_DES::enableContinuousBuffer() + * @see Crypt_Base::password_key_size + * @see Crypt_Base::setPassword() + * @var Integer + * @access private + */ + var $password_key_size = 8; + + /** + * The namespace used by the cipher for its constants. + * + * @see Crypt_Base::const_namespace * @var String * @access private */ - var $encryptIV = "\0\0\0\0\0\0\0\0"; + var $const_namespace = 'DES'; /** - * A "sliding" Initialization Vector + * The mcrypt specific name of the cipher * - * @see Crypt_DES::enableContinuousBuffer() + * @see Crypt_Base::cipher_name_mcrypt * @var String * @access private */ - var $decryptIV = "\0\0\0\0\0\0\0\0"; + var $cipher_name_mcrypt = 'des'; /** - * mcrypt resource for encryption + * Optimizing value while CFB-encrypting * - * The mcrypt resource can be recreated every time something needs to be created or it can be created just once. - * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode. - * - * @see Crypt_DES::encrypt() - * @var String + * @see Crypt_Base::cfb_init_len + * @var Integer * @access private */ - var $enmcrypt; + var $cfb_init_len = 500; /** - * mcrypt resource for decryption + * Switch for DES/3DES encryption * - * The mcrypt resource can be recreated every time something needs to be created or it can be created just once. - * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode. + * Used only if $engine == CRYPT_DES_MODE_INTERNAL * - * @see Crypt_DES::decrypt() - * @var String + * @see Crypt_DES::_setupKey() + * @see Crypt_DES::_processBlock() + * @var Integer * @access private */ - var $demcrypt; + var $des_rounds = 1; /** - * Does the enmcrypt resource need to be (re)initialized? + * max possible size of $key * * @see Crypt_DES::setKey() - * @see Crypt_DES::setIV() - * @var Boolean + * @var String * @access private */ - var $enchanged = true; + var $key_size_max = 8; /** - * Does the demcrypt resource need to be (re)initialized? + * The Key Schedule * - * @see Crypt_DES::setKey() - * @see Crypt_DES::setIV() - * @var Boolean - * @access private - */ - var $dechanged = true; - - /** - * Is the mode one that is paddable? - * - * @see Crypt_DES::Crypt_DES() - * @var Boolean - * @access private - */ - var $paddable = false; - - /** - * Encryption buffer for CTR, OFB and CFB modes - * - * @see Crypt_DES::encrypt() + * @see Crypt_DES::_setupKey() * @var Array * @access private */ - var $enbuffer = array('encrypted' => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true); + var $keys; /** - * Decryption buffer for CTR, OFB and CFB modes + * Shuffle table. * - * @see Crypt_DES::decrypt() + * For each byte value index, the entry holds an 8-byte string + * with each byte containing all bits in the same state as the + * corresponding bit in the index value. + * + * @see Crypt_DES::_processBlock() + * @see Crypt_DES::_setupKey() * @var Array * @access private */ - var $debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0, 'demcrypt_init' => true); + var $shuffle = array( + "\x00\x00\x00\x00\x00\x00\x00\x00", "\x00\x00\x00\x00\x00\x00\x00\xFF", + "\x00\x00\x00\x00\x00\x00\xFF\x00", "\x00\x00\x00\x00\x00\x00\xFF\xFF", + "\x00\x00\x00\x00\x00\xFF\x00\x00", "\x00\x00\x00\x00\x00\xFF\x00\xFF", + "\x00\x00\x00\x00\x00\xFF\xFF\x00", "\x00\x00\x00\x00\x00\xFF\xFF\xFF", + "\x00\x00\x00\x00\xFF\x00\x00\x00", "\x00\x00\x00\x00\xFF\x00\x00\xFF", + "\x00\x00\x00\x00\xFF\x00\xFF\x00", "\x00\x00\x00\x00\xFF\x00\xFF\xFF", + "\x00\x00\x00\x00\xFF\xFF\x00\x00", "\x00\x00\x00\x00\xFF\xFF\x00\xFF", + "\x00\x00\x00\x00\xFF\xFF\xFF\x00", "\x00\x00\x00\x00\xFF\xFF\xFF\xFF", + "\x00\x00\x00\xFF\x00\x00\x00\x00", "\x00\x00\x00\xFF\x00\x00\x00\xFF", + "\x00\x00\x00\xFF\x00\x00\xFF\x00", "\x00\x00\x00\xFF\x00\x00\xFF\xFF", + "\x00\x00\x00\xFF\x00\xFF\x00\x00", "\x00\x00\x00\xFF\x00\xFF\x00\xFF", + "\x00\x00\x00\xFF\x00\xFF\xFF\x00", "\x00\x00\x00\xFF\x00\xFF\xFF\xFF", + "\x00\x00\x00\xFF\xFF\x00\x00\x00", "\x00\x00\x00\xFF\xFF\x00\x00\xFF", + "\x00\x00\x00\xFF\xFF\x00\xFF\x00", "\x00\x00\x00\xFF\xFF\x00\xFF\xFF", + "\x00\x00\x00\xFF\xFF\xFF\x00\x00", "\x00\x00\x00\xFF\xFF\xFF\x00\xFF", + "\x00\x00\x00\xFF\xFF\xFF\xFF\x00", "\x00\x00\x00\xFF\xFF\xFF\xFF\xFF", + "\x00\x00\xFF\x00\x00\x00\x00\x00", "\x00\x00\xFF\x00\x00\x00\x00\xFF", + "\x00\x00\xFF\x00\x00\x00\xFF\x00", "\x00\x00\xFF\x00\x00\x00\xFF\xFF", + "\x00\x00\xFF\x00\x00\xFF\x00\x00", "\x00\x00\xFF\x00\x00\xFF\x00\xFF", + "\x00\x00\xFF\x00\x00\xFF\xFF\x00", "\x00\x00\xFF\x00\x00\xFF\xFF\xFF", + "\x00\x00\xFF\x00\xFF\x00\x00\x00", "\x00\x00\xFF\x00\xFF\x00\x00\xFF", + "\x00\x00\xFF\x00\xFF\x00\xFF\x00", "\x00\x00\xFF\x00\xFF\x00\xFF\xFF", + "\x00\x00\xFF\x00\xFF\xFF\x00\x00", "\x00\x00\xFF\x00\xFF\xFF\x00\xFF", + "\x00\x00\xFF\x00\xFF\xFF\xFF\x00", "\x00\x00\xFF\x00\xFF\xFF\xFF\xFF", + "\x00\x00\xFF\xFF\x00\x00\x00\x00", "\x00\x00\xFF\xFF\x00\x00\x00\xFF", + "\x00\x00\xFF\xFF\x00\x00\xFF\x00", "\x00\x00\xFF\xFF\x00\x00\xFF\xFF", + "\x00\x00\xFF\xFF\x00\xFF\x00\x00", "\x00\x00\xFF\xFF\x00\xFF\x00\xFF", + "\x00\x00\xFF\xFF\x00\xFF\xFF\x00", "\x00\x00\xFF\xFF\x00\xFF\xFF\xFF", + "\x00\x00\xFF\xFF\xFF\x00\x00\x00", "\x00\x00\xFF\xFF\xFF\x00\x00\xFF", + "\x00\x00\xFF\xFF\xFF\x00\xFF\x00", "\x00\x00\xFF\xFF\xFF\x00\xFF\xFF", + "\x00\x00\xFF\xFF\xFF\xFF\x00\x00", "\x00\x00\xFF\xFF\xFF\xFF\x00\xFF", + "\x00\x00\xFF\xFF\xFF\xFF\xFF\x00", "\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF", + "\x00\xFF\x00\x00\x00\x00\x00\x00", "\x00\xFF\x00\x00\x00\x00\x00\xFF", + "\x00\xFF\x00\x00\x00\x00\xFF\x00", "\x00\xFF\x00\x00\x00\x00\xFF\xFF", + "\x00\xFF\x00\x00\x00\xFF\x00\x00", "\x00\xFF\x00\x00\x00\xFF\x00\xFF", + "\x00\xFF\x00\x00\x00\xFF\xFF\x00", "\x00\xFF\x00\x00\x00\xFF\xFF\xFF", + "\x00\xFF\x00\x00\xFF\x00\x00\x00", "\x00\xFF\x00\x00\xFF\x00\x00\xFF", + "\x00\xFF\x00\x00\xFF\x00\xFF\x00", "\x00\xFF\x00\x00\xFF\x00\xFF\xFF", + "\x00\xFF\x00\x00\xFF\xFF\x00\x00", "\x00\xFF\x00\x00\xFF\xFF\x00\xFF", + "\x00\xFF\x00\x00\xFF\xFF\xFF\x00", "\x00\xFF\x00\x00\xFF\xFF\xFF\xFF", + "\x00\xFF\x00\xFF\x00\x00\x00\x00", "\x00\xFF\x00\xFF\x00\x00\x00\xFF", + "\x00\xFF\x00\xFF\x00\x00\xFF\x00", "\x00\xFF\x00\xFF\x00\x00\xFF\xFF", + "\x00\xFF\x00\xFF\x00\xFF\x00\x00", "\x00\xFF\x00\xFF\x00\xFF\x00\xFF", + "\x00\xFF\x00\xFF\x00\xFF\xFF\x00", "\x00\xFF\x00\xFF\x00\xFF\xFF\xFF", + "\x00\xFF\x00\xFF\xFF\x00\x00\x00", "\x00\xFF\x00\xFF\xFF\x00\x00\xFF", + "\x00\xFF\x00\xFF\xFF\x00\xFF\x00", "\x00\xFF\x00\xFF\xFF\x00\xFF\xFF", + "\x00\xFF\x00\xFF\xFF\xFF\x00\x00", "\x00\xFF\x00\xFF\xFF\xFF\x00\xFF", + "\x00\xFF\x00\xFF\xFF\xFF\xFF\x00", "\x00\xFF\x00\xFF\xFF\xFF\xFF\xFF", + "\x00\xFF\xFF\x00\x00\x00\x00\x00", "\x00\xFF\xFF\x00\x00\x00\x00\xFF", + "\x00\xFF\xFF\x00\x00\x00\xFF\x00", "\x00\xFF\xFF\x00\x00\x00\xFF\xFF", + "\x00\xFF\xFF\x00\x00\xFF\x00\x00", "\x00\xFF\xFF\x00\x00\xFF\x00\xFF", + "\x00\xFF\xFF\x00\x00\xFF\xFF\x00", "\x00\xFF\xFF\x00\x00\xFF\xFF\xFF", + "\x00\xFF\xFF\x00\xFF\x00\x00\x00", "\x00\xFF\xFF\x00\xFF\x00\x00\xFF", + "\x00\xFF\xFF\x00\xFF\x00\xFF\x00", "\x00\xFF\xFF\x00\xFF\x00\xFF\xFF", + "\x00\xFF\xFF\x00\xFF\xFF\x00\x00", "\x00\xFF\xFF\x00\xFF\xFF\x00\xFF", + "\x00\xFF\xFF\x00\xFF\xFF\xFF\x00", "\x00\xFF\xFF\x00\xFF\xFF\xFF\xFF", + "\x00\xFF\xFF\xFF\x00\x00\x00\x00", "\x00\xFF\xFF\xFF\x00\x00\x00\xFF", + "\x00\xFF\xFF\xFF\x00\x00\xFF\x00", "\x00\xFF\xFF\xFF\x00\x00\xFF\xFF", + "\x00\xFF\xFF\xFF\x00\xFF\x00\x00", "\x00\xFF\xFF\xFF\x00\xFF\x00\xFF", + "\x00\xFF\xFF\xFF\x00\xFF\xFF\x00", "\x00\xFF\xFF\xFF\x00\xFF\xFF\xFF", + "\x00\xFF\xFF\xFF\xFF\x00\x00\x00", "\x00\xFF\xFF\xFF\xFF\x00\x00\xFF", + "\x00\xFF\xFF\xFF\xFF\x00\xFF\x00", "\x00\xFF\xFF\xFF\xFF\x00\xFF\xFF", + "\x00\xFF\xFF\xFF\xFF\xFF\x00\x00", "\x00\xFF\xFF\xFF\xFF\xFF\x00\xFF", + "\x00\xFF\xFF\xFF\xFF\xFF\xFF\x00", "\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF", + "\xFF\x00\x00\x00\x00\x00\x00\x00", "\xFF\x00\x00\x00\x00\x00\x00\xFF", + "\xFF\x00\x00\x00\x00\x00\xFF\x00", "\xFF\x00\x00\x00\x00\x00\xFF\xFF", + "\xFF\x00\x00\x00\x00\xFF\x00\x00", "\xFF\x00\x00\x00\x00\xFF\x00\xFF", + "\xFF\x00\x00\x00\x00\xFF\xFF\x00", "\xFF\x00\x00\x00\x00\xFF\xFF\xFF", + "\xFF\x00\x00\x00\xFF\x00\x00\x00", "\xFF\x00\x00\x00\xFF\x00\x00\xFF", + "\xFF\x00\x00\x00\xFF\x00\xFF\x00", "\xFF\x00\x00\x00\xFF\x00\xFF\xFF", + "\xFF\x00\x00\x00\xFF\xFF\x00\x00", "\xFF\x00\x00\x00\xFF\xFF\x00\xFF", + "\xFF\x00\x00\x00\xFF\xFF\xFF\x00", "\xFF\x00\x00\x00\xFF\xFF\xFF\xFF", + "\xFF\x00\x00\xFF\x00\x00\x00\x00", "\xFF\x00\x00\xFF\x00\x00\x00\xFF", + "\xFF\x00\x00\xFF\x00\x00\xFF\x00", "\xFF\x00\x00\xFF\x00\x00\xFF\xFF", + "\xFF\x00\x00\xFF\x00\xFF\x00\x00", "\xFF\x00\x00\xFF\x00\xFF\x00\xFF", + "\xFF\x00\x00\xFF\x00\xFF\xFF\x00", "\xFF\x00\x00\xFF\x00\xFF\xFF\xFF", + "\xFF\x00\x00\xFF\xFF\x00\x00\x00", "\xFF\x00\x00\xFF\xFF\x00\x00\xFF", + "\xFF\x00\x00\xFF\xFF\x00\xFF\x00", "\xFF\x00\x00\xFF\xFF\x00\xFF\xFF", + "\xFF\x00\x00\xFF\xFF\xFF\x00\x00", "\xFF\x00\x00\xFF\xFF\xFF\x00\xFF", + "\xFF\x00\x00\xFF\xFF\xFF\xFF\x00", "\xFF\x00\x00\xFF\xFF\xFF\xFF\xFF", + "\xFF\x00\xFF\x00\x00\x00\x00\x00", "\xFF\x00\xFF\x00\x00\x00\x00\xFF", + "\xFF\x00\xFF\x00\x00\x00\xFF\x00", "\xFF\x00\xFF\x00\x00\x00\xFF\xFF", + "\xFF\x00\xFF\x00\x00\xFF\x00\x00", "\xFF\x00\xFF\x00\x00\xFF\x00\xFF", + "\xFF\x00\xFF\x00\x00\xFF\xFF\x00", "\xFF\x00\xFF\x00\x00\xFF\xFF\xFF", + "\xFF\x00\xFF\x00\xFF\x00\x00\x00", "\xFF\x00\xFF\x00\xFF\x00\x00\xFF", + "\xFF\x00\xFF\x00\xFF\x00\xFF\x00", "\xFF\x00\xFF\x00\xFF\x00\xFF\xFF", + "\xFF\x00\xFF\x00\xFF\xFF\x00\x00", "\xFF\x00\xFF\x00\xFF\xFF\x00\xFF", + "\xFF\x00\xFF\x00\xFF\xFF\xFF\x00", "\xFF\x00\xFF\x00\xFF\xFF\xFF\xFF", + "\xFF\x00\xFF\xFF\x00\x00\x00\x00", "\xFF\x00\xFF\xFF\x00\x00\x00\xFF", + "\xFF\x00\xFF\xFF\x00\x00\xFF\x00", "\xFF\x00\xFF\xFF\x00\x00\xFF\xFF", + "\xFF\x00\xFF\xFF\x00\xFF\x00\x00", "\xFF\x00\xFF\xFF\x00\xFF\x00\xFF", + "\xFF\x00\xFF\xFF\x00\xFF\xFF\x00", "\xFF\x00\xFF\xFF\x00\xFF\xFF\xFF", + "\xFF\x00\xFF\xFF\xFF\x00\x00\x00", "\xFF\x00\xFF\xFF\xFF\x00\x00\xFF", + "\xFF\x00\xFF\xFF\xFF\x00\xFF\x00", "\xFF\x00\xFF\xFF\xFF\x00\xFF\xFF", + "\xFF\x00\xFF\xFF\xFF\xFF\x00\x00", "\xFF\x00\xFF\xFF\xFF\xFF\x00\xFF", + "\xFF\x00\xFF\xFF\xFF\xFF\xFF\x00", "\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF", + "\xFF\xFF\x00\x00\x00\x00\x00\x00", "\xFF\xFF\x00\x00\x00\x00\x00\xFF", + "\xFF\xFF\x00\x00\x00\x00\xFF\x00", "\xFF\xFF\x00\x00\x00\x00\xFF\xFF", + "\xFF\xFF\x00\x00\x00\xFF\x00\x00", "\xFF\xFF\x00\x00\x00\xFF\x00\xFF", + "\xFF\xFF\x00\x00\x00\xFF\xFF\x00", "\xFF\xFF\x00\x00\x00\xFF\xFF\xFF", + "\xFF\xFF\x00\x00\xFF\x00\x00\x00", "\xFF\xFF\x00\x00\xFF\x00\x00\xFF", + "\xFF\xFF\x00\x00\xFF\x00\xFF\x00", "\xFF\xFF\x00\x00\xFF\x00\xFF\xFF", + "\xFF\xFF\x00\x00\xFF\xFF\x00\x00", "\xFF\xFF\x00\x00\xFF\xFF\x00\xFF", + "\xFF\xFF\x00\x00\xFF\xFF\xFF\x00", "\xFF\xFF\x00\x00\xFF\xFF\xFF\xFF", + "\xFF\xFF\x00\xFF\x00\x00\x00\x00", "\xFF\xFF\x00\xFF\x00\x00\x00\xFF", + "\xFF\xFF\x00\xFF\x00\x00\xFF\x00", "\xFF\xFF\x00\xFF\x00\x00\xFF\xFF", + "\xFF\xFF\x00\xFF\x00\xFF\x00\x00", "\xFF\xFF\x00\xFF\x00\xFF\x00\xFF", + "\xFF\xFF\x00\xFF\x00\xFF\xFF\x00", "\xFF\xFF\x00\xFF\x00\xFF\xFF\xFF", + "\xFF\xFF\x00\xFF\xFF\x00\x00\x00", "\xFF\xFF\x00\xFF\xFF\x00\x00\xFF", + "\xFF\xFF\x00\xFF\xFF\x00\xFF\x00", "\xFF\xFF\x00\xFF\xFF\x00\xFF\xFF", + "\xFF\xFF\x00\xFF\xFF\xFF\x00\x00", "\xFF\xFF\x00\xFF\xFF\xFF\x00\xFF", + "\xFF\xFF\x00\xFF\xFF\xFF\xFF\x00", "\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF", + "\xFF\xFF\xFF\x00\x00\x00\x00\x00", "\xFF\xFF\xFF\x00\x00\x00\x00\xFF", + "\xFF\xFF\xFF\x00\x00\x00\xFF\x00", "\xFF\xFF\xFF\x00\x00\x00\xFF\xFF", + "\xFF\xFF\xFF\x00\x00\xFF\x00\x00", "\xFF\xFF\xFF\x00\x00\xFF\x00\xFF", + "\xFF\xFF\xFF\x00\x00\xFF\xFF\x00", "\xFF\xFF\xFF\x00\x00\xFF\xFF\xFF", + "\xFF\xFF\xFF\x00\xFF\x00\x00\x00", "\xFF\xFF\xFF\x00\xFF\x00\x00\xFF", + "\xFF\xFF\xFF\x00\xFF\x00\xFF\x00", "\xFF\xFF\xFF\x00\xFF\x00\xFF\xFF", + "\xFF\xFF\xFF\x00\xFF\xFF\x00\x00", "\xFF\xFF\xFF\x00\xFF\xFF\x00\xFF", + "\xFF\xFF\xFF\x00\xFF\xFF\xFF\x00", "\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF", + "\xFF\xFF\xFF\xFF\x00\x00\x00\x00", "\xFF\xFF\xFF\xFF\x00\x00\x00\xFF", + "\xFF\xFF\xFF\xFF\x00\x00\xFF\x00", "\xFF\xFF\xFF\xFF\x00\x00\xFF\xFF", + "\xFF\xFF\xFF\xFF\x00\xFF\x00\x00", "\xFF\xFF\xFF\xFF\x00\xFF\x00\xFF", + "\xFF\xFF\xFF\xFF\x00\xFF\xFF\x00", "\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF", + "\xFF\xFF\xFF\xFF\xFF\x00\x00\x00", "\xFF\xFF\xFF\xFF\xFF\x00\x00\xFF", + "\xFF\xFF\xFF\xFF\xFF\x00\xFF\x00", "\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF", + "\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00", "\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF", + "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00", "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" + ); /** - * mcrypt resource for CFB mode + * IP mapping helper table. * - * @see Crypt_DES::encrypt() - * @see Crypt_DES::decrypt() - * @var String + * Indexing this table with each source byte performs the initial bit permutation. + * + * @var Array * @access private */ - var $ecb; + var $ipmap = array( + 0x00, 0x10, 0x01, 0x11, 0x20, 0x30, 0x21, 0x31, + 0x02, 0x12, 0x03, 0x13, 0x22, 0x32, 0x23, 0x33, + 0x40, 0x50, 0x41, 0x51, 0x60, 0x70, 0x61, 0x71, + 0x42, 0x52, 0x43, 0x53, 0x62, 0x72, 0x63, 0x73, + 0x04, 0x14, 0x05, 0x15, 0x24, 0x34, 0x25, 0x35, + 0x06, 0x16, 0x07, 0x17, 0x26, 0x36, 0x27, 0x37, + 0x44, 0x54, 0x45, 0x55, 0x64, 0x74, 0x65, 0x75, + 0x46, 0x56, 0x47, 0x57, 0x66, 0x76, 0x67, 0x77, + 0x80, 0x90, 0x81, 0x91, 0xA0, 0xB0, 0xA1, 0xB1, + 0x82, 0x92, 0x83, 0x93, 0xA2, 0xB2, 0xA3, 0xB3, + 0xC0, 0xD0, 0xC1, 0xD1, 0xE0, 0xF0, 0xE1, 0xF1, + 0xC2, 0xD2, 0xC3, 0xD3, 0xE2, 0xF2, 0xE3, 0xF3, + 0x84, 0x94, 0x85, 0x95, 0xA4, 0xB4, 0xA5, 0xB5, + 0x86, 0x96, 0x87, 0x97, 0xA6, 0xB6, 0xA7, 0xB7, + 0xC4, 0xD4, 0xC5, 0xD5, 0xE4, 0xF4, 0xE5, 0xF5, + 0xC6, 0xD6, 0xC7, 0xD7, 0xE6, 0xF6, 0xE7, 0xF7, + 0x08, 0x18, 0x09, 0x19, 0x28, 0x38, 0x29, 0x39, + 0x0A, 0x1A, 0x0B, 0x1B, 0x2A, 0x3A, 0x2B, 0x3B, + 0x48, 0x58, 0x49, 0x59, 0x68, 0x78, 0x69, 0x79, + 0x4A, 0x5A, 0x4B, 0x5B, 0x6A, 0x7A, 0x6B, 0x7B, + 0x0C, 0x1C, 0x0D, 0x1D, 0x2C, 0x3C, 0x2D, 0x3D, + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4C, 0x5C, 0x4D, 0x5D, 0x6C, 0x7C, 0x6D, 0x7D, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x88, 0x98, 0x89, 0x99, 0xA8, 0xB8, 0xA9, 0xB9, + 0x8A, 0x9A, 0x8B, 0x9B, 0xAA, 0xBA, 0xAB, 0xBB, + 0xC8, 0xD8, 0xC9, 0xD9, 0xE8, 0xF8, 0xE9, 0xF9, + 0xCA, 0xDA, 0xCB, 0xDB, 0xEA, 0xFA, 0xEB, 0xFB, + 0x8C, 0x9C, 0x8D, 0x9D, 0xAC, 0xBC, 0xAD, 0xBD, + 0x8E, 0x9E, 0x8F, 0x9F, 0xAE, 0xBE, 0xAF, 0xBF, + 0xCC, 0xDC, 0xCD, 0xDD, 0xEC, 0xFC, 0xED, 0xFD, + 0xCE, 0xDE, 0xCF, 0xDF, 0xEE, 0xFE, 0xEF, 0xFF + ); + + /** + * Inverse IP mapping helper table. + * Indexing this table with a byte value reverses the bit order. + * + * @var Array + * @access private + */ + var $invipmap = array( + 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, + 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0, + 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, + 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8, + 0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, + 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4, + 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, + 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC, + 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, + 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2, + 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, + 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA, + 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, + 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6, + 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, + 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE, + 0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1, + 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1, + 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, + 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9, + 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, + 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5, + 0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, + 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD, + 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, + 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3, + 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, + 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB, + 0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, + 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7, + 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, + 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF + ); + + /** + * Pre-permuted S-box1 + * + * Each box ($sbox1-$sbox8) has been vectorized, then each value pre-permuted using the + * P table: concatenation can then be replaced by exclusive ORs. + * + * @var Array + * @access private + */ + var $sbox1 = array( + 0x00808200, 0x00000000, 0x00008000, 0x00808202, + 0x00808002, 0x00008202, 0x00000002, 0x00008000, + 0x00000200, 0x00808200, 0x00808202, 0x00000200, + 0x00800202, 0x00808002, 0x00800000, 0x00000002, + 0x00000202, 0x00800200, 0x00800200, 0x00008200, + 0x00008200, 0x00808000, 0x00808000, 0x00800202, + 0x00008002, 0x00800002, 0x00800002, 0x00008002, + 0x00000000, 0x00000202, 0x00008202, 0x00800000, + 0x00008000, 0x00808202, 0x00000002, 0x00808000, + 0x00808200, 0x00800000, 0x00800000, 0x00000200, + 0x00808002, 0x00008000, 0x00008200, 0x00800002, + 0x00000200, 0x00000002, 0x00800202, 0x00008202, + 0x00808202, 0x00008002, 0x00808000, 0x00800202, + 0x00800002, 0x00000202, 0x00008202, 0x00808200, + 0x00000202, 0x00800200, 0x00800200, 0x00000000, + 0x00008002, 0x00008200, 0x00000000, 0x00808002 + ); + + /** + * Pre-permuted S-box2 + * + * @var Array + * @access private + */ + var $sbox2 = array( + 0x40084010, 0x40004000, 0x00004000, 0x00084010, + 0x00080000, 0x00000010, 0x40080010, 0x40004010, + 0x40000010, 0x40084010, 0x40084000, 0x40000000, + 0x40004000, 0x00080000, 0x00000010, 0x40080010, + 0x00084000, 0x00080010, 0x40004010, 0x00000000, + 0x40000000, 0x00004000, 0x00084010, 0x40080000, + 0x00080010, 0x40000010, 0x00000000, 0x00084000, + 0x00004010, 0x40084000, 0x40080000, 0x00004010, + 0x00000000, 0x00084010, 0x40080010, 0x00080000, + 0x40004010, 0x40080000, 0x40084000, 0x00004000, + 0x40080000, 0x40004000, 0x00000010, 0x40084010, + 0x00084010, 0x00000010, 0x00004000, 0x40000000, + 0x00004010, 0x40084000, 0x00080000, 0x40000010, + 0x00080010, 0x40004010, 0x40000010, 0x00080010, + 0x00084000, 0x00000000, 0x40004000, 0x00004010, + 0x40000000, 0x40080010, 0x40084010, 0x00084000 + ); + + /** + * Pre-permuted S-box3 + * + * @var Array + * @access private + */ + var $sbox3 = array( + 0x00000104, 0x04010100, 0x00000000, 0x04010004, + 0x04000100, 0x00000000, 0x00010104, 0x04000100, + 0x00010004, 0x04000004, 0x04000004, 0x00010000, + 0x04010104, 0x00010004, 0x04010000, 0x00000104, + 0x04000000, 0x00000004, 0x04010100, 0x00000100, + 0x00010100, 0x04010000, 0x04010004, 0x00010104, + 0x04000104, 0x00010100, 0x00010000, 0x04000104, + 0x00000004, 0x04010104, 0x00000100, 0x04000000, + 0x04010100, 0x04000000, 0x00010004, 0x00000104, + 0x00010000, 0x04010100, 0x04000100, 0x00000000, + 0x00000100, 0x00010004, 0x04010104, 0x04000100, + 0x04000004, 0x00000100, 0x00000000, 0x04010004, + 0x04000104, 0x00010000, 0x04000000, 0x04010104, + 0x00000004, 0x00010104, 0x00010100, 0x04000004, + 0x04010000, 0x04000104, 0x00000104, 0x04010000, + 0x00010104, 0x00000004, 0x04010004, 0x00010100 + ); + + /** + * Pre-permuted S-box4 + * + * @var Array + * @access private + */ + var $sbox4 = array( + 0x80401000, 0x80001040, 0x80001040, 0x00000040, + 0x00401040, 0x80400040, 0x80400000, 0x80001000, + 0x00000000, 0x00401000, 0x00401000, 0x80401040, + 0x80000040, 0x00000000, 0x00400040, 0x80400000, + 0x80000000, 0x00001000, 0x00400000, 0x80401000, + 0x00000040, 0x00400000, 0x80001000, 0x00001040, + 0x80400040, 0x80000000, 0x00001040, 0x00400040, + 0x00001000, 0x00401040, 0x80401040, 0x80000040, + 0x00400040, 0x80400000, 0x00401000, 0x80401040, + 0x80000040, 0x00000000, 0x00000000, 0x00401000, + 0x00001040, 0x00400040, 0x80400040, 0x80000000, + 0x80401000, 0x80001040, 0x80001040, 0x00000040, + 0x80401040, 0x80000040, 0x80000000, 0x00001000, + 0x80400000, 0x80001000, 0x00401040, 0x80400040, + 0x80001000, 0x00001040, 0x00400000, 0x80401000, + 0x00000040, 0x00400000, 0x00001000, 0x00401040 + ); + + /** + * Pre-permuted S-box5 + * + * @var Array + * @access private + */ + var $sbox5 = array( + 0x00000080, 0x01040080, 0x01040000, 0x21000080, + 0x00040000, 0x00000080, 0x20000000, 0x01040000, + 0x20040080, 0x00040000, 0x01000080, 0x20040080, + 0x21000080, 0x21040000, 0x00040080, 0x20000000, + 0x01000000, 0x20040000, 0x20040000, 0x00000000, + 0x20000080, 0x21040080, 0x21040080, 0x01000080, + 0x21040000, 0x20000080, 0x00000000, 0x21000000, + 0x01040080, 0x01000000, 0x21000000, 0x00040080, + 0x00040000, 0x21000080, 0x00000080, 0x01000000, + 0x20000000, 0x01040000, 0x21000080, 0x20040080, + 0x01000080, 0x20000000, 0x21040000, 0x01040080, + 0x20040080, 0x00000080, 0x01000000, 0x21040000, + 0x21040080, 0x00040080, 0x21000000, 0x21040080, + 0x01040000, 0x00000000, 0x20040000, 0x21000000, + 0x00040080, 0x01000080, 0x20000080, 0x00040000, + 0x00000000, 0x20040000, 0x01040080, 0x20000080 + ); + + /** + * Pre-permuted S-box6 + * + * @var Array + * @access private + */ + var $sbox6 = array( + 0x10000008, 0x10200000, 0x00002000, 0x10202008, + 0x10200000, 0x00000008, 0x10202008, 0x00200000, + 0x10002000, 0x00202008, 0x00200000, 0x10000008, + 0x00200008, 0x10002000, 0x10000000, 0x00002008, + 0x00000000, 0x00200008, 0x10002008, 0x00002000, + 0x00202000, 0x10002008, 0x00000008, 0x10200008, + 0x10200008, 0x00000000, 0x00202008, 0x10202000, + 0x00002008, 0x00202000, 0x10202000, 0x10000000, + 0x10002000, 0x00000008, 0x10200008, 0x00202000, + 0x10202008, 0x00200000, 0x00002008, 0x10000008, + 0x00200000, 0x10002000, 0x10000000, 0x00002008, + 0x10000008, 0x10202008, 0x00202000, 0x10200000, + 0x00202008, 0x10202000, 0x00000000, 0x10200008, + 0x00000008, 0x00002000, 0x10200000, 0x00202008, + 0x00002000, 0x00200008, 0x10002008, 0x00000000, + 0x10202000, 0x10000000, 0x00200008, 0x10002008 + ); + + /** + * Pre-permuted S-box7 + * + * @var Array + * @access private + */ + var $sbox7 = array( + 0x00100000, 0x02100001, 0x02000401, 0x00000000, + 0x00000400, 0x02000401, 0x00100401, 0x02100400, + 0x02100401, 0x00100000, 0x00000000, 0x02000001, + 0x00000001, 0x02000000, 0x02100001, 0x00000401, + 0x02000400, 0x00100401, 0x00100001, 0x02000400, + 0x02000001, 0x02100000, 0x02100400, 0x00100001, + 0x02100000, 0x00000400, 0x00000401, 0x02100401, + 0x00100400, 0x00000001, 0x02000000, 0x00100400, + 0x02000000, 0x00100400, 0x00100000, 0x02000401, + 0x02000401, 0x02100001, 0x02100001, 0x00000001, + 0x00100001, 0x02000000, 0x02000400, 0x00100000, + 0x02100400, 0x00000401, 0x00100401, 0x02100400, + 0x00000401, 0x02000001, 0x02100401, 0x02100000, + 0x00100400, 0x00000000, 0x00000001, 0x02100401, + 0x00000000, 0x00100401, 0x02100000, 0x00000400, + 0x02000001, 0x02000400, 0x00000400, 0x00100001 + ); + + /** + * Pre-permuted S-box8 + * + * @var Array + * @access private + */ + var $sbox8 = array( + 0x08000820, 0x00000800, 0x00020000, 0x08020820, + 0x08000000, 0x08000820, 0x00000020, 0x08000000, + 0x00020020, 0x08020000, 0x08020820, 0x00020800, + 0x08020800, 0x00020820, 0x00000800, 0x00000020, + 0x08020000, 0x08000020, 0x08000800, 0x00000820, + 0x00020800, 0x00020020, 0x08020020, 0x08020800, + 0x00000820, 0x00000000, 0x00000000, 0x08020020, + 0x08000020, 0x08000800, 0x00020820, 0x00020000, + 0x00020820, 0x00020000, 0x08020800, 0x00000800, + 0x00000020, 0x08020020, 0x00000800, 0x00020820, + 0x08000800, 0x00000020, 0x08000020, 0x08020000, + 0x08020020, 0x08000000, 0x00020000, 0x08000820, + 0x00000000, 0x08020820, 0x00020020, 0x08000020, + 0x08020000, 0x08000800, 0x08000820, 0x00000000, + 0x08020820, 0x00020800, 0x00020800, 0x00000820, + 0x00000820, 0x00020020, 0x08000000, 0x08020800 + ); /** * Default Constructor. * - * Determines whether or not the mcrypt extension should be used. $mode should only, at present, be - * CRYPT_DES_MODE_ECB or CRYPT_DES_MODE_CBC. If not explictly set, CRYPT_DES_MODE_CBC will be used. + * Determines whether or not the mcrypt extension should be used. * + * $mode could be: + * + * - CRYPT_DES_MODE_ECB + * + * - CRYPT_DES_MODE_CBC + * + * - CRYPT_DES_MODE_CTR + * + * - CRYPT_DES_MODE_CFB + * + * - CRYPT_DES_MODE_OFB + * + * If not explictly set, CRYPT_DES_MODE_CBC will be used. + * + * @see Crypt_Base::Crypt_Base() * @param optional Integer $mode - * @return Crypt_DES * @access public */ function Crypt_DES($mode = CRYPT_DES_MODE_CBC) { - if ( !defined('CRYPT_DES_MODE') ) { - switch (true) { - case extension_loaded('mcrypt') && in_array('des', mcrypt_list_algorithms()): - define('CRYPT_DES_MODE', CRYPT_DES_MODE_MCRYPT); - break; - default: - define('CRYPT_DES_MODE', CRYPT_DES_MODE_INTERNAL); - } - } - - switch ( CRYPT_DES_MODE ) { - case CRYPT_DES_MODE_MCRYPT: - switch ($mode) { - case CRYPT_DES_MODE_ECB: - $this->paddable = true; - $this->mode = MCRYPT_MODE_ECB; - break; - case CRYPT_DES_MODE_CTR: - $this->mode = 'ctr'; - //$this->mode = in_array('ctr', mcrypt_list_modes()) ? 'ctr' : CRYPT_DES_MODE_CTR; - break; - case CRYPT_DES_MODE_CFB: - $this->mode = 'ncfb'; - $this->ecb = mcrypt_module_open(MCRYPT_DES, '', MCRYPT_MODE_ECB, ''); - break; - case CRYPT_DES_MODE_OFB: - $this->mode = MCRYPT_MODE_NOFB; - break; - case CRYPT_DES_MODE_CBC: - default: - $this->paddable = true; - $this->mode = MCRYPT_MODE_CBC; - } - $this->enmcrypt = mcrypt_module_open(MCRYPT_DES, '', $this->mode, ''); - $this->demcrypt = mcrypt_module_open(MCRYPT_DES, '', $this->mode, ''); - - break; - default: - switch ($mode) { - case CRYPT_DES_MODE_ECB: - case CRYPT_DES_MODE_CBC: - $this->paddable = true; - $this->mode = $mode; - break; - case CRYPT_DES_MODE_CTR: - case CRYPT_DES_MODE_CFB: - case CRYPT_DES_MODE_OFB: - $this->mode = $mode; - break; - default: - $this->paddable = true; - $this->mode = CRYPT_DES_MODE_CBC; - } - } + parent::Crypt_Base($mode); } /** @@ -360,653 +701,50 @@ class Crypt_DES { * * If the key is not explicitly set, it'll be assumed to be all zero's. * + * @see Crypt_Base::setKey() * @access public * @param String $key */ function setKey($key) { - $this->keys = ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) ? str_pad(substr($key, 0, 8), 8, chr(0)) : $this->_prepareKey($key); - $this->enchanged = true; - $this->dechanged = true; - } - - /** - * Sets the password. - * - * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows: - * {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2}: - * $hash, $salt, $count - * - * @param String $password - * @param optional String $method - * @access public - */ - function setPassword($password, $method = 'pbkdf2') - { - $key = ''; - - switch ($method) { - default: // 'pbkdf2' - list(, , $hash, $salt, $count) = func_get_args(); - if (!isset($hash)) { - $hash = 'sha1'; - } - // WPA and WPA2 use the SSID as the salt - if (!isset($salt)) { - $salt = 'phpseclib/salt'; - } - // RFC2898#section-4.2 uses 1,000 iterations by default - // WPA and WPA2 use 4,096. - if (!isset($count)) { - $count = 1000; - } - - if (!class_exists('Crypt_Hash')) { - require_once('Crypt/Hash.php'); - } - - $i = 1; - while (strlen($key) < 8) { // $dkLen == 8 - //$dk.= $this->_pbkdf($password, $salt, $count, $i++); - $hmac = new Crypt_Hash(); - $hmac->setHash($hash); - $hmac->setKey($password); - $f = $u = $hmac->hash($salt . pack('N', $i++)); - for ($j = 2; $j <= $count; $j++) { - $u = $hmac->hash($u); - $f^= $u; - } - $key.= $f; - } + // We check/cut here only up to max length of the key. + // Key padding to the proper length will be done in _setupKey() + if (strlen($key) > $this->key_size_max) { + $key = substr($key, 0, $this->key_size_max); } - $this->setKey($key); + // Sets the key + parent::setKey($key); } /** - * Sets the initialization vector. (optional) + * Encrypts a block * - * SetIV is not required when CRYPT_DES_MODE_ECB is being used. If not explictly set, it'll be assumed - * to be all zero's. - * - * @access public - * @param String $iv - */ - function setIV($iv) - { - $this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($iv, 0, 8), 8, chr(0)); - $this->enchanged = true; - $this->dechanged = true; - } - - /** - * Generate CTR XOR encryption key - * - * Encrypt the output of this and XOR it against the ciphertext / plaintext to get the - * plaintext / ciphertext in CTR mode. - * - * @see Crypt_DES::decrypt() + * @see Crypt_Base::_encryptBlock() + * @see Crypt_Base::encrypt() * @see Crypt_DES::encrypt() - * @access public - * @param String $iv + * @access private + * @param String $in + * @return String */ - function _generate_xor(&$iv) + function _encryptBlock($in) { - $xor = $iv; - for ($j = 4; $j <= 8; $j+=4) { - $temp = substr($iv, -$j, 4); - switch ($temp) { - case "\xFF\xFF\xFF\xFF": - $iv = substr_replace($iv, "\x00\x00\x00\x00", -$j, 4); - break; - case "\x7F\xFF\xFF\xFF": - $iv = substr_replace($iv, "\x80\x00\x00\x00", -$j, 4); - break 2; - default: - extract(unpack('Ncount', $temp)); - $iv = substr_replace($iv, pack('N', $count + 1), -$j, 4); - break 2; - } - } - - return $xor; + return $this->_processBlock($in, CRYPT_DES_ENCRYPT); } /** - * Encrypts a message. - * - * $plaintext will be padded with up to 8 additional bytes. Other DES implementations may or may not pad in the - * same manner. Other common approaches to padding and the reasons why it's necessary are discussed in the following - * URL: - * - * {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html} - * - * An alternative to padding is to, separately, send the length of the file. This is what SSH, in fact, does. - * strlen($plaintext) will still need to be a multiple of 8, however, arbitrary values can be added to make it that - * length. + * Decrypts a block * + * @see Crypt_Base::_decryptBlock() + * @see Crypt_Base::decrypt() * @see Crypt_DES::decrypt() - * @access public - * @param String $plaintext - */ - function encrypt($plaintext) - { - if ($this->paddable) { - $plaintext = $this->_pad($plaintext); - } - - if ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) { - if ($this->enchanged) { - mcrypt_generic_init($this->enmcrypt, $this->keys, $this->encryptIV); - if ($this->mode == 'ncfb') { - mcrypt_generic_init($this->ecb, $this->keys, "\0\0\0\0\0\0\0\0"); - } - $this->enchanged = false; - } - - if ($this->mode != 'ncfb' || !$this->continuousBuffer) { - $ciphertext = mcrypt_generic($this->enmcrypt, $plaintext); - } else { - $iv = &$this->encryptIV; - $pos = &$this->enbuffer['pos']; - $len = strlen($plaintext); - $ciphertext = ''; - $i = 0; - if ($pos) { - $orig_pos = $pos; - $max = 8 - $pos; - if ($len >= $max) { - $i = $max; - $len-= $max; - $pos = 0; - } else { - $i = $len; - $pos+= $len; - $len = 0; - } - $ciphertext = substr($iv, $orig_pos) ^ $plaintext; - $iv = substr_replace($iv, $ciphertext, $orig_pos, $i); - $this->enbuffer['enmcrypt_init'] = true; - } - if ($len >= 8) { - if ($this->enbuffer['enmcrypt_init'] === false || $len > 600) { - if ($this->enbuffer['enmcrypt_init'] === true) { - mcrypt_generic_init($this->enmcrypt, $this->keys, $iv); - $this->enbuffer['enmcrypt_init'] = false; - } - $ciphertext.= mcrypt_generic($this->enmcrypt, substr($plaintext, $i, $len - $len % 8)); - $iv = substr($ciphertext, -8); - $len%= 8; - } else { - while ($len >= 8) { - $iv = mcrypt_generic($this->ecb, $iv) ^ substr($plaintext, $i, 8); - $ciphertext.= $iv; - $len-= 8; - $i+= 8; - } - } - } - if ($len) { - $iv = mcrypt_generic($this->ecb, $iv); - $block = $iv ^ substr($plaintext, -$len); - $iv = substr_replace($iv, $block, 0, $len); - $ciphertext.= $block; - $pos = $len; - } - return $ciphertext; - } - - if (!$this->continuousBuffer) { - mcrypt_generic_init($this->enmcrypt, $this->keys, $this->encryptIV); - } - - return $ciphertext; - } - - if (!is_array($this->keys)) { - $this->keys = $this->_prepareKey("\0\0\0\0\0\0\0\0"); - } - - $buffer = &$this->enbuffer; - $continuousBuffer = $this->continuousBuffer; - $ciphertext = ''; - switch ($this->mode) { - case CRYPT_DES_MODE_ECB: - for ($i = 0; $i < strlen($plaintext); $i+=8) { - $ciphertext.= $this->_processBlock(substr($plaintext, $i, 8), CRYPT_DES_ENCRYPT); - } - break; - case CRYPT_DES_MODE_CBC: - $xor = $this->encryptIV; - for ($i = 0; $i < strlen($plaintext); $i+=8) { - $block = substr($plaintext, $i, 8); - $block = $this->_processBlock($block ^ $xor, CRYPT_DES_ENCRYPT); - $xor = $block; - $ciphertext.= $block; - } - if ($this->continuousBuffer) { - $this->encryptIV = $xor; - } - break; - case CRYPT_DES_MODE_CTR: - $xor = $this->encryptIV; - if (strlen($buffer['encrypted'])) { - for ($i = 0; $i < strlen($plaintext); $i+=8) { - $block = substr($plaintext, $i, 8); - $buffer['encrypted'].= $this->_processBlock($this->_generate_xor($xor), CRYPT_DES_ENCRYPT); - $key = $this->_string_shift($buffer['encrypted'], 8); - $ciphertext.= $block ^ $key; - } - } else { - for ($i = 0; $i < strlen($plaintext); $i+=8) { - $block = substr($plaintext, $i, 8); - $key = $this->_processBlock($this->_generate_xor($xor), CRYPT_DES_ENCRYPT); - $ciphertext.= $block ^ $key; - } - } - if ($this->continuousBuffer) { - $this->encryptIV = $xor; - if ($start = strlen($plaintext) & 7) { - $buffer['encrypted'] = substr($key, $start) . $buffer['encrypted']; - } - } - break; - case CRYPT_DES_MODE_CFB: - if ($this->continuousBuffer) { - $iv = &$this->encryptIV; - $pos = &$buffer['pos']; - } else { - $iv = $this->encryptIV; - $pos = 0; - } - $len = strlen($plaintext); - $i = 0; - if ($pos) { - $orig_pos = $pos; - $max = 8 - $pos; - if ($len >= $max) { - $i = $max; - $len-= $max; - $pos = 0; - } else { - $i = $len; - $pos+= $len; - $len = 0; - } - $ciphertext = substr($iv, $orig_pos) ^ $plaintext; - $iv = substr_replace($iv, $ciphertext, $orig_pos, $i); - } - while ($len >= 8) { - $iv = $this->_processBlock($iv, CRYPT_DES_ENCRYPT) ^ substr($plaintext, $i, 8); - $ciphertext.= $iv; - $len-= 8; - $i+= 8; - } - if ($len) { - $iv = $this->_processBlock($iv, CRYPT_DES_ENCRYPT); - $block = $iv ^ substr($plaintext, $i); - $iv = substr_replace($iv, $block, 0, $len); - $ciphertext.= $block; - $pos = $len; - } - return $ciphertext; - case CRYPT_DES_MODE_OFB: - $xor = $this->encryptIV; - if (strlen($buffer['xor'])) { - for ($i = 0; $i < strlen($plaintext); $i+=8) { - $xor = $this->_processBlock($xor, CRYPT_DES_ENCRYPT); - $buffer['xor'].= $xor; - $key = $this->_string_shift($buffer['xor'], 8); - $ciphertext.= substr($plaintext, $i, 8) ^ $key; - } - } else { - for ($i = 0; $i < strlen($plaintext); $i+=8) { - $xor = $this->_processBlock($xor, CRYPT_DES_ENCRYPT); - $ciphertext.= substr($plaintext, $i, 8) ^ $xor; - } - $key = $xor; - } - if ($this->continuousBuffer) { - $this->encryptIV = $xor; - if ($start = strlen($plaintext) & 7) { - $buffer['xor'] = substr($key, $start) . $buffer['xor']; - } - } - } - - return $ciphertext; - } - - /** - * Decrypts a message. - * - * If strlen($ciphertext) is not a multiple of 8, null bytes will be added to the end of the string until it is. - * - * @see Crypt_DES::encrypt() - * @access public - * @param String $ciphertext - */ - function decrypt($ciphertext) - { - if ($this->paddable) { - // we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic : - // "The data is padded with "\0" to make sure the length of the data is n * blocksize." - $ciphertext = str_pad($ciphertext, (strlen($ciphertext) + 7) & 0xFFFFFFF8, chr(0)); - } - - if ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) { - if ($this->dechanged) { - mcrypt_generic_init($this->demcrypt, $this->keys, $this->decryptIV); - if ($this->mode == 'ncfb') { - mcrypt_generic_init($this->ecb, $this->keys, "\0\0\0\0\0\0\0\0"); - } - $this->dechanged = false; - } - - if ($this->mode != 'ncfb' || !$this->continuousBuffer) { - $plaintext = mdecrypt_generic($this->demcrypt, $ciphertext); - } else { - $iv = &$this->decryptIV; - $pos = &$this->debuffer['pos']; - $len = strlen($ciphertext); - $plaintext = ''; - $i = 0; - if ($pos) { - $orig_pos = $pos; - $max = 8 - $pos; - if ($len >= $max) { - $i = $max; - $len-= $max; - $pos = 0; - } else { - $i = $len; - $pos+= $len; - $len = 0; - } - $plaintext = substr($iv, $orig_pos) ^ $ciphertext; - $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i); - } - if ($len >= 8) { - $cb = substr($ciphertext, $i, $len - $len % 8); - $plaintext.= mcrypt_generic($this->ecb, $iv . $cb) ^ $cb; - $iv = substr($cb, -8); - $len%= 8; - } - if ($len) { - $iv = mcrypt_generic($this->ecb, $iv); - $plaintext.= $iv ^ substr($ciphertext, -$len); - $iv = substr_replace($iv, substr($ciphertext, -$len), 0, $len); - $pos = $len; - } - return $plaintext; - } - - if (!$this->continuousBuffer) { - mcrypt_generic_init($this->demcrypt, $this->keys, $this->decryptIV); - } - - return $this->paddable ? $this->_unpad($plaintext) : $plaintext; - } - - if (!is_array($this->keys)) { - $this->keys = $this->_prepareKey("\0\0\0\0\0\0\0\0"); - } - - $buffer = &$this->debuffer; - $continuousBuffer = $this->continuousBuffer; - $plaintext = ''; - switch ($this->mode) { - case CRYPT_DES_MODE_ECB: - for ($i = 0; $i < strlen($ciphertext); $i+=8) { - $plaintext.= $this->_processBlock(substr($ciphertext, $i, 8), CRYPT_DES_DECRYPT); - } - break; - case CRYPT_DES_MODE_CBC: - $xor = $this->decryptIV; - for ($i = 0; $i < strlen($ciphertext); $i+=8) { - $block = substr($ciphertext, $i, 8); - $plaintext.= $this->_processBlock($block, CRYPT_DES_DECRYPT) ^ $xor; - $xor = $block; - } - if ($this->continuousBuffer) { - $this->decryptIV = $xor; - } - break; - case CRYPT_DES_MODE_CTR: - $xor = $this->decryptIV; - if (strlen($buffer['ciphertext'])) { - for ($i = 0; $i < strlen($ciphertext); $i+=8) { - $block = substr($ciphertext, $i, 8); - $buffer['ciphertext'].= $this->_processBlock($this->_generate_xor($xor), CRYPT_DES_ENCRYPT); - $key = $this->_string_shift($buffer['ciphertext'], 8); - $plaintext.= $block ^ $key; - } - } else { - for ($i = 0; $i < strlen($ciphertext); $i+=8) { - $block = substr($ciphertext, $i, 8); - $key = $this->_processBlock($this->_generate_xor($xor), CRYPT_DES_ENCRYPT); - $plaintext.= $block ^ $key; - } - } - if ($this->continuousBuffer) { - $this->decryptIV = $xor; - if ($start = strlen($ciphertext) % 8) { - $buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext']; - } - } - break; - case CRYPT_DES_MODE_CFB: - if ($this->continuousBuffer) { - $iv = &$this->decryptIV; - $pos = &$buffer['pos']; - } else { - $iv = $this->decryptIV; - $pos = 0; - } - $len = strlen($ciphertext); - $i = 0; - if ($pos) { - $orig_pos = $pos; - $max = 8 - $pos; - if ($len >= $max) { - $i = $max; - $len-= $max; - $pos = 0; - } else { - $i = $len; - $pos+= $len; - $len = 0; - } - $plaintext = substr($iv, $orig_pos) ^ $ciphertext; - $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i); - } - while ($len >= 8) { - $iv = $this->_processBlock($iv, CRYPT_DES_ENCRYPT); - $cb = substr($ciphertext, $i, 8); - $plaintext.= $iv ^ $cb; - $iv = $cb; - $len-= 8; - $i+= 8; - } - if ($len) { - $iv = $this->_processBlock($iv, CRYPT_DES_ENCRYPT); - $plaintext.= $iv ^ substr($ciphertext, $i); - $iv = substr_replace($iv, substr($ciphertext, $i), 0, $len); - $pos = $len; - } - return $plaintext; - case CRYPT_DES_MODE_OFB: - $xor = $this->decryptIV; - if (strlen($buffer['xor'])) { - for ($i = 0; $i < strlen($ciphertext); $i+=8) { - $xor = $this->_processBlock($xor, CRYPT_DES_ENCRYPT); - $buffer['xor'].= $xor; - $key = $this->_string_shift($buffer['xor'], 8); - $plaintext.= substr($ciphertext, $i, 8) ^ $key; - } - } else { - for ($i = 0; $i < strlen($ciphertext); $i+=8) { - $xor = $this->_processBlock($xor, CRYPT_DES_ENCRYPT); - $plaintext.= substr($ciphertext, $i, 8) ^ $xor; - } - $key = $xor; - } - if ($this->continuousBuffer) { - $this->decryptIV = $xor; - if ($start = strlen($ciphertext) % 8) { - $buffer['xor'] = substr($key, $start) . $buffer['xor']; - } - } - } - - return $this->paddable ? $this->_unpad($plaintext) : $plaintext; - } - - /** - * Treat consecutive "packets" as if they are a continuous buffer. - * - * Say you have a 16-byte plaintext $plaintext. Using the default behavior, the two following code snippets - * will yield different outputs: - * - * - * echo $des->encrypt(substr($plaintext, 0, 8)); - * echo $des->encrypt(substr($plaintext, 8, 8)); - * - * - * echo $des->encrypt($plaintext); - * - * - * The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates - * another, as demonstrated with the following: - * - * - * $des->encrypt(substr($plaintext, 0, 8)); - * echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8))); - * - * - * echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8))); - * - * - * With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different - * outputs. The reason is due to the fact that the initialization vector's change after every encryption / - * decryption round when the continuous buffer is enabled. When it's disabled, they remain constant. - * - * Put another way, when the continuous buffer is enabled, the state of the Crypt_DES() object changes after each - * encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that - * continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them), - * however, they are also less intuitive and more likely to cause you problems. - * - * @see Crypt_DES::disableContinuousBuffer() - * @access public - */ - function enableContinuousBuffer() - { - $this->continuousBuffer = true; - } - - /** - * Treat consecutive packets as if they are a discontinuous buffer. - * - * The default behavior. - * - * @see Crypt_DES::enableContinuousBuffer() - * @access public - */ - function disableContinuousBuffer() - { - $this->continuousBuffer = false; - $this->encryptIV = $this->iv; - $this->decryptIV = $this->iv; - $this->enbuffer = array('encrypted' => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true); - $this->debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0, 'demcrypt_init' => true); - - if (CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT) { - mcrypt_generic_init($this->enmcrypt, $this->keys, $this->iv); - mcrypt_generic_init($this->demcrypt, $this->keys, $this->iv); - } - } - - /** - * Pad "packets". - * - * DES works by encrypting eight bytes at a time. If you ever need to encrypt or decrypt something that's not - * a multiple of eight, it becomes necessary to pad the input so that it's length is a multiple of eight. - * - * Padding is enabled by default. Sometimes, however, it is undesirable to pad strings. Such is the case in SSH1, - * where "packets" are padded with random bytes before being encrypted. Unpad these packets and you risk stripping - * away characters that shouldn't be stripped away. (SSH knows how many bytes are added because the length is - * transmitted separately) - * - * @see Crypt_DES::disablePadding() - * @access public - */ - function enablePadding() - { - $this->padding = true; - } - - /** - * Do not pad packets. - * - * @see Crypt_DES::enablePadding() - * @access public - */ - function disablePadding() - { - $this->padding = false; - } - - /** - * Pads a string - * - * Pads a string using the RSA PKCS padding standards so that its length is a multiple of the blocksize (8). - * 8 - (strlen($text) & 7) bytes are added, each of which is equal to chr(8 - (strlen($text) & 7) - * - * If padding is disabled and $text is not a multiple of the blocksize, the string will be padded regardless - * and padding will, hence forth, be enabled. - * - * @see Crypt_DES::_unpad() * @access private + * @param String $in + * @return String */ - function _pad($text) + function _decryptBlock($in) { - $length = strlen($text); - - if (!$this->padding) { - if (($length & 7) == 0) { - return $text; - } else { - user_error("The plaintext's length ($length) is not a multiple of the block size (8)"); - $this->padding = true; - } - } - - $pad = 8 - ($length & 7); - return str_pad($text, $length + $pad, chr($pad)); - } - - /** - * Unpads a string - * - * If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong - * and false will be returned. - * - * @see Crypt_DES::_pad() - * @access private - */ - function _unpad($text) - { - if (!$this->padding) { - return $text; - } - - $length = ord($text[strlen($text) - 1]); - - if (!$length || $length > 8) { - return false; - } - - return substr($text, 0, -$length); + return $this->_processBlock($in, CRYPT_DES_DECRYPT); } /** @@ -1016,6 +754,8 @@ class Crypt_DES { * {@link http://en.wikipedia.org/wiki/Image:Feistel.png Feistel.png} to get a general * idea of what this function does. * + * @see Crypt_DES::_encryptBlock() + * @see Crypt_DES::_decryptBlock() * @access private * @param String $block * @param Integer $mode @@ -1023,310 +763,772 @@ class Crypt_DES { */ function _processBlock($block, $mode) { - // s-boxes. in the official DES docs, they're described as being matrices that - // one accesses by using the first and last bits to determine the row and the - // middle four bits to determine the column. in this implementation, they've - // been converted to vectors - static $sbox = array( - array( - 14, 0, 4, 15, 13, 7, 1, 4, 2, 14, 15, 2, 11, 13, 8, 1, - 3, 10 ,10, 6, 6, 12, 12, 11, 5, 9, 9, 5, 0, 3, 7, 8, - 4, 15, 1, 12, 14, 8, 8, 2, 13, 4, 6, 9, 2, 1, 11, 7, - 15, 5, 12, 11, 9, 3, 7, 14, 3, 10, 10, 0, 5, 6, 0, 13 - ), - array( - 15, 3, 1, 13, 8, 4, 14, 7, 6, 15, 11, 2, 3, 8, 4, 14, - 9, 12, 7, 0, 2, 1, 13, 10, 12, 6, 0, 9, 5, 11, 10, 5, - 0, 13, 14, 8, 7, 10, 11, 1, 10, 3, 4, 15, 13, 4, 1, 2, - 5, 11, 8, 6, 12, 7, 6, 12, 9, 0, 3, 5, 2, 14, 15, 9 - ), - array( - 10, 13, 0, 7, 9, 0, 14, 9, 6, 3, 3, 4, 15, 6, 5, 10, - 1, 2, 13, 8, 12, 5, 7, 14, 11, 12, 4, 11, 2, 15, 8, 1, - 13, 1, 6, 10, 4, 13, 9, 0, 8, 6, 15, 9, 3, 8, 0, 7, - 11, 4, 1, 15, 2, 14, 12, 3, 5, 11, 10, 5, 14, 2, 7, 12 - ), - array( - 7, 13, 13, 8, 14, 11, 3, 5, 0, 6, 6, 15, 9, 0, 10, 3, - 1, 4, 2, 7, 8, 2, 5, 12, 11, 1, 12, 10, 4, 14, 15, 9, - 10, 3, 6, 15, 9, 0, 0, 6, 12, 10, 11, 1, 7, 13, 13, 8, - 15, 9, 1, 4, 3, 5, 14, 11, 5, 12, 2, 7, 8, 2, 4, 14 - ), - array( - 2, 14, 12, 11, 4, 2, 1, 12, 7, 4, 10, 7, 11, 13, 6, 1, - 8, 5, 5, 0, 3, 15, 15, 10, 13, 3, 0, 9, 14, 8, 9, 6, - 4, 11, 2, 8, 1, 12, 11, 7, 10, 1, 13, 14, 7, 2, 8, 13, - 15, 6, 9, 15, 12, 0, 5, 9, 6, 10, 3, 4, 0, 5, 14, 3 - ), - array( - 12, 10, 1, 15, 10, 4, 15, 2, 9, 7, 2, 12, 6, 9, 8, 5, - 0, 6, 13, 1, 3, 13, 4, 14, 14, 0, 7, 11, 5, 3, 11, 8, - 9, 4, 14, 3, 15, 2, 5, 12, 2, 9, 8, 5, 12, 15, 3, 10, - 7, 11, 0, 14, 4, 1, 10, 7, 1, 6, 13, 0, 11, 8, 6, 13 - ), - array( - 4, 13, 11, 0, 2, 11, 14, 7, 15, 4, 0, 9, 8, 1, 13, 10, - 3, 14, 12, 3, 9, 5, 7, 12, 5, 2, 10, 15, 6, 8, 1, 6, - 1, 6, 4, 11, 11, 13, 13, 8, 12, 1, 3, 4, 7, 10, 14, 7, - 10, 9, 15, 5, 6, 0, 8, 15, 0, 14, 5, 2, 9, 3, 2, 12 - ), - array( - 13, 1, 2, 15, 8, 13, 4, 8, 6, 10, 15, 3, 11, 7, 1, 4, - 10, 12, 9, 5, 3, 6, 14, 11, 5, 0, 0, 14, 12, 9, 7, 2, - 7, 2, 11, 1, 4, 14, 1, 7, 9, 4, 12, 10, 14, 8, 2, 13, - 0, 15, 6, 12, 10, 9, 13, 0, 15, 3, 3, 5, 5, 6, 8, 11 - ) - ); - - $keys = $this->keys; - - $temp = unpack('Na/Nb', $block); - $block = array($temp['a'], $temp['b']); - - // because php does arithmetic right shifts, if the most significant bits are set, right - // shifting those into the correct position will add 1's - not 0's. this will intefere - // with the | operation unless a second & is done. so we isolate these bits and left shift - // them into place. we then & each block with 0x7FFFFFFF to prevennt 1's from being added - // for any other shifts. - $msb = array( - ($block[0] >> 31) & 1, - ($block[1] >> 31) & 1 - ); - $block[0] &= 0x7FFFFFFF; - $block[1] &= 0x7FFFFFFF; - - // we isolate the appropriate bit in the appropriate integer and shift as appropriate. in - // some cases, there are going to be multiple bits in the same integer that need to be shifted - // in the same way. we combine those into one shift operation. - $block = array( - (($block[1] & 0x00000040) << 25) | (($block[1] & 0x00004000) << 16) | - (($block[1] & 0x00400001) << 7) | (($block[1] & 0x40000100) >> 2) | - (($block[0] & 0x00000040) << 21) | (($block[0] & 0x00004000) << 12) | - (($block[0] & 0x00400001) << 3) | (($block[0] & 0x40000100) >> 6) | - (($block[1] & 0x00000010) << 19) | (($block[1] & 0x00001000) << 10) | - (($block[1] & 0x00100000) << 1) | (($block[1] & 0x10000000) >> 8) | - (($block[0] & 0x00000010) << 15) | (($block[0] & 0x00001000) << 6) | - (($block[0] & 0x00100000) >> 3) | (($block[0] & 0x10000000) >> 12) | - (($block[1] & 0x00000004) << 13) | (($block[1] & 0x00000400) << 4) | - (($block[1] & 0x00040000) >> 5) | (($block[1] & 0x04000000) >> 14) | - (($block[0] & 0x00000004) << 9) | ( $block[0] & 0x00000400 ) | - (($block[0] & 0x00040000) >> 9) | (($block[0] & 0x04000000) >> 18) | - (($block[1] & 0x00010000) >> 11) | (($block[1] & 0x01000000) >> 20) | - (($block[0] & 0x00010000) >> 15) | (($block[0] & 0x01000000) >> 24) - , - (($block[1] & 0x00000080) << 24) | (($block[1] & 0x00008000) << 15) | - (($block[1] & 0x00800002) << 6) | (($block[0] & 0x00000080) << 20) | - (($block[0] & 0x00008000) << 11) | (($block[0] & 0x00800002) << 2) | - (($block[1] & 0x00000020) << 18) | (($block[1] & 0x00002000) << 9) | - ( $block[1] & 0x00200000 ) | (($block[1] & 0x20000000) >> 9) | - (($block[0] & 0x00000020) << 14) | (($block[0] & 0x00002000) << 5) | - (($block[0] & 0x00200000) >> 4) | (($block[0] & 0x20000000) >> 13) | - (($block[1] & 0x00000008) << 12) | (($block[1] & 0x00000800) << 3) | - (($block[1] & 0x00080000) >> 6) | (($block[1] & 0x08000000) >> 15) | - (($block[0] & 0x00000008) << 8) | (($block[0] & 0x00000800) >> 1) | - (($block[0] & 0x00080000) >> 10) | (($block[0] & 0x08000000) >> 19) | - (($block[1] & 0x00000200) >> 3) | (($block[0] & 0x00000200) >> 7) | - (($block[1] & 0x00020000) >> 12) | (($block[1] & 0x02000000) >> 21) | - (($block[0] & 0x00020000) >> 16) | (($block[0] & 0x02000000) >> 25) | - ($msb[1] << 28) | ($msb[0] << 24) - ); - - for ($i = 0; $i < 16; $i++) { - // start of "the Feistel (F) function" - see the following URL: - // http://en.wikipedia.org/wiki/Image:Data_Encryption_Standard_InfoBox_Diagram.png - $temp = (($sbox[0][((($block[1] >> 27) & 0x1F) | (($block[1] & 1) << 5)) ^ $keys[$mode][$i][0]]) << 28) - | (($sbox[1][(($block[1] & 0x1F800000) >> 23) ^ $keys[$mode][$i][1]]) << 24) - | (($sbox[2][(($block[1] & 0x01F80000) >> 19) ^ $keys[$mode][$i][2]]) << 20) - | (($sbox[3][(($block[1] & 0x001F8000) >> 15) ^ $keys[$mode][$i][3]]) << 16) - | (($sbox[4][(($block[1] & 0x0001F800) >> 11) ^ $keys[$mode][$i][4]]) << 12) - | (($sbox[5][(($block[1] & 0x00001F80) >> 7) ^ $keys[$mode][$i][5]]) << 8) - | (($sbox[6][(($block[1] & 0x000001F8) >> 3) ^ $keys[$mode][$i][6]]) << 4) - | ( $sbox[7][((($block[1] & 0x1F) << 1) | (($block[1] >> 31) & 1)) ^ $keys[$mode][$i][7]]); - - $msb = ($temp >> 31) & 1; - $temp &= 0x7FFFFFFF; - $newBlock = (($temp & 0x00010000) << 15) | (($temp & 0x02020120) << 5) - | (($temp & 0x00001800) << 17) | (($temp & 0x01000000) >> 10) - | (($temp & 0x00000008) << 24) | (($temp & 0x00100000) << 6) - | (($temp & 0x00000010) << 21) | (($temp & 0x00008000) << 9) - | (($temp & 0x00000200) << 12) | (($temp & 0x10000000) >> 27) - | (($temp & 0x00000040) << 14) | (($temp & 0x08000000) >> 8) - | (($temp & 0x00004000) << 4) | (($temp & 0x00000002) << 16) - | (($temp & 0x00442000) >> 6) | (($temp & 0x40800000) >> 15) - | (($temp & 0x00000001) << 11) | (($temp & 0x20000000) >> 20) - | (($temp & 0x00080000) >> 13) | (($temp & 0x00000004) << 3) - | (($temp & 0x04000000) >> 22) | (($temp & 0x00000480) >> 7) - | (($temp & 0x00200000) >> 19) | ($msb << 23); - // end of "the Feistel (F) function" - $newBlock is F's output - - $temp = $block[1]; - $block[1] = $block[0] ^ $newBlock; - $block[0] = $temp; + static $sbox1, $sbox2, $sbox3, $sbox4, $sbox5, $sbox6, $sbox7, $sbox8, $shuffleip, $shuffleinvip; + if (!$sbox1) { + $sbox1 = array_map("intval", $this->sbox1); + $sbox2 = array_map("intval", $this->sbox2); + $sbox3 = array_map("intval", $this->sbox3); + $sbox4 = array_map("intval", $this->sbox4); + $sbox5 = array_map("intval", $this->sbox5); + $sbox6 = array_map("intval", $this->sbox6); + $sbox7 = array_map("intval", $this->sbox7); + $sbox8 = array_map("intval", $this->sbox8); + /* Merge $shuffle with $[inv]ipmap */ + for ($i = 0; $i < 256; ++$i) { + $shuffleip[] = $this->shuffle[$this->ipmap[$i]]; + $shuffleinvip[] = $this->shuffle[$this->invipmap[$i]]; + } } - $msb = array( - ($block[0] >> 31) & 1, - ($block[1] >> 31) & 1 - ); - $block[0] &= 0x7FFFFFFF; - $block[1] &= 0x7FFFFFFF; + $keys = $this->keys[$mode]; + $ki = -1; - $block = array( - (($block[0] & 0x01000004) << 7) | (($block[1] & 0x01000004) << 6) | - (($block[0] & 0x00010000) << 13) | (($block[1] & 0x00010000) << 12) | - (($block[0] & 0x00000100) << 19) | (($block[1] & 0x00000100) << 18) | - (($block[0] & 0x00000001) << 25) | (($block[1] & 0x00000001) << 24) | - (($block[0] & 0x02000008) >> 2) | (($block[1] & 0x02000008) >> 3) | - (($block[0] & 0x00020000) << 4) | (($block[1] & 0x00020000) << 3) | - (($block[0] & 0x00000200) << 10) | (($block[1] & 0x00000200) << 9) | - (($block[0] & 0x00000002) << 16) | (($block[1] & 0x00000002) << 15) | - (($block[0] & 0x04000000) >> 11) | (($block[1] & 0x04000000) >> 12) | - (($block[0] & 0x00040000) >> 5) | (($block[1] & 0x00040000) >> 6) | - (($block[0] & 0x00000400) << 1) | ( $block[1] & 0x00000400 ) | - (($block[0] & 0x08000000) >> 20) | (($block[1] & 0x08000000) >> 21) | - (($block[0] & 0x00080000) >> 14) | (($block[1] & 0x00080000) >> 15) | - (($block[0] & 0x00000800) >> 8) | (($block[1] & 0x00000800) >> 9) - , - (($block[0] & 0x10000040) << 3) | (($block[1] & 0x10000040) << 2) | - (($block[0] & 0x00100000) << 9) | (($block[1] & 0x00100000) << 8) | - (($block[0] & 0x00001000) << 15) | (($block[1] & 0x00001000) << 14) | - (($block[0] & 0x00000010) << 21) | (($block[1] & 0x00000010) << 20) | - (($block[0] & 0x20000080) >> 6) | (($block[1] & 0x20000080) >> 7) | - ( $block[0] & 0x00200000 ) | (($block[1] & 0x00200000) >> 1) | - (($block[0] & 0x00002000) << 6) | (($block[1] & 0x00002000) << 5) | - (($block[0] & 0x00000020) << 12) | (($block[1] & 0x00000020) << 11) | - (($block[0] & 0x40000000) >> 15) | (($block[1] & 0x40000000) >> 16) | - (($block[0] & 0x00400000) >> 9) | (($block[1] & 0x00400000) >> 10) | - (($block[0] & 0x00004000) >> 3) | (($block[1] & 0x00004000) >> 4) | - (($block[0] & 0x00800000) >> 18) | (($block[1] & 0x00800000) >> 19) | - (($block[0] & 0x00008000) >> 12) | (($block[1] & 0x00008000) >> 13) | - ($msb[0] << 7) | ($msb[1] << 6) - ); + // Do the initial IP permutation. + $t = unpack('Nl/Nr', $block); + list($l, $r) = array($t['l'], $t['r']); + $block = ($shuffleip[ $r & 0xFF] & "\x80\x80\x80\x80\x80\x80\x80\x80") | + ($shuffleip[($r >> 8) & 0xFF] & "\x40\x40\x40\x40\x40\x40\x40\x40") | + ($shuffleip[($r >> 16) & 0xFF] & "\x20\x20\x20\x20\x20\x20\x20\x20") | + ($shuffleip[($r >> 24) & 0xFF] & "\x10\x10\x10\x10\x10\x10\x10\x10") | + ($shuffleip[ $l & 0xFF] & "\x08\x08\x08\x08\x08\x08\x08\x08") | + ($shuffleip[($l >> 8) & 0xFF] & "\x04\x04\x04\x04\x04\x04\x04\x04") | + ($shuffleip[($l >> 16) & 0xFF] & "\x02\x02\x02\x02\x02\x02\x02\x02") | + ($shuffleip[($l >> 24) & 0xFF] & "\x01\x01\x01\x01\x01\x01\x01\x01"); - return pack('NN', $block[0], $block[1]); + // Extract L0 and R0. + $t = unpack('Nl/Nr', $block); + list($l, $r) = array($t['l'], $t['r']); + + for ($des_round = 0; $des_round < $this->des_rounds; ++$des_round) { + // Perform the 16 steps. + for ($i = 0; $i < 16; $i++) { + // start of "the Feistel (F) function" - see the following URL: + // http://en.wikipedia.org/wiki/Image:Data_Encryption_Standard_InfoBox_Diagram.png + // Merge key schedule. + $b1 = (($r >> 3) & 0x1FFFFFFF) ^ ($r << 29) ^ $keys[++$ki]; + $b2 = (($r >> 31) & 0x00000001) ^ ($r << 1) ^ $keys[++$ki]; + + // S-box indexing. + $t = $sbox1[($b1 >> 24) & 0x3F] ^ $sbox2[($b2 >> 24) & 0x3F] ^ + $sbox3[($b1 >> 16) & 0x3F] ^ $sbox4[($b2 >> 16) & 0x3F] ^ + $sbox5[($b1 >> 8) & 0x3F] ^ $sbox6[($b2 >> 8) & 0x3F] ^ + $sbox7[ $b1 & 0x3F] ^ $sbox8[ $b2 & 0x3F] ^ $l; + // end of "the Feistel (F) function" + + $l = $r; + $r = $t; + } + + // Last step should not permute L & R. + $t = $l; + $l = $r; + $r = $t; + } + + // Perform the inverse IP permutation. + return ($shuffleinvip[($r >> 24) & 0xFF] & "\x80\x80\x80\x80\x80\x80\x80\x80") | + ($shuffleinvip[($l >> 24) & 0xFF] & "\x40\x40\x40\x40\x40\x40\x40\x40") | + ($shuffleinvip[($r >> 16) & 0xFF] & "\x20\x20\x20\x20\x20\x20\x20\x20") | + ($shuffleinvip[($l >> 16) & 0xFF] & "\x10\x10\x10\x10\x10\x10\x10\x10") | + ($shuffleinvip[($r >> 8) & 0xFF] & "\x08\x08\x08\x08\x08\x08\x08\x08") | + ($shuffleinvip[($l >> 8) & 0xFF] & "\x04\x04\x04\x04\x04\x04\x04\x04") | + ($shuffleinvip[ $r & 0xFF] & "\x02\x02\x02\x02\x02\x02\x02\x02") | + ($shuffleinvip[ $l & 0xFF] & "\x01\x01\x01\x01\x01\x01\x01\x01"); } /** - * Creates the key schedule. + * Creates the key schedule * + * @see Crypt_Base::_setupKey() * @access private - * @param String $key - * @return Array */ - function _prepareKey($key) + function _setupKey() { + if (isset($this->kl['key']) && $this->key === $this->kl['key'] && $this->des_rounds === $this->kl['des_rounds']) { + // already expanded + return; + } + $this->kl = array('key' => $this->key, 'des_rounds' => $this->des_rounds); + static $shifts = array( // number of key bits shifted per round 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 ); - // pad the key and remove extra characters as appropriate. - $key = str_pad(substr($key, 0, 8), 8, chr(0)); - - $temp = unpack('Na/Nb', $key); - $key = array($temp['a'], $temp['b']); - $msb = array( - ($key[0] >> 31) & 1, - ($key[1] >> 31) & 1 + static $pc1map = array( + 0x00, 0x00, 0x08, 0x08, 0x04, 0x04, 0x0C, 0x0C, + 0x02, 0x02, 0x0A, 0x0A, 0x06, 0x06, 0x0E, 0x0E, + 0x10, 0x10, 0x18, 0x18, 0x14, 0x14, 0x1C, 0x1C, + 0x12, 0x12, 0x1A, 0x1A, 0x16, 0x16, 0x1E, 0x1E, + 0x20, 0x20, 0x28, 0x28, 0x24, 0x24, 0x2C, 0x2C, + 0x22, 0x22, 0x2A, 0x2A, 0x26, 0x26, 0x2E, 0x2E, + 0x30, 0x30, 0x38, 0x38, 0x34, 0x34, 0x3C, 0x3C, + 0x32, 0x32, 0x3A, 0x3A, 0x36, 0x36, 0x3E, 0x3E, + 0x40, 0x40, 0x48, 0x48, 0x44, 0x44, 0x4C, 0x4C, + 0x42, 0x42, 0x4A, 0x4A, 0x46, 0x46, 0x4E, 0x4E, + 0x50, 0x50, 0x58, 0x58, 0x54, 0x54, 0x5C, 0x5C, + 0x52, 0x52, 0x5A, 0x5A, 0x56, 0x56, 0x5E, 0x5E, + 0x60, 0x60, 0x68, 0x68, 0x64, 0x64, 0x6C, 0x6C, + 0x62, 0x62, 0x6A, 0x6A, 0x66, 0x66, 0x6E, 0x6E, + 0x70, 0x70, 0x78, 0x78, 0x74, 0x74, 0x7C, 0x7C, + 0x72, 0x72, 0x7A, 0x7A, 0x76, 0x76, 0x7E, 0x7E, + 0x80, 0x80, 0x88, 0x88, 0x84, 0x84, 0x8C, 0x8C, + 0x82, 0x82, 0x8A, 0x8A, 0x86, 0x86, 0x8E, 0x8E, + 0x90, 0x90, 0x98, 0x98, 0x94, 0x94, 0x9C, 0x9C, + 0x92, 0x92, 0x9A, 0x9A, 0x96, 0x96, 0x9E, 0x9E, + 0xA0, 0xA0, 0xA8, 0xA8, 0xA4, 0xA4, 0xAC, 0xAC, + 0xA2, 0xA2, 0xAA, 0xAA, 0xA6, 0xA6, 0xAE, 0xAE, + 0xB0, 0xB0, 0xB8, 0xB8, 0xB4, 0xB4, 0xBC, 0xBC, + 0xB2, 0xB2, 0xBA, 0xBA, 0xB6, 0xB6, 0xBE, 0xBE, + 0xC0, 0xC0, 0xC8, 0xC8, 0xC4, 0xC4, 0xCC, 0xCC, + 0xC2, 0xC2, 0xCA, 0xCA, 0xC6, 0xC6, 0xCE, 0xCE, + 0xD0, 0xD0, 0xD8, 0xD8, 0xD4, 0xD4, 0xDC, 0xDC, + 0xD2, 0xD2, 0xDA, 0xDA, 0xD6, 0xD6, 0xDE, 0xDE, + 0xE0, 0xE0, 0xE8, 0xE8, 0xE4, 0xE4, 0xEC, 0xEC, + 0xE2, 0xE2, 0xEA, 0xEA, 0xE6, 0xE6, 0xEE, 0xEE, + 0xF0, 0xF0, 0xF8, 0xF8, 0xF4, 0xF4, 0xFC, 0xFC, + 0xF2, 0xF2, 0xFA, 0xFA, 0xF6, 0xF6, 0xFE, 0xFE ); - $key[0] &= 0x7FFFFFFF; - $key[1] &= 0x7FFFFFFF; - $key = array( - (($key[1] & 0x00000002) << 26) | (($key[1] & 0x00000204) << 17) | - (($key[1] & 0x00020408) << 8) | (($key[1] & 0x02040800) >> 1) | - (($key[0] & 0x00000002) << 22) | (($key[0] & 0x00000204) << 13) | - (($key[0] & 0x00020408) << 4) | (($key[0] & 0x02040800) >> 5) | - (($key[1] & 0x04080000) >> 10) | (($key[0] & 0x04080000) >> 14) | - (($key[1] & 0x08000000) >> 19) | (($key[0] & 0x08000000) >> 23) | - (($key[0] & 0x00000010) >> 1) | (($key[0] & 0x00001000) >> 10) | - (($key[0] & 0x00100000) >> 19) | (($key[0] & 0x10000000) >> 28) - , - (($key[1] & 0x00000080) << 20) | (($key[1] & 0x00008000) << 11) | - (($key[1] & 0x00800000) << 2) | (($key[0] & 0x00000080) << 16) | - (($key[0] & 0x00008000) << 7) | (($key[0] & 0x00800000) >> 2) | - (($key[1] & 0x00000040) << 13) | (($key[1] & 0x00004000) << 4) | - (($key[1] & 0x00400000) >> 5) | (($key[1] & 0x40000000) >> 14) | - (($key[0] & 0x00000040) << 9) | ( $key[0] & 0x00004000 ) | - (($key[0] & 0x00400000) >> 9) | (($key[0] & 0x40000000) >> 18) | - (($key[1] & 0x00000020) << 6) | (($key[1] & 0x00002000) >> 3) | - (($key[1] & 0x00200000) >> 12) | (($key[1] & 0x20000000) >> 21) | - (($key[0] & 0x00000020) << 2) | (($key[0] & 0x00002000) >> 7) | - (($key[0] & 0x00200000) >> 16) | (($key[0] & 0x20000000) >> 25) | - (($key[1] & 0x00000010) >> 1) | (($key[1] & 0x00001000) >> 10) | - (($key[1] & 0x00100000) >> 19) | (($key[1] & 0x10000000) >> 28) | - ($msb[1] << 24) | ($msb[0] << 20) - ); + // Mapping tables for the PC-2 transformation. + static $pc2mapc1 = array( + 0x00000000, 0x00000400, 0x00200000, 0x00200400, + 0x00000001, 0x00000401, 0x00200001, 0x00200401, + 0x02000000, 0x02000400, 0x02200000, 0x02200400, + 0x02000001, 0x02000401, 0x02200001, 0x02200401 + ); + static $pc2mapc2 = array( + 0x00000000, 0x00000800, 0x08000000, 0x08000800, + 0x00010000, 0x00010800, 0x08010000, 0x08010800, + 0x00000000, 0x00000800, 0x08000000, 0x08000800, + 0x00010000, 0x00010800, 0x08010000, 0x08010800, + 0x00000100, 0x00000900, 0x08000100, 0x08000900, + 0x00010100, 0x00010900, 0x08010100, 0x08010900, + 0x00000100, 0x00000900, 0x08000100, 0x08000900, + 0x00010100, 0x00010900, 0x08010100, 0x08010900, + 0x00000010, 0x00000810, 0x08000010, 0x08000810, + 0x00010010, 0x00010810, 0x08010010, 0x08010810, + 0x00000010, 0x00000810, 0x08000010, 0x08000810, + 0x00010010, 0x00010810, 0x08010010, 0x08010810, + 0x00000110, 0x00000910, 0x08000110, 0x08000910, + 0x00010110, 0x00010910, 0x08010110, 0x08010910, + 0x00000110, 0x00000910, 0x08000110, 0x08000910, + 0x00010110, 0x00010910, 0x08010110, 0x08010910, + 0x00040000, 0x00040800, 0x08040000, 0x08040800, + 0x00050000, 0x00050800, 0x08050000, 0x08050800, + 0x00040000, 0x00040800, 0x08040000, 0x08040800, + 0x00050000, 0x00050800, 0x08050000, 0x08050800, + 0x00040100, 0x00040900, 0x08040100, 0x08040900, + 0x00050100, 0x00050900, 0x08050100, 0x08050900, + 0x00040100, 0x00040900, 0x08040100, 0x08040900, + 0x00050100, 0x00050900, 0x08050100, 0x08050900, + 0x00040010, 0x00040810, 0x08040010, 0x08040810, + 0x00050010, 0x00050810, 0x08050010, 0x08050810, + 0x00040010, 0x00040810, 0x08040010, 0x08040810, + 0x00050010, 0x00050810, 0x08050010, 0x08050810, + 0x00040110, 0x00040910, 0x08040110, 0x08040910, + 0x00050110, 0x00050910, 0x08050110, 0x08050910, + 0x00040110, 0x00040910, 0x08040110, 0x08040910, + 0x00050110, 0x00050910, 0x08050110, 0x08050910, + 0x01000000, 0x01000800, 0x09000000, 0x09000800, + 0x01010000, 0x01010800, 0x09010000, 0x09010800, + 0x01000000, 0x01000800, 0x09000000, 0x09000800, + 0x01010000, 0x01010800, 0x09010000, 0x09010800, + 0x01000100, 0x01000900, 0x09000100, 0x09000900, + 0x01010100, 0x01010900, 0x09010100, 0x09010900, + 0x01000100, 0x01000900, 0x09000100, 0x09000900, + 0x01010100, 0x01010900, 0x09010100, 0x09010900, + 0x01000010, 0x01000810, 0x09000010, 0x09000810, + 0x01010010, 0x01010810, 0x09010010, 0x09010810, + 0x01000010, 0x01000810, 0x09000010, 0x09000810, + 0x01010010, 0x01010810, 0x09010010, 0x09010810, + 0x01000110, 0x01000910, 0x09000110, 0x09000910, + 0x01010110, 0x01010910, 0x09010110, 0x09010910, + 0x01000110, 0x01000910, 0x09000110, 0x09000910, + 0x01010110, 0x01010910, 0x09010110, 0x09010910, + 0x01040000, 0x01040800, 0x09040000, 0x09040800, + 0x01050000, 0x01050800, 0x09050000, 0x09050800, + 0x01040000, 0x01040800, 0x09040000, 0x09040800, + 0x01050000, 0x01050800, 0x09050000, 0x09050800, + 0x01040100, 0x01040900, 0x09040100, 0x09040900, + 0x01050100, 0x01050900, 0x09050100, 0x09050900, + 0x01040100, 0x01040900, 0x09040100, 0x09040900, + 0x01050100, 0x01050900, 0x09050100, 0x09050900, + 0x01040010, 0x01040810, 0x09040010, 0x09040810, + 0x01050010, 0x01050810, 0x09050010, 0x09050810, + 0x01040010, 0x01040810, 0x09040010, 0x09040810, + 0x01050010, 0x01050810, 0x09050010, 0x09050810, + 0x01040110, 0x01040910, 0x09040110, 0x09040910, + 0x01050110, 0x01050910, 0x09050110, 0x09050910, + 0x01040110, 0x01040910, 0x09040110, 0x09040910, + 0x01050110, 0x01050910, 0x09050110, 0x09050910 + ); + static $pc2mapc3 = array( + 0x00000000, 0x00000004, 0x00001000, 0x00001004, + 0x00000000, 0x00000004, 0x00001000, 0x00001004, + 0x10000000, 0x10000004, 0x10001000, 0x10001004, + 0x10000000, 0x10000004, 0x10001000, 0x10001004, + 0x00000020, 0x00000024, 0x00001020, 0x00001024, + 0x00000020, 0x00000024, 0x00001020, 0x00001024, + 0x10000020, 0x10000024, 0x10001020, 0x10001024, + 0x10000020, 0x10000024, 0x10001020, 0x10001024, + 0x00080000, 0x00080004, 0x00081000, 0x00081004, + 0x00080000, 0x00080004, 0x00081000, 0x00081004, + 0x10080000, 0x10080004, 0x10081000, 0x10081004, + 0x10080000, 0x10080004, 0x10081000, 0x10081004, + 0x00080020, 0x00080024, 0x00081020, 0x00081024, + 0x00080020, 0x00080024, 0x00081020, 0x00081024, + 0x10080020, 0x10080024, 0x10081020, 0x10081024, + 0x10080020, 0x10080024, 0x10081020, 0x10081024, + 0x20000000, 0x20000004, 0x20001000, 0x20001004, + 0x20000000, 0x20000004, 0x20001000, 0x20001004, + 0x30000000, 0x30000004, 0x30001000, 0x30001004, + 0x30000000, 0x30000004, 0x30001000, 0x30001004, + 0x20000020, 0x20000024, 0x20001020, 0x20001024, + 0x20000020, 0x20000024, 0x20001020, 0x20001024, + 0x30000020, 0x30000024, 0x30001020, 0x30001024, + 0x30000020, 0x30000024, 0x30001020, 0x30001024, + 0x20080000, 0x20080004, 0x20081000, 0x20081004, + 0x20080000, 0x20080004, 0x20081000, 0x20081004, + 0x30080000, 0x30080004, 0x30081000, 0x30081004, + 0x30080000, 0x30080004, 0x30081000, 0x30081004, + 0x20080020, 0x20080024, 0x20081020, 0x20081024, + 0x20080020, 0x20080024, 0x20081020, 0x20081024, + 0x30080020, 0x30080024, 0x30081020, 0x30081024, + 0x30080020, 0x30080024, 0x30081020, 0x30081024, + 0x00000002, 0x00000006, 0x00001002, 0x00001006, + 0x00000002, 0x00000006, 0x00001002, 0x00001006, + 0x10000002, 0x10000006, 0x10001002, 0x10001006, + 0x10000002, 0x10000006, 0x10001002, 0x10001006, + 0x00000022, 0x00000026, 0x00001022, 0x00001026, + 0x00000022, 0x00000026, 0x00001022, 0x00001026, + 0x10000022, 0x10000026, 0x10001022, 0x10001026, + 0x10000022, 0x10000026, 0x10001022, 0x10001026, + 0x00080002, 0x00080006, 0x00081002, 0x00081006, + 0x00080002, 0x00080006, 0x00081002, 0x00081006, + 0x10080002, 0x10080006, 0x10081002, 0x10081006, + 0x10080002, 0x10080006, 0x10081002, 0x10081006, + 0x00080022, 0x00080026, 0x00081022, 0x00081026, + 0x00080022, 0x00080026, 0x00081022, 0x00081026, + 0x10080022, 0x10080026, 0x10081022, 0x10081026, + 0x10080022, 0x10080026, 0x10081022, 0x10081026, + 0x20000002, 0x20000006, 0x20001002, 0x20001006, + 0x20000002, 0x20000006, 0x20001002, 0x20001006, + 0x30000002, 0x30000006, 0x30001002, 0x30001006, + 0x30000002, 0x30000006, 0x30001002, 0x30001006, + 0x20000022, 0x20000026, 0x20001022, 0x20001026, + 0x20000022, 0x20000026, 0x20001022, 0x20001026, + 0x30000022, 0x30000026, 0x30001022, 0x30001026, + 0x30000022, 0x30000026, 0x30001022, 0x30001026, + 0x20080002, 0x20080006, 0x20081002, 0x20081006, + 0x20080002, 0x20080006, 0x20081002, 0x20081006, + 0x30080002, 0x30080006, 0x30081002, 0x30081006, + 0x30080002, 0x30080006, 0x30081002, 0x30081006, + 0x20080022, 0x20080026, 0x20081022, 0x20081026, + 0x20080022, 0x20080026, 0x20081022, 0x20081026, + 0x30080022, 0x30080026, 0x30081022, 0x30081026, + 0x30080022, 0x30080026, 0x30081022, 0x30081026 + ); + static $pc2mapc4 = array( + 0x00000000, 0x00100000, 0x00000008, 0x00100008, + 0x00000200, 0x00100200, 0x00000208, 0x00100208, + 0x00000000, 0x00100000, 0x00000008, 0x00100008, + 0x00000200, 0x00100200, 0x00000208, 0x00100208, + 0x04000000, 0x04100000, 0x04000008, 0x04100008, + 0x04000200, 0x04100200, 0x04000208, 0x04100208, + 0x04000000, 0x04100000, 0x04000008, 0x04100008, + 0x04000200, 0x04100200, 0x04000208, 0x04100208, + 0x00002000, 0x00102000, 0x00002008, 0x00102008, + 0x00002200, 0x00102200, 0x00002208, 0x00102208, + 0x00002000, 0x00102000, 0x00002008, 0x00102008, + 0x00002200, 0x00102200, 0x00002208, 0x00102208, + 0x04002000, 0x04102000, 0x04002008, 0x04102008, + 0x04002200, 0x04102200, 0x04002208, 0x04102208, + 0x04002000, 0x04102000, 0x04002008, 0x04102008, + 0x04002200, 0x04102200, 0x04002208, 0x04102208, + 0x00000000, 0x00100000, 0x00000008, 0x00100008, + 0x00000200, 0x00100200, 0x00000208, 0x00100208, + 0x00000000, 0x00100000, 0x00000008, 0x00100008, + 0x00000200, 0x00100200, 0x00000208, 0x00100208, + 0x04000000, 0x04100000, 0x04000008, 0x04100008, + 0x04000200, 0x04100200, 0x04000208, 0x04100208, + 0x04000000, 0x04100000, 0x04000008, 0x04100008, + 0x04000200, 0x04100200, 0x04000208, 0x04100208, + 0x00002000, 0x00102000, 0x00002008, 0x00102008, + 0x00002200, 0x00102200, 0x00002208, 0x00102208, + 0x00002000, 0x00102000, 0x00002008, 0x00102008, + 0x00002200, 0x00102200, 0x00002208, 0x00102208, + 0x04002000, 0x04102000, 0x04002008, 0x04102008, + 0x04002200, 0x04102200, 0x04002208, 0x04102208, + 0x04002000, 0x04102000, 0x04002008, 0x04102008, + 0x04002200, 0x04102200, 0x04002208, 0x04102208, + 0x00020000, 0x00120000, 0x00020008, 0x00120008, + 0x00020200, 0x00120200, 0x00020208, 0x00120208, + 0x00020000, 0x00120000, 0x00020008, 0x00120008, + 0x00020200, 0x00120200, 0x00020208, 0x00120208, + 0x04020000, 0x04120000, 0x04020008, 0x04120008, + 0x04020200, 0x04120200, 0x04020208, 0x04120208, + 0x04020000, 0x04120000, 0x04020008, 0x04120008, + 0x04020200, 0x04120200, 0x04020208, 0x04120208, + 0x00022000, 0x00122000, 0x00022008, 0x00122008, + 0x00022200, 0x00122200, 0x00022208, 0x00122208, + 0x00022000, 0x00122000, 0x00022008, 0x00122008, + 0x00022200, 0x00122200, 0x00022208, 0x00122208, + 0x04022000, 0x04122000, 0x04022008, 0x04122008, + 0x04022200, 0x04122200, 0x04022208, 0x04122208, + 0x04022000, 0x04122000, 0x04022008, 0x04122008, + 0x04022200, 0x04122200, 0x04022208, 0x04122208, + 0x00020000, 0x00120000, 0x00020008, 0x00120008, + 0x00020200, 0x00120200, 0x00020208, 0x00120208, + 0x00020000, 0x00120000, 0x00020008, 0x00120008, + 0x00020200, 0x00120200, 0x00020208, 0x00120208, + 0x04020000, 0x04120000, 0x04020008, 0x04120008, + 0x04020200, 0x04120200, 0x04020208, 0x04120208, + 0x04020000, 0x04120000, 0x04020008, 0x04120008, + 0x04020200, 0x04120200, 0x04020208, 0x04120208, + 0x00022000, 0x00122000, 0x00022008, 0x00122008, + 0x00022200, 0x00122200, 0x00022208, 0x00122208, + 0x00022000, 0x00122000, 0x00022008, 0x00122008, + 0x00022200, 0x00122200, 0x00022208, 0x00122208, + 0x04022000, 0x04122000, 0x04022008, 0x04122008, + 0x04022200, 0x04122200, 0x04022208, 0x04122208, + 0x04022000, 0x04122000, 0x04022008, 0x04122008, + 0x04022200, 0x04122200, 0x04022208, 0x04122208 + ); + static $pc2mapd1 = array( + 0x00000000, 0x00000001, 0x08000000, 0x08000001, + 0x00200000, 0x00200001, 0x08200000, 0x08200001, + 0x00000002, 0x00000003, 0x08000002, 0x08000003, + 0x00200002, 0x00200003, 0x08200002, 0x08200003 + ); + static $pc2mapd2 = array( + 0x00000000, 0x00100000, 0x00000800, 0x00100800, + 0x00000000, 0x00100000, 0x00000800, 0x00100800, + 0x04000000, 0x04100000, 0x04000800, 0x04100800, + 0x04000000, 0x04100000, 0x04000800, 0x04100800, + 0x00000004, 0x00100004, 0x00000804, 0x00100804, + 0x00000004, 0x00100004, 0x00000804, 0x00100804, + 0x04000004, 0x04100004, 0x04000804, 0x04100804, + 0x04000004, 0x04100004, 0x04000804, 0x04100804, + 0x00000000, 0x00100000, 0x00000800, 0x00100800, + 0x00000000, 0x00100000, 0x00000800, 0x00100800, + 0x04000000, 0x04100000, 0x04000800, 0x04100800, + 0x04000000, 0x04100000, 0x04000800, 0x04100800, + 0x00000004, 0x00100004, 0x00000804, 0x00100804, + 0x00000004, 0x00100004, 0x00000804, 0x00100804, + 0x04000004, 0x04100004, 0x04000804, 0x04100804, + 0x04000004, 0x04100004, 0x04000804, 0x04100804, + 0x00000200, 0x00100200, 0x00000A00, 0x00100A00, + 0x00000200, 0x00100200, 0x00000A00, 0x00100A00, + 0x04000200, 0x04100200, 0x04000A00, 0x04100A00, + 0x04000200, 0x04100200, 0x04000A00, 0x04100A00, + 0x00000204, 0x00100204, 0x00000A04, 0x00100A04, + 0x00000204, 0x00100204, 0x00000A04, 0x00100A04, + 0x04000204, 0x04100204, 0x04000A04, 0x04100A04, + 0x04000204, 0x04100204, 0x04000A04, 0x04100A04, + 0x00000200, 0x00100200, 0x00000A00, 0x00100A00, + 0x00000200, 0x00100200, 0x00000A00, 0x00100A00, + 0x04000200, 0x04100200, 0x04000A00, 0x04100A00, + 0x04000200, 0x04100200, 0x04000A00, 0x04100A00, + 0x00000204, 0x00100204, 0x00000A04, 0x00100A04, + 0x00000204, 0x00100204, 0x00000A04, 0x00100A04, + 0x04000204, 0x04100204, 0x04000A04, 0x04100A04, + 0x04000204, 0x04100204, 0x04000A04, 0x04100A04, + 0x00020000, 0x00120000, 0x00020800, 0x00120800, + 0x00020000, 0x00120000, 0x00020800, 0x00120800, + 0x04020000, 0x04120000, 0x04020800, 0x04120800, + 0x04020000, 0x04120000, 0x04020800, 0x04120800, + 0x00020004, 0x00120004, 0x00020804, 0x00120804, + 0x00020004, 0x00120004, 0x00020804, 0x00120804, + 0x04020004, 0x04120004, 0x04020804, 0x04120804, + 0x04020004, 0x04120004, 0x04020804, 0x04120804, + 0x00020000, 0x00120000, 0x00020800, 0x00120800, + 0x00020000, 0x00120000, 0x00020800, 0x00120800, + 0x04020000, 0x04120000, 0x04020800, 0x04120800, + 0x04020000, 0x04120000, 0x04020800, 0x04120800, + 0x00020004, 0x00120004, 0x00020804, 0x00120804, + 0x00020004, 0x00120004, 0x00020804, 0x00120804, + 0x04020004, 0x04120004, 0x04020804, 0x04120804, + 0x04020004, 0x04120004, 0x04020804, 0x04120804, + 0x00020200, 0x00120200, 0x00020A00, 0x00120A00, + 0x00020200, 0x00120200, 0x00020A00, 0x00120A00, + 0x04020200, 0x04120200, 0x04020A00, 0x04120A00, + 0x04020200, 0x04120200, 0x04020A00, 0x04120A00, + 0x00020204, 0x00120204, 0x00020A04, 0x00120A04, + 0x00020204, 0x00120204, 0x00020A04, 0x00120A04, + 0x04020204, 0x04120204, 0x04020A04, 0x04120A04, + 0x04020204, 0x04120204, 0x04020A04, 0x04120A04, + 0x00020200, 0x00120200, 0x00020A00, 0x00120A00, + 0x00020200, 0x00120200, 0x00020A00, 0x00120A00, + 0x04020200, 0x04120200, 0x04020A00, 0x04120A00, + 0x04020200, 0x04120200, 0x04020A00, 0x04120A00, + 0x00020204, 0x00120204, 0x00020A04, 0x00120A04, + 0x00020204, 0x00120204, 0x00020A04, 0x00120A04, + 0x04020204, 0x04120204, 0x04020A04, 0x04120A04, + 0x04020204, 0x04120204, 0x04020A04, 0x04120A04 + ); + static $pc2mapd3 = array( + 0x00000000, 0x00010000, 0x02000000, 0x02010000, + 0x00000020, 0x00010020, 0x02000020, 0x02010020, + 0x00040000, 0x00050000, 0x02040000, 0x02050000, + 0x00040020, 0x00050020, 0x02040020, 0x02050020, + 0x00002000, 0x00012000, 0x02002000, 0x02012000, + 0x00002020, 0x00012020, 0x02002020, 0x02012020, + 0x00042000, 0x00052000, 0x02042000, 0x02052000, + 0x00042020, 0x00052020, 0x02042020, 0x02052020, + 0x00000000, 0x00010000, 0x02000000, 0x02010000, + 0x00000020, 0x00010020, 0x02000020, 0x02010020, + 0x00040000, 0x00050000, 0x02040000, 0x02050000, + 0x00040020, 0x00050020, 0x02040020, 0x02050020, + 0x00002000, 0x00012000, 0x02002000, 0x02012000, + 0x00002020, 0x00012020, 0x02002020, 0x02012020, + 0x00042000, 0x00052000, 0x02042000, 0x02052000, + 0x00042020, 0x00052020, 0x02042020, 0x02052020, + 0x00000010, 0x00010010, 0x02000010, 0x02010010, + 0x00000030, 0x00010030, 0x02000030, 0x02010030, + 0x00040010, 0x00050010, 0x02040010, 0x02050010, + 0x00040030, 0x00050030, 0x02040030, 0x02050030, + 0x00002010, 0x00012010, 0x02002010, 0x02012010, + 0x00002030, 0x00012030, 0x02002030, 0x02012030, + 0x00042010, 0x00052010, 0x02042010, 0x02052010, + 0x00042030, 0x00052030, 0x02042030, 0x02052030, + 0x00000010, 0x00010010, 0x02000010, 0x02010010, + 0x00000030, 0x00010030, 0x02000030, 0x02010030, + 0x00040010, 0x00050010, 0x02040010, 0x02050010, + 0x00040030, 0x00050030, 0x02040030, 0x02050030, + 0x00002010, 0x00012010, 0x02002010, 0x02012010, + 0x00002030, 0x00012030, 0x02002030, 0x02012030, + 0x00042010, 0x00052010, 0x02042010, 0x02052010, + 0x00042030, 0x00052030, 0x02042030, 0x02052030, + 0x20000000, 0x20010000, 0x22000000, 0x22010000, + 0x20000020, 0x20010020, 0x22000020, 0x22010020, + 0x20040000, 0x20050000, 0x22040000, 0x22050000, + 0x20040020, 0x20050020, 0x22040020, 0x22050020, + 0x20002000, 0x20012000, 0x22002000, 0x22012000, + 0x20002020, 0x20012020, 0x22002020, 0x22012020, + 0x20042000, 0x20052000, 0x22042000, 0x22052000, + 0x20042020, 0x20052020, 0x22042020, 0x22052020, + 0x20000000, 0x20010000, 0x22000000, 0x22010000, + 0x20000020, 0x20010020, 0x22000020, 0x22010020, + 0x20040000, 0x20050000, 0x22040000, 0x22050000, + 0x20040020, 0x20050020, 0x22040020, 0x22050020, + 0x20002000, 0x20012000, 0x22002000, 0x22012000, + 0x20002020, 0x20012020, 0x22002020, 0x22012020, + 0x20042000, 0x20052000, 0x22042000, 0x22052000, + 0x20042020, 0x20052020, 0x22042020, 0x22052020, + 0x20000010, 0x20010010, 0x22000010, 0x22010010, + 0x20000030, 0x20010030, 0x22000030, 0x22010030, + 0x20040010, 0x20050010, 0x22040010, 0x22050010, + 0x20040030, 0x20050030, 0x22040030, 0x22050030, + 0x20002010, 0x20012010, 0x22002010, 0x22012010, + 0x20002030, 0x20012030, 0x22002030, 0x22012030, + 0x20042010, 0x20052010, 0x22042010, 0x22052010, + 0x20042030, 0x20052030, 0x22042030, 0x22052030, + 0x20000010, 0x20010010, 0x22000010, 0x22010010, + 0x20000030, 0x20010030, 0x22000030, 0x22010030, + 0x20040010, 0x20050010, 0x22040010, 0x22050010, + 0x20040030, 0x20050030, 0x22040030, 0x22050030, + 0x20002010, 0x20012010, 0x22002010, 0x22012010, + 0x20002030, 0x20012030, 0x22002030, 0x22012030, + 0x20042010, 0x20052010, 0x22042010, 0x22052010, + 0x20042030, 0x20052030, 0x22042030, 0x22052030 + ); + static $pc2mapd4 = array( + 0x00000000, 0x00000400, 0x01000000, 0x01000400, + 0x00000000, 0x00000400, 0x01000000, 0x01000400, + 0x00000100, 0x00000500, 0x01000100, 0x01000500, + 0x00000100, 0x00000500, 0x01000100, 0x01000500, + 0x10000000, 0x10000400, 0x11000000, 0x11000400, + 0x10000000, 0x10000400, 0x11000000, 0x11000400, + 0x10000100, 0x10000500, 0x11000100, 0x11000500, + 0x10000100, 0x10000500, 0x11000100, 0x11000500, + 0x00080000, 0x00080400, 0x01080000, 0x01080400, + 0x00080000, 0x00080400, 0x01080000, 0x01080400, + 0x00080100, 0x00080500, 0x01080100, 0x01080500, + 0x00080100, 0x00080500, 0x01080100, 0x01080500, + 0x10080000, 0x10080400, 0x11080000, 0x11080400, + 0x10080000, 0x10080400, 0x11080000, 0x11080400, + 0x10080100, 0x10080500, 0x11080100, 0x11080500, + 0x10080100, 0x10080500, 0x11080100, 0x11080500, + 0x00000008, 0x00000408, 0x01000008, 0x01000408, + 0x00000008, 0x00000408, 0x01000008, 0x01000408, + 0x00000108, 0x00000508, 0x01000108, 0x01000508, + 0x00000108, 0x00000508, 0x01000108, 0x01000508, + 0x10000008, 0x10000408, 0x11000008, 0x11000408, + 0x10000008, 0x10000408, 0x11000008, 0x11000408, + 0x10000108, 0x10000508, 0x11000108, 0x11000508, + 0x10000108, 0x10000508, 0x11000108, 0x11000508, + 0x00080008, 0x00080408, 0x01080008, 0x01080408, + 0x00080008, 0x00080408, 0x01080008, 0x01080408, + 0x00080108, 0x00080508, 0x01080108, 0x01080508, + 0x00080108, 0x00080508, 0x01080108, 0x01080508, + 0x10080008, 0x10080408, 0x11080008, 0x11080408, + 0x10080008, 0x10080408, 0x11080008, 0x11080408, + 0x10080108, 0x10080508, 0x11080108, 0x11080508, + 0x10080108, 0x10080508, 0x11080108, 0x11080508, + 0x00001000, 0x00001400, 0x01001000, 0x01001400, + 0x00001000, 0x00001400, 0x01001000, 0x01001400, + 0x00001100, 0x00001500, 0x01001100, 0x01001500, + 0x00001100, 0x00001500, 0x01001100, 0x01001500, + 0x10001000, 0x10001400, 0x11001000, 0x11001400, + 0x10001000, 0x10001400, 0x11001000, 0x11001400, + 0x10001100, 0x10001500, 0x11001100, 0x11001500, + 0x10001100, 0x10001500, 0x11001100, 0x11001500, + 0x00081000, 0x00081400, 0x01081000, 0x01081400, + 0x00081000, 0x00081400, 0x01081000, 0x01081400, + 0x00081100, 0x00081500, 0x01081100, 0x01081500, + 0x00081100, 0x00081500, 0x01081100, 0x01081500, + 0x10081000, 0x10081400, 0x11081000, 0x11081400, + 0x10081000, 0x10081400, 0x11081000, 0x11081400, + 0x10081100, 0x10081500, 0x11081100, 0x11081500, + 0x10081100, 0x10081500, 0x11081100, 0x11081500, + 0x00001008, 0x00001408, 0x01001008, 0x01001408, + 0x00001008, 0x00001408, 0x01001008, 0x01001408, + 0x00001108, 0x00001508, 0x01001108, 0x01001508, + 0x00001108, 0x00001508, 0x01001108, 0x01001508, + 0x10001008, 0x10001408, 0x11001008, 0x11001408, + 0x10001008, 0x10001408, 0x11001008, 0x11001408, + 0x10001108, 0x10001508, 0x11001108, 0x11001508, + 0x10001108, 0x10001508, 0x11001108, 0x11001508, + 0x00081008, 0x00081408, 0x01081008, 0x01081408, + 0x00081008, 0x00081408, 0x01081008, 0x01081408, + 0x00081108, 0x00081508, 0x01081108, 0x01081508, + 0x00081108, 0x00081508, 0x01081108, 0x01081508, + 0x10081008, 0x10081408, 0x11081008, 0x11081408, + 0x10081008, 0x10081408, 0x11081008, 0x11081408, + 0x10081108, 0x10081508, 0x11081108, 0x11081508, + 0x10081108, 0x10081508, 0x11081108, 0x11081508 + ); $keys = array(); - for ($i = 0; $i < 16; $i++) { - $key[0] <<= $shifts[$i]; - $temp = ($key[0] & 0xF0000000) >> 28; - $key[0] = ($key[0] | $temp) & 0x0FFFFFFF; + for ($des_round = 0; $des_round < $this->des_rounds; ++$des_round) { + // pad the key and remove extra characters as appropriate. + $key = str_pad(substr($this->key, $des_round * 8, 8), 8, "\0"); - $key[1] <<= $shifts[$i]; - $temp = ($key[1] & 0xF0000000) >> 28; - $key[1] = ($key[1] | $temp) & 0x0FFFFFFF; + // Perform the PC/1 transformation and compute C and D. + $t = unpack('Nl/Nr', $key); + list($l, $r) = array($t['l'], $t['r']); + $key = ($this->shuffle[$pc1map[ $r & 0xFF]] & "\x80\x80\x80\x80\x80\x80\x80\x00") | + ($this->shuffle[$pc1map[($r >> 8) & 0xFF]] & "\x40\x40\x40\x40\x40\x40\x40\x00") | + ($this->shuffle[$pc1map[($r >> 16) & 0xFF]] & "\x20\x20\x20\x20\x20\x20\x20\x00") | + ($this->shuffle[$pc1map[($r >> 24) & 0xFF]] & "\x10\x10\x10\x10\x10\x10\x10\x00") | + ($this->shuffle[$pc1map[ $l & 0xFF]] & "\x08\x08\x08\x08\x08\x08\x08\x00") | + ($this->shuffle[$pc1map[($l >> 8) & 0xFF]] & "\x04\x04\x04\x04\x04\x04\x04\x00") | + ($this->shuffle[$pc1map[($l >> 16) & 0xFF]] & "\x02\x02\x02\x02\x02\x02\x02\x00") | + ($this->shuffle[$pc1map[($l >> 24) & 0xFF]] & "\x01\x01\x01\x01\x01\x01\x01\x00"); + $key = unpack('Nc/Nd', $key); + $c = ( $key['c'] >> 4) & 0x0FFFFFFF; + $d = (($key['d'] >> 4) & 0x0FFFFFF0) | ($key['c'] & 0x0F); - $temp = array( - (($key[1] & 0x00004000) >> 9) | (($key[1] & 0x00000800) >> 7) | - (($key[1] & 0x00020000) >> 14) | (($key[1] & 0x00000010) >> 2) | - (($key[1] & 0x08000000) >> 26) | (($key[1] & 0x00800000) >> 23) - , - (($key[1] & 0x02400000) >> 20) | (($key[1] & 0x00000001) << 4) | - (($key[1] & 0x00002000) >> 10) | (($key[1] & 0x00040000) >> 18) | - (($key[1] & 0x00000080) >> 6) - , - ( $key[1] & 0x00000020 ) | (($key[1] & 0x00000200) >> 5) | - (($key[1] & 0x00010000) >> 13) | (($key[1] & 0x01000000) >> 22) | - (($key[1] & 0x00000004) >> 1) | (($key[1] & 0x00100000) >> 20) - , - (($key[1] & 0x00001000) >> 7) | (($key[1] & 0x00200000) >> 17) | - (($key[1] & 0x00000002) << 2) | (($key[1] & 0x00000100) >> 6) | - (($key[1] & 0x00008000) >> 14) | (($key[1] & 0x04000000) >> 26) - , - (($key[0] & 0x00008000) >> 10) | ( $key[0] & 0x00000010 ) | - (($key[0] & 0x02000000) >> 22) | (($key[0] & 0x00080000) >> 17) | - (($key[0] & 0x00000200) >> 8) | (($key[0] & 0x00000002) >> 1) - , - (($key[0] & 0x04000000) >> 21) | (($key[0] & 0x00010000) >> 12) | - (($key[0] & 0x00000020) >> 2) | (($key[0] & 0x00000800) >> 9) | - (($key[0] & 0x00800000) >> 22) | (($key[0] & 0x00000100) >> 8) - , - (($key[0] & 0x00001000) >> 7) | (($key[0] & 0x00000088) >> 3) | - (($key[0] & 0x00020000) >> 14) | (($key[0] & 0x00000001) << 2) | - (($key[0] & 0x00400000) >> 21) - , - (($key[0] & 0x00000400) >> 5) | (($key[0] & 0x00004000) >> 10) | - (($key[0] & 0x00000040) >> 3) | (($key[0] & 0x00100000) >> 18) | - (($key[0] & 0x08000000) >> 26) | (($key[0] & 0x01000000) >> 24) + $keys[$des_round] = array( + CRYPT_DES_ENCRYPT => array(), + CRYPT_DES_DECRYPT => array_fill(0, 32, 0) ); + for ($i = 0, $ki = 31; $i < 16; ++$i, $ki-= 2) { + $c <<= $shifts[$i]; + $c = ($c | ($c >> 28)) & 0x0FFFFFFF; + $d <<= $shifts[$i]; + $d = ($d | ($d >> 28)) & 0x0FFFFFFF; - $keys[] = $temp; + // Perform the PC-2 transformation. + $cp = $pc2mapc1[ $c >> 24 ] | $pc2mapc2[($c >> 16) & 0xFF] | + $pc2mapc3[($c >> 8) & 0xFF] | $pc2mapc4[ $c & 0xFF]; + $dp = $pc2mapd1[ $d >> 24 ] | $pc2mapd2[($d >> 16) & 0xFF] | + $pc2mapd3[($d >> 8) & 0xFF] | $pc2mapd4[ $d & 0xFF]; + + // Reorder: odd bytes/even bytes. Push the result in key schedule. + $keys[$des_round][CRYPT_DES_ENCRYPT][ ] = + $keys[$des_round][CRYPT_DES_DECRYPT][$ki - 1] = ( $cp & 0xFF000000) | (($cp << 8) & 0x00FF0000) | + (($dp >> 16) & 0x0000FF00) | (($dp >> 8) & 0x000000FF); + $keys[$des_round][CRYPT_DES_ENCRYPT][ ] = + $keys[$des_round][CRYPT_DES_DECRYPT][$ki ] = (($cp << 8) & 0xFF000000) | (($cp << 16) & 0x00FF0000) | + (($dp >> 8) & 0x0000FF00) | ( $dp & 0x000000FF); + } } - $temp = array( - CRYPT_DES_ENCRYPT => $keys, - CRYPT_DES_DECRYPT => array_reverse($keys) - ); - - return $temp; + switch ($this->des_rounds) { + case 3: // 3DES keys + $this->keys = array( + CRYPT_DES_ENCRYPT => array_merge( + $keys[0][CRYPT_DES_ENCRYPT], + $keys[1][CRYPT_DES_DECRYPT], + $keys[2][CRYPT_DES_ENCRYPT] + ), + CRYPT_DES_DECRYPT => array_merge( + $keys[2][CRYPT_DES_DECRYPT], + $keys[1][CRYPT_DES_ENCRYPT], + $keys[0][CRYPT_DES_DECRYPT] + ) + ); + break; + // case 1: // DES keys + default: + $this->keys = array( + CRYPT_DES_ENCRYPT => $keys[0][CRYPT_DES_ENCRYPT], + CRYPT_DES_DECRYPT => $keys[0][CRYPT_DES_DECRYPT] + ); + } } /** - * String Shift + * Setup the performance-optimized function for de/encrypt() * - * Inspired by array_shift - * - * @param String $string - * @param optional Integer $index - * @return String + * @see Crypt_Base::_setupInlineCrypt() * @access private */ - function _string_shift(&$string, $index = 1) + function _setupInlineCrypt() { - $substr = substr($string, 0, $index); - $string = substr($string, $index); - return $substr; + $lambda_functions =& Crypt_DES::_getLambdaFunctions(); + + // Engine configuration for: + // - DES ($des_rounds == 1) or + // - 3DES ($des_rounds == 3) + $des_rounds = $this->des_rounds; + + // We create max. 10 hi-optimized code for memory reason. Means: For each $key one ultra fast inline-crypt function. + // After that, we'll still create very fast optimized code but not the hi-ultimative code, for each $mode one + $gen_hi_opt_code = (bool)( count($lambda_functions) < 10 ); + + // Generation of a uniqe hash for our generated code + switch (true) { + case $gen_hi_opt_code: + // For hi-optimized code, we create for each combination of + // $mode, $des_rounds and $this->key its own encrypt/decrypt function. + $code_hash = md5(str_pad("Crypt_DES, $des_rounds, {$this->mode}, ", 32, "\0") . $this->key); + break; + default: + // After max 10 hi-optimized functions, we create generic + // (still very fast.. but not ultra) functions for each $mode/$des_rounds + // Currently 2 * 5 generic functions will be then max. possible. + $code_hash = "Crypt_DES, $des_rounds, {$this->mode}"; + } + + // Is there a re-usable $lambda_functions in there? If not, we have to create it. + if (!isset($lambda_functions[$code_hash])) { + // Init code for both, encrypt and decrypt. + $init_crypt = 'static $sbox1, $sbox2, $sbox3, $sbox4, $sbox5, $sbox6, $sbox7, $sbox8, $shuffleip, $shuffleinvip; + if (!$sbox1) { + $sbox1 = array_map("intval", $self->sbox1); + $sbox2 = array_map("intval", $self->sbox2); + $sbox3 = array_map("intval", $self->sbox3); + $sbox4 = array_map("intval", $self->sbox4); + $sbox5 = array_map("intval", $self->sbox5); + $sbox6 = array_map("intval", $self->sbox6); + $sbox7 = array_map("intval", $self->sbox7); + $sbox8 = array_map("intval", $self->sbox8);' + /* Merge $shuffle with $[inv]ipmap */ . ' + for ($i = 0; $i < 256; ++$i) { + $shuffleip[] = $self->shuffle[$self->ipmap[$i]]; + $shuffleinvip[] = $self->shuffle[$self->invipmap[$i]]; + } + } + '; + + switch (true) { + case $gen_hi_opt_code: + // In Hi-optimized code mode, we use our [3]DES key schedule as hardcoded integers. + // No futher initialisation of the $keys schedule is necessary. + // That is the extra performance boost. + $k = array( + CRYPT_DES_ENCRYPT => $this->keys[CRYPT_DES_ENCRYPT], + CRYPT_DES_DECRYPT => $this->keys[CRYPT_DES_DECRYPT] + ); + $init_encrypt = ''; + $init_decrypt = ''; + break; + default: + // In generic optimized code mode, we have to use, as the best compromise [currently], + // our key schedule as $ke/$kd arrays. (with hardcoded indexes...) + $k = array( + CRYPT_DES_ENCRYPT => array(), + CRYPT_DES_DECRYPT => array() + ); + for ($i = 0, $c = count($this->keys[CRYPT_DES_ENCRYPT]); $i < $c; ++$i) { + $k[CRYPT_DES_ENCRYPT][$i] = '$ke[' . $i . ']'; + $k[CRYPT_DES_DECRYPT][$i] = '$kd[' . $i . ']'; + } + $init_encrypt = '$ke = $self->keys[CRYPT_DES_ENCRYPT];'; + $init_decrypt = '$kd = $self->keys[CRYPT_DES_DECRYPT];'; + break; + } + + // Creating code for en- and decryption. + $crypt_block = array(); + foreach (array(CRYPT_DES_ENCRYPT, CRYPT_DES_DECRYPT) as $c) { + + /* Do the initial IP permutation. */ + $crypt_block[$c] = ' + $in = unpack("N*", $in); + $l = $in[1]; + $r = $in[2]; + $in = unpack("N*", + ($shuffleip[ $r & 0xFF] & "\x80\x80\x80\x80\x80\x80\x80\x80") | + ($shuffleip[($r >> 8) & 0xFF] & "\x40\x40\x40\x40\x40\x40\x40\x40") | + ($shuffleip[($r >> 16) & 0xFF] & "\x20\x20\x20\x20\x20\x20\x20\x20") | + ($shuffleip[($r >> 24) & 0xFF] & "\x10\x10\x10\x10\x10\x10\x10\x10") | + ($shuffleip[ $l & 0xFF] & "\x08\x08\x08\x08\x08\x08\x08\x08") | + ($shuffleip[($l >> 8) & 0xFF] & "\x04\x04\x04\x04\x04\x04\x04\x04") | + ($shuffleip[($l >> 16) & 0xFF] & "\x02\x02\x02\x02\x02\x02\x02\x02") | + ($shuffleip[($l >> 24) & 0xFF] & "\x01\x01\x01\x01\x01\x01\x01\x01") + ); + ' . /* Extract L0 and R0 */ ' + $l = $in[1]; + $r = $in[2]; + '; + + $l = '$l'; + $r = '$r'; + + // Perform DES or 3DES. + for ($ki = -1, $des_round = 0; $des_round < $des_rounds; ++$des_round) { + // Perform the 16 steps. + for ($i = 0; $i < 16; ++$i) { + // start of "the Feistel (F) function" - see the following URL: + // http://en.wikipedia.org/wiki/Image:Data_Encryption_Standard_InfoBox_Diagram.png + // Merge key schedule. + $crypt_block[$c].= ' + $b1 = ((' . $r . ' >> 3) & 0x1FFFFFFF) ^ (' . $r . ' << 29) ^ ' . $k[$c][++$ki] . '; + $b2 = ((' . $r . ' >> 31) & 0x00000001) ^ (' . $r . ' << 1) ^ ' . $k[$c][++$ki] . ';' . + /* S-box indexing. */ + $l . ' = $sbox1[($b1 >> 24) & 0x3F] ^ $sbox2[($b2 >> 24) & 0x3F] ^ + $sbox3[($b1 >> 16) & 0x3F] ^ $sbox4[($b2 >> 16) & 0x3F] ^ + $sbox5[($b1 >> 8) & 0x3F] ^ $sbox6[($b2 >> 8) & 0x3F] ^ + $sbox7[ $b1 & 0x3F] ^ $sbox8[ $b2 & 0x3F] ^ ' . $l . '; + '; + // end of "the Feistel (F) function" + + // swap L & R + list($l, $r) = array($r, $l); + } + list($l, $r) = array($r, $l); + } + + // Perform the inverse IP permutation. + $crypt_block[$c].= '$in = + ($shuffleinvip[($l >> 24) & 0xFF] & "\x80\x80\x80\x80\x80\x80\x80\x80") | + ($shuffleinvip[($r >> 24) & 0xFF] & "\x40\x40\x40\x40\x40\x40\x40\x40") | + ($shuffleinvip[($l >> 16) & 0xFF] & "\x20\x20\x20\x20\x20\x20\x20\x20") | + ($shuffleinvip[($r >> 16) & 0xFF] & "\x10\x10\x10\x10\x10\x10\x10\x10") | + ($shuffleinvip[($l >> 8) & 0xFF] & "\x08\x08\x08\x08\x08\x08\x08\x08") | + ($shuffleinvip[($r >> 8) & 0xFF] & "\x04\x04\x04\x04\x04\x04\x04\x04") | + ($shuffleinvip[ $l & 0xFF] & "\x02\x02\x02\x02\x02\x02\x02\x02") | + ($shuffleinvip[ $r & 0xFF] & "\x01\x01\x01\x01\x01\x01\x01\x01"); + '; + } + + // Creates the inline-crypt function + $lambda_functions[$code_hash] = $this->_createInlineCryptFunction( + array( + 'init_crypt' => $init_crypt, + 'init_encrypt' => $init_encrypt, + 'init_decrypt' => $init_decrypt, + 'encrypt_block' => $crypt_block[CRYPT_DES_ENCRYPT], + 'decrypt_block' => $crypt_block[CRYPT_DES_DECRYPT] + ) + ); + } + + // Set the inline-crypt function as callback in: $this->inline_crypt + $this->inline_crypt = $lambda_functions[$code_hash]; } } diff --git a/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/Hash.php b/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/Hash.php index c5d314f009..2189724198 100644 --- a/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/Hash.php +++ b/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/Hash.php @@ -52,7 +52,6 @@ * @author Jim Wigginton * @copyright MMVII Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @version $Id: Hash.php,v 1.6 2009/11/23 23:37:07 terrafrost Exp $ * @link http://phpseclib.sourceforge.net */ @@ -83,6 +82,15 @@ define('CRYPT_HASH_MODE_HASH', 3); * @package Crypt_Hash */ class Crypt_Hash { + /** + * Hash Parameter + * + * @see Crypt_Hash::setHash() + * @var Integer + * @access private + */ + var $hashParam; + /** * Byte-length of compression blocks / key (Internal HMAC) * @@ -168,13 +176,26 @@ class Crypt_Hash { * Keys can be of any length. * * @access public - * @param String $key + * @param optional String $key */ function setKey($key = false) { $this->key = $key; } + /** + * Gets the hash function. + * + * As set by the constructor or by the setHash() method. + * + * @access public + * @return String + */ + function getHash() + { + return $this->hashParam; + } + /** * Sets the hash function. * @@ -183,7 +204,7 @@ class Crypt_Hash { */ function setHash($hash) { - $hash = strtolower($hash); + $this->hashParam = $hash = strtolower($hash); switch ($hash) { case 'md5-96': case 'sha1-96': @@ -350,7 +371,7 @@ class Crypt_Hash { * Wrapper for MD5 * * @access private - * @param String $text + * @param String $m */ function _md5($m) { @@ -361,7 +382,7 @@ class Crypt_Hash { * Wrapper for SHA1 * * @access private - * @param String $text + * @param String $m */ function _sha1($m) { @@ -374,7 +395,7 @@ class Crypt_Hash { * See {@link http://tools.ietf.org/html/rfc1319 RFC1319}. * * @access private - * @param String $text + * @param String $m */ function _md2($m) { @@ -450,7 +471,7 @@ class Crypt_Hash { * See {@link http://en.wikipedia.org/wiki/SHA_hash_functions#SHA-256_.28a_SHA-2_variant.29_pseudocode SHA-256 (a SHA-2 variant) pseudocode - Wikipedia}. * * @access private - * @param String $text + * @param String $m */ function _sha256($m) { @@ -555,7 +576,7 @@ class Crypt_Hash { * Pure-PHP implementation of SHA384 and SHA512 * * @access private - * @param String $text + * @param String $m */ function _sha512($m) { @@ -784,9 +805,8 @@ class Crypt_Hash { * _sha256() adds multiple unsigned 32-bit integers. Since PHP doesn't support unsigned integers and since the * possibility of overflow exists, care has to be taken. Math_BigInteger() could be used but this should be faster. * - * @param String $string - * @param optional Integer $index - * @return String + * @param Integer $... + * @return Integer * @see _sha256() * @access private */ diff --git a/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/RC2.php b/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/RC2.php new file mode 100755 index 0000000000..5e0ca88c8f --- /dev/null +++ b/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/RC2.php @@ -0,0 +1,656 @@ + + * setKey('abcdefgh'); + * + * $plaintext = str_repeat('a', 1024); + * + * echo $rc2->decrypt($rc2->encrypt($plaintext)); + * ?> + * + * + * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @category Crypt + * @package Crypt_RC2 + * @author Patrick Monnerat + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @link http://phpseclib.sourceforge.net + */ + +/** + * Include Crypt_Base + * + * Base cipher class + */ +if (!class_exists('Crypt_Base')) { + require_once('Base.php'); +} + +/**#@+ + * @access public + * @see Crypt_RC2::encrypt() + * @see Crypt_RC2::decrypt() + */ +/** + * Encrypt / decrypt using the Counter mode. + * + * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29 + */ +define('CRYPT_RC2_MODE_CTR', CRYPT_MODE_CTR); +/** + * Encrypt / decrypt using the Electronic Code Book mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29 + */ +define('CRYPT_RC2_MODE_ECB', CRYPT_MODE_ECB); +/** + * Encrypt / decrypt using the Code Book Chaining mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29 + */ +define('CRYPT_RC2_MODE_CBC', CRYPT_MODE_CBC); +/** + * Encrypt / decrypt using the Cipher Feedback mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29 + */ +define('CRYPT_RC2_MODE_CFB', CRYPT_MODE_CFB); +/** + * Encrypt / decrypt using the Cipher Feedback mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29 + */ +define('CRYPT_RC2_MODE_OFB', CRYPT_MODE_OFB); +/**#@-*/ + +/**#@+ + * @access private + * @see Crypt_RC2::Crypt_RC2() + */ +/** + * Toggles the internal implementation + */ +define('CRYPT_RC2_MODE_INTERNAL', CRYPT_MODE_INTERNAL); +/** + * Toggles the mcrypt implementation + */ +define('CRYPT_RC2_MODE_MCRYPT', CRYPT_MODE_MCRYPT); +/**#@-*/ + +/** + * Pure-PHP implementation of RC2. + * + * @version 0.1.1 + * @access public + * @package Crypt_RC2 + */ +class Crypt_RC2 extends Crypt_Base { + /** + * Block Length of the cipher + * + * @see Crypt_Base::block_size + * @var Integer + * @access private + */ + var $block_size = 8; + + /** + * The Key + * + * @see Crypt_Base::key + * @see setKey() + * @var String + * @access private + */ + var $key = "\0"; + + /** + * The default password key_size used by setPassword() + * + * @see Crypt_Base::password_key_size + * @see Crypt_Base::setPassword() + * @var Integer + * @access private + */ + var $password_key_size = 16; // = 128 bits + + /** + * The namespace used by the cipher for its constants. + * + * @see Crypt_Base::const_namespace + * @var String + * @access private + */ + var $const_namespace = 'RC2'; + + /** + * The mcrypt specific name of the cipher + * + * @see Crypt_Base::cipher_name_mcrypt + * @var String + * @access private + */ + var $cipher_name_mcrypt = 'rc2'; + + /** + * Optimizing value while CFB-encrypting + * + * @see Crypt_Base::cfb_init_len + * @var Integer + * @access private + */ + var $cfb_init_len = 500; + +/** + * The key length in bits. + * + * @see Crypt_RC2::setKeyLength() + * @see Crypt_RC2::setKey() + * @var Integer + * @access private + * @internal Should be in range [1..1024]. + * @internal Changing this value after setting the key has no effect. + */ + var $default_key_length = 1024; + + /** + * The Key Schedule + * + * @see Crypt_RC2::_setupKey() + * @var Array + * @access private + */ + var $keys; + + /** + * Key expansion randomization table. + * Twice the same 256-value sequence to save a modulus in key expansion. + * + * @see Crypt_RC2::setKey() + * @var Array + * @access private + */ + var $pitable = array( + 0xD9, 0x78, 0xF9, 0xC4, 0x19, 0xDD, 0xB5, 0xED, + 0x28, 0xE9, 0xFD, 0x79, 0x4A, 0xA0, 0xD8, 0x9D, + 0xC6, 0x7E, 0x37, 0x83, 0x2B, 0x76, 0x53, 0x8E, + 0x62, 0x4C, 0x64, 0x88, 0x44, 0x8B, 0xFB, 0xA2, + 0x17, 0x9A, 0x59, 0xF5, 0x87, 0xB3, 0x4F, 0x13, + 0x61, 0x45, 0x6D, 0x8D, 0x09, 0x81, 0x7D, 0x32, + 0xBD, 0x8F, 0x40, 0xEB, 0x86, 0xB7, 0x7B, 0x0B, + 0xF0, 0x95, 0x21, 0x22, 0x5C, 0x6B, 0x4E, 0x82, + 0x54, 0xD6, 0x65, 0x93, 0xCE, 0x60, 0xB2, 0x1C, + 0x73, 0x56, 0xC0, 0x14, 0xA7, 0x8C, 0xF1, 0xDC, + 0x12, 0x75, 0xCA, 0x1F, 0x3B, 0xBE, 0xE4, 0xD1, + 0x42, 0x3D, 0xD4, 0x30, 0xA3, 0x3C, 0xB6, 0x26, + 0x6F, 0xBF, 0x0E, 0xDA, 0x46, 0x69, 0x07, 0x57, + 0x27, 0xF2, 0x1D, 0x9B, 0xBC, 0x94, 0x43, 0x03, + 0xF8, 0x11, 0xC7, 0xF6, 0x90, 0xEF, 0x3E, 0xE7, + 0x06, 0xC3, 0xD5, 0x2F, 0xC8, 0x66, 0x1E, 0xD7, + 0x08, 0xE8, 0xEA, 0xDE, 0x80, 0x52, 0xEE, 0xF7, + 0x84, 0xAA, 0x72, 0xAC, 0x35, 0x4D, 0x6A, 0x2A, + 0x96, 0x1A, 0xD2, 0x71, 0x5A, 0x15, 0x49, 0x74, + 0x4B, 0x9F, 0xD0, 0x5E, 0x04, 0x18, 0xA4, 0xEC, + 0xC2, 0xE0, 0x41, 0x6E, 0x0F, 0x51, 0xCB, 0xCC, + 0x24, 0x91, 0xAF, 0x50, 0xA1, 0xF4, 0x70, 0x39, + 0x99, 0x7C, 0x3A, 0x85, 0x23, 0xB8, 0xB4, 0x7A, + 0xFC, 0x02, 0x36, 0x5B, 0x25, 0x55, 0x97, 0x31, + 0x2D, 0x5D, 0xFA, 0x98, 0xE3, 0x8A, 0x92, 0xAE, + 0x05, 0xDF, 0x29, 0x10, 0x67, 0x6C, 0xBA, 0xC9, + 0xD3, 0x00, 0xE6, 0xCF, 0xE1, 0x9E, 0xA8, 0x2C, + 0x63, 0x16, 0x01, 0x3F, 0x58, 0xE2, 0x89, 0xA9, + 0x0D, 0x38, 0x34, 0x1B, 0xAB, 0x33, 0xFF, 0xB0, + 0xBB, 0x48, 0x0C, 0x5F, 0xB9, 0xB1, 0xCD, 0x2E, + 0xC5, 0xF3, 0xDB, 0x47, 0xE5, 0xA5, 0x9C, 0x77, + 0x0A, 0xA6, 0x20, 0x68, 0xFE, 0x7F, 0xC1, 0xAD, + 0xD9, 0x78, 0xF9, 0xC4, 0x19, 0xDD, 0xB5, 0xED, + 0x28, 0xE9, 0xFD, 0x79, 0x4A, 0xA0, 0xD8, 0x9D, + 0xC6, 0x7E, 0x37, 0x83, 0x2B, 0x76, 0x53, 0x8E, + 0x62, 0x4C, 0x64, 0x88, 0x44, 0x8B, 0xFB, 0xA2, + 0x17, 0x9A, 0x59, 0xF5, 0x87, 0xB3, 0x4F, 0x13, + 0x61, 0x45, 0x6D, 0x8D, 0x09, 0x81, 0x7D, 0x32, + 0xBD, 0x8F, 0x40, 0xEB, 0x86, 0xB7, 0x7B, 0x0B, + 0xF0, 0x95, 0x21, 0x22, 0x5C, 0x6B, 0x4E, 0x82, + 0x54, 0xD6, 0x65, 0x93, 0xCE, 0x60, 0xB2, 0x1C, + 0x73, 0x56, 0xC0, 0x14, 0xA7, 0x8C, 0xF1, 0xDC, + 0x12, 0x75, 0xCA, 0x1F, 0x3B, 0xBE, 0xE4, 0xD1, + 0x42, 0x3D, 0xD4, 0x30, 0xA3, 0x3C, 0xB6, 0x26, + 0x6F, 0xBF, 0x0E, 0xDA, 0x46, 0x69, 0x07, 0x57, + 0x27, 0xF2, 0x1D, 0x9B, 0xBC, 0x94, 0x43, 0x03, + 0xF8, 0x11, 0xC7, 0xF6, 0x90, 0xEF, 0x3E, 0xE7, + 0x06, 0xC3, 0xD5, 0x2F, 0xC8, 0x66, 0x1E, 0xD7, + 0x08, 0xE8, 0xEA, 0xDE, 0x80, 0x52, 0xEE, 0xF7, + 0x84, 0xAA, 0x72, 0xAC, 0x35, 0x4D, 0x6A, 0x2A, + 0x96, 0x1A, 0xD2, 0x71, 0x5A, 0x15, 0x49, 0x74, + 0x4B, 0x9F, 0xD0, 0x5E, 0x04, 0x18, 0xA4, 0xEC, + 0xC2, 0xE0, 0x41, 0x6E, 0x0F, 0x51, 0xCB, 0xCC, + 0x24, 0x91, 0xAF, 0x50, 0xA1, 0xF4, 0x70, 0x39, + 0x99, 0x7C, 0x3A, 0x85, 0x23, 0xB8, 0xB4, 0x7A, + 0xFC, 0x02, 0x36, 0x5B, 0x25, 0x55, 0x97, 0x31, + 0x2D, 0x5D, 0xFA, 0x98, 0xE3, 0x8A, 0x92, 0xAE, + 0x05, 0xDF, 0x29, 0x10, 0x67, 0x6C, 0xBA, 0xC9, + 0xD3, 0x00, 0xE6, 0xCF, 0xE1, 0x9E, 0xA8, 0x2C, + 0x63, 0x16, 0x01, 0x3F, 0x58, 0xE2, 0x89, 0xA9, + 0x0D, 0x38, 0x34, 0x1B, 0xAB, 0x33, 0xFF, 0xB0, + 0xBB, 0x48, 0x0C, 0x5F, 0xB9, 0xB1, 0xCD, 0x2E, + 0xC5, 0xF3, 0xDB, 0x47, 0xE5, 0xA5, 0x9C, 0x77, + 0x0A, 0xA6, 0x20, 0x68, 0xFE, 0x7F, 0xC1, 0xAD + ); + + /** + * Inverse key expansion randomization table. + * + * @see Crypt_RC2::setKey() + * @var Array + * @access private + */ + var $invpitable = array( + 0xD1, 0xDA, 0xB9, 0x6F, 0x9C, 0xC8, 0x78, 0x66, + 0x80, 0x2C, 0xF8, 0x37, 0xEA, 0xE0, 0x62, 0xA4, + 0xCB, 0x71, 0x50, 0x27, 0x4B, 0x95, 0xD9, 0x20, + 0x9D, 0x04, 0x91, 0xE3, 0x47, 0x6A, 0x7E, 0x53, + 0xFA, 0x3A, 0x3B, 0xB4, 0xA8, 0xBC, 0x5F, 0x68, + 0x08, 0xCA, 0x8F, 0x14, 0xD7, 0xC0, 0xEF, 0x7B, + 0x5B, 0xBF, 0x2F, 0xE5, 0xE2, 0x8C, 0xBA, 0x12, + 0xE1, 0xAF, 0xB2, 0x54, 0x5D, 0x59, 0x76, 0xDB, + 0x32, 0xA2, 0x58, 0x6E, 0x1C, 0x29, 0x64, 0xF3, + 0xE9, 0x96, 0x0C, 0x98, 0x19, 0x8D, 0x3E, 0x26, + 0xAB, 0xA5, 0x85, 0x16, 0x40, 0xBD, 0x49, 0x67, + 0xDC, 0x22, 0x94, 0xBB, 0x3C, 0xC1, 0x9B, 0xEB, + 0x45, 0x28, 0x18, 0xD8, 0x1A, 0x42, 0x7D, 0xCC, + 0xFB, 0x65, 0x8E, 0x3D, 0xCD, 0x2A, 0xA3, 0x60, + 0xAE, 0x93, 0x8A, 0x48, 0x97, 0x51, 0x15, 0xF7, + 0x01, 0x0B, 0xB7, 0x36, 0xB1, 0x2E, 0x11, 0xFD, + 0x84, 0x2D, 0x3F, 0x13, 0x88, 0xB3, 0x34, 0x24, + 0x1B, 0xDE, 0xC5, 0x1D, 0x4D, 0x2B, 0x17, 0x31, + 0x74, 0xA9, 0xC6, 0x43, 0x6D, 0x39, 0x90, 0xBE, + 0xC3, 0xB0, 0x21, 0x6B, 0xF6, 0x0F, 0xD5, 0x99, + 0x0D, 0xAC, 0x1F, 0x5C, 0x9E, 0xF5, 0xF9, 0x4C, + 0xD6, 0xDF, 0x89, 0xE4, 0x8B, 0xFF, 0xC7, 0xAA, + 0xE7, 0xED, 0x46, 0x25, 0xB6, 0x06, 0x5E, 0x35, + 0xB5, 0xEC, 0xCE, 0xE8, 0x6C, 0x30, 0x55, 0x61, + 0x4A, 0xFE, 0xA0, 0x79, 0x03, 0xF0, 0x10, 0x72, + 0x7C, 0xCF, 0x52, 0xA6, 0xA7, 0xEE, 0x44, 0xD3, + 0x9A, 0x57, 0x92, 0xD0, 0x5A, 0x7A, 0x41, 0x7F, + 0x0E, 0x00, 0x63, 0xF2, 0x4F, 0x05, 0x83, 0xC9, + 0xA1, 0xD4, 0xDD, 0xC4, 0x56, 0xF4, 0xD2, 0x77, + 0x81, 0x09, 0x82, 0x33, 0x9F, 0x07, 0x86, 0x75, + 0x38, 0x4E, 0x69, 0xF1, 0xAD, 0x23, 0x73, 0x87, + 0x70, 0x02, 0xC2, 0x1E, 0xB8, 0x0A, 0xFC, 0xE6 + ); + + /** + * Default Constructor. + * + * Determines whether or not the mcrypt extension should be used. + * + * $mode could be: + * + * - CRYPT_RC2_MODE_ECB + * + * - CRYPT_RC2_MODE_CBC + * + * - CRYPT_RC2_MODE_CTR + * + * - CRYPT_RC2_MODE_CFB + * + * - CRYPT_RC2_MODE_OFB + * + * If not explictly set, CRYPT_RC2_MODE_CBC will be used. + * + * @see Crypt_Base::Crypt_Base() + * @param optional Integer $mode + * @access public + */ + function Crypt_RC2($mode = CRYPT_RC2_MODE_CBC) + { + parent::Crypt_Base($mode); + $this->setKey(''); + } + + /** + * Sets the key length + * + * Valid key lengths are 1 to 1024. + * Calling this function after setting the key has no effect until the next + * Crypt_RC2::setKey() call. + * + * @access public + * @param Integer $length in bits + */ + function setKeyLength($length) + { + if ($length >= 1 && $length <= 1024) { + $this->default_key_length = $length; + } + } + + /** + * Sets the key. + * + * Keys can be of any length. RC2, itself, uses 1 to 1024 bit keys (eg. + * strlen($key) <= 128), however, we only use the first 128 bytes if $key + * has more then 128 bytes in it, and set $key to a single null byte if + * it is empty. + * + * If the key is not explicitly set, it'll be assumed to be a single + * null byte. + * + * @see Crypt_Base::setKey() + * @access public + * @param String $key + * @param Integer $t1 optional Effective key length in bits. + */ + function setKey($key, $t1 = 0) + { + if ($t1 <= 0) { + $t1 = $this->default_key_length; + } else if ($t1 > 1024) { + $t1 = 1024; + } + // Key byte count should be 1..128. + $key = strlen($key) ? substr($key, 0, 128): "\x00"; + $t = strlen($key); + + // The mcrypt RC2 implementation only supports effective key length + // of 1024 bits. It is however possible to handle effective key + // lengths in range 1..1024 by expanding the key and applying + // inverse pitable mapping to the first byte before submitting it + // to mcrypt. + + // Key expansion. + $l = array_values(unpack('C*', $key)); + $t8 = ($t1 + 7) >> 3; + $tm = 0xFF >> (8 * $t8 - $t1); + + // Expand key. + $pitable = $this->pitable; + for ($i = $t; $i < 128; $i++) { + $l[$i] = $pitable[$l[$i - 1] + $l[$i - $t]]; + } + $i = 128 - $t8; + $l[$i] = $pitable[$l[$i] & $tm]; + while ($i--) { + $l[$i] = $pitable[$l[$i + 1] ^ $l[$i + $t8]]; + } + + // Prepare the key for mcrypt. + $l[0] = $this->invpitable[$l[0]]; + array_unshift($l, 'C*'); + parent::setKey(call_user_func_array('pack', $l)); + } + + /** + * Encrypts a block + * + * @see Crypt_Base::_encryptBlock() + * @see Crypt_Base::encrypt() + * @access private + * @param String $in + * @return String + */ + function _encryptBlock($in) + { + list($r0, $r1, $r2, $r3) = array_values(unpack('v*', $in)); + $keys = $this->keys; + $limit = 20; + $actions = array($limit => 44, 44 => 64); + $j = 0; + + for (;;) { + // Mixing round. + $r0 = (($r0 + $keys[$j++] + ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF) << 1; + $r0 |= $r0 >> 16; + $r1 = (($r1 + $keys[$j++] + ((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF) << 2; + $r1 |= $r1 >> 16; + $r2 = (($r2 + $keys[$j++] + ((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF) << 3; + $r2 |= $r2 >> 16; + $r3 = (($r3 + $keys[$j++] + ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF) << 5; + $r3 |= $r3 >> 16; + + if ($j == $limit) { + if ($limit == 64) { + break; + } + + // Mashing round. + $r0 += $keys[$r3 & 0x3F]; + $r1 += $keys[$r0 & 0x3F]; + $r2 += $keys[$r1 & 0x3F]; + $r3 += $keys[$r2 & 0x3F]; + $limit = $actions[$limit]; + } + } + + return pack('vvvv', $r0, $r1, $r2, $r3); + } + + /** + * Decrypts a block + * + * @see Crypt_Base::_decryptBlock() + * @see Crypt_Base::decrypt() + * @access private + * @param String $in + * @return String + */ + function _decryptBlock($in) + { + list($r0, $r1, $r2, $r3) = array_values(unpack('v*', $in)); + $keys = $this->keys; + $limit = 44; + $actions = array($limit => 20, 20 => 0); + $j = 64; + + for (;;) { + // R-mixing round. + $r3 = ($r3 | ($r3 << 16)) >> 5; + $r3 = ($r3 - $keys[--$j] - ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF; + $r2 = ($r2 | ($r2 << 16)) >> 3; + $r2 = ($r2 - $keys[--$j] - ((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF; + $r1 = ($r1 | ($r1 << 16)) >> 2; + $r1 = ($r1 - $keys[--$j] - ((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF; + $r0 = ($r0 | ($r0 << 16)) >> 1; + $r0 = ($r0 - $keys[--$j] - ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF; + + if ($j == $limit) { + if (!$limit) { + break; + } + + // R-mashing round. + $r3 = ($r3 - $keys[$r2 & 0x3F]) & 0xFFFF; + $r2 = ($r2 - $keys[$r1 & 0x3F]) & 0xFFFF; + $r1 = ($r1 - $keys[$r0 & 0x3F]) & 0xFFFF; + $r0 = ($r0 - $keys[$r3 & 0x3F]) & 0xFFFF; + $limit = $actions[$limit]; + } + } + + return pack('vvvv', $r0, $r1, $r2, $r3); + } + + /** + * Creates the key schedule + * + * @see Crypt_Base::_setupKey() + * @access private + */ + function _setupKey() + { + // Key has already been expanded in Crypt_RC2::setKey(): + // Only the first value must be altered. + $l = unpack('Ca/Cb/v*', $this->key); + array_unshift($l, $this->pitable[$l['a']] | ($l['b'] << 8)); + unset($l['a']); + unset($l['b']); + $this->keys = $l; + } + + /** + * Setup the performance-optimized function for de/encrypt() + * + * @see Crypt_Base::_setupInlineCrypt() + * @access private + */ + function _setupInlineCrypt() + { + $lambda_functions = &Crypt_RC2::_getLambdaFunctions(); + + // The first 10 generated $lambda_functions will use the $keys hardcoded as integers + // for the mixing rounds, for better inline crypt performance [~20% faster]. + // But for memory reason we have to limit those ultra-optimized $lambda_functions to an amount of 10. + $keys = $this->keys; + if (count($lambda_functions) >= 10) { + foreach ($this->keys as $k => $v) { + $keys[$k] = '$keys[' . $k . ']'; + } + } + + $code_hash = md5(str_pad("Crypt_RC2, {$this->mode}, ", 32, "\0") . implode(',', $keys)); + + // Is there a re-usable $lambda_functions in there? + // If not, we have to create it. + if (!isset($lambda_functions[$code_hash])) { + // Init code for both, encrypt and decrypt. + $init_crypt = '$keys = $self->keys;'; + + // $in is the current 8 bytes block which has to be en/decrypt + $encrypt_block = $decrypt_block = ' + $in = unpack("v4", $in); + $r0 = $in[1]; + $r1 = $in[2]; + $r2 = $in[3]; + $r3 = $in[4]; + '; + + // Create code for encryption. + $limit = 20; + $actions = array($limit => 44, 44 => 64); + $j = 0; + + for (;;) { + // Mixing round. + $encrypt_block .= ' + $r0 = (($r0 + ' . $keys[$j++] . ' + + ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF) << 1; + $r0 |= $r0 >> 16; + $r1 = (($r1 + ' . $keys[$j++] . ' + + ((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF) << 2; + $r1 |= $r1 >> 16; + $r2 = (($r2 + ' . $keys[$j++] . ' + + ((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF) << 3; + $r2 |= $r2 >> 16; + $r3 = (($r3 + ' . $keys[$j++] . ' + + ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF) << 5; + $r3 |= $r3 >> 16;'; + + if ($j == $limit) { + if ($limit == 64) { + break; + } + + // Mashing round. + $encrypt_block .= ' + $r0 += $keys[$r3 & 0x3F]; + $r1 += $keys[$r0 & 0x3F]; + $r2 += $keys[$r1 & 0x3F]; + $r3 += $keys[$r2 & 0x3F];'; + $limit = $actions[$limit]; + } + } + + $encrypt_block .= '$in = pack("v4", $r0, $r1, $r2, $r3);'; + + // Create code for decryption. + $limit = 44; + $actions = array($limit => 20, 20 => 0); + $j = 64; + + for (;;) { + // R-mixing round. + $decrypt_block .= ' + $r3 = ($r3 | ($r3 << 16)) >> 5; + $r3 = ($r3 - ' . $keys[--$j] . ' - + ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF; + $r2 = ($r2 | ($r2 << 16)) >> 3; + $r2 = ($r2 - ' . $keys[--$j] . ' - + ((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF; + $r1 = ($r1 | ($r1 << 16)) >> 2; + $r1 = ($r1 - ' . $keys[--$j] . ' - + ((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF; + $r0 = ($r0 | ($r0 << 16)) >> 1; + $r0 = ($r0 - ' . $keys[--$j] . ' - + ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF;'; + + if ($j == $limit) { + if (!$limit) { + break; + } + + // R-mashing round. + $decrypt_block .= ' + $r3 = ($r3 - $keys[$r2 & 0x3F]) & 0xFFFF; + $r2 = ($r2 - $keys[$r1 & 0x3F]) & 0xFFFF; + $r1 = ($r1 - $keys[$r0 & 0x3F]) & 0xFFFF; + $r0 = ($r0 - $keys[$r3 & 0x3F]) & 0xFFFF;'; + $limit = $actions[$limit]; + } + } + + $decrypt_block .= '$in = pack("v4", $r0, $r1, $r2, $r3);'; + + // Creates the inline-crypt function + $lambda_functions[$code_hash] = $this->_createInlineCryptFunction( + array( + 'init_crypt' => $init_crypt, + 'encrypt_block' => $encrypt_block, + 'decrypt_block' => $decrypt_block + ) + ); + } + + // Set the inline-crypt function as callback in: $this->inline_crypt + $this->inline_crypt = $lambda_functions[$code_hash]; + } +} + +// vim: ts=4:sw=4:et: +// vim6: fdl=1: diff --git a/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/RC4.php b/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/RC4.php index 390108e048..f6a9eae2fb 100644 --- a/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/RC4.php +++ b/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/RC4.php @@ -14,7 +14,7 @@ * - {@link http://en.wikipedia.org/wiki/RC4 - Wikipedia: RC4} * * RC4 is also known as ARCFOUR or ARC4. The reason is elaborated upon at Wikipedia. This class is named RC4 and not - * ARCFOUR or ARC4 because RC4 is how it is refered to in the SSH1 specification. + * ARCFOUR or ARC4 because RC4 is how it is referred to in the SSH1 specification. * * Here's a short example of how to use this library: * @@ -41,10 +41,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -58,10 +58,18 @@ * @author Jim Wigginton * @copyright MMVII Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @version $Id: RC4.php,v 1.8 2009/06/09 04:00:38 terrafrost Exp $ * @link http://phpseclib.sourceforge.net */ +/** + * Include Crypt_Base + * + * Base cipher class + */ +if (!class_exists('Crypt_Base')) { + require_once('Base.php'); +} + /**#@+ * @access private * @see Crypt_RC4::Crypt_RC4() @@ -69,11 +77,11 @@ /** * Toggles the internal implementation */ -define('CRYPT_RC4_MODE_INTERNAL', 1); +define('CRYPT_RC4_MODE_INTERNAL', CRYPT_MODE_INTERNAL); /** * Toggles the mcrypt implementation */ -define('CRYPT_RC4_MODE_MCRYPT', 2); +define('CRYPT_RC4_MODE_MCRYPT', CRYPT_MODE_MCRYPT); /**#@-*/ /**#@+ @@ -92,7 +100,57 @@ define('CRYPT_RC4_DECRYPT', 1); * @access public * @package Crypt_RC4 */ -class Crypt_RC4 { +class Crypt_RC4 extends Crypt_Base { + /** + * Block Length of the cipher + * + * RC4 is a stream cipher + * so we the block_size to 0 + * + * @see Crypt_Base::block_size + * @var Integer + * @access private + */ + var $block_size = 0; + + /** + * The default password key_size used by setPassword() + * + * @see Crypt_Base::password_key_size + * @see Crypt_Base::setPassword() + * @var Integer + * @access private + */ + var $password_key_size = 128; // = 1024 bits + + /** + * The namespace used by the cipher for its constants. + * + * @see Crypt_Base::const_namespace + * @var String + * @access private + */ + var $const_namespace = 'RC4'; + + + /** + * The mcrypt specific name of the cipher + * + * @see Crypt_Base::cipher_name_mcrypt + * @var String + * @access private + */ + var $cipher_name_mcrypt = 'arcfour'; + + /** + * Holds whether performance-optimized $inline_crypt() can/should be used. + * + * @see Crypt_Base::inline_crypt + * @var mixed + * @access private + */ + var $use_inline_crypt = false; // currently not available + /** * The Key * @@ -103,190 +161,26 @@ class Crypt_RC4 { var $key = "\0"; /** - * The Key Stream for encryption - * - * If CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT, this will be equal to the mcrypt object + * The Key Stream for decryption and encryption * * @see Crypt_RC4::setKey() * @var Array * @access private */ - var $encryptStream = false; - - /** - * The Key Stream for decryption - * - * If CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT, this will be equal to the mcrypt object - * - * @see Crypt_RC4::setKey() - * @var Array - * @access private - */ - var $decryptStream = false; - - /** - * The $i and $j indexes for encryption - * - * @see Crypt_RC4::_crypt() - * @var Integer - * @access private - */ - var $encryptIndex = 0; - - /** - * The $i and $j indexes for decryption - * - * @see Crypt_RC4::_crypt() - * @var Integer - * @access private - */ - var $decryptIndex = 0; - - /** - * The Encryption Algorithm - * - * Only used if CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT. Only possible values are MCRYPT_RC4 or MCRYPT_ARCFOUR. - * - * @see Crypt_RC4::Crypt_RC4() - * @var Integer - * @access private - */ - var $mode; - - /** - * Continuous Buffer status - * - * @see Crypt_RC4::enableContinuousBuffer() - * @var Boolean - * @access private - */ - var $continuousBuffer = false; + var $stream; /** * Default Constructor. * * Determines whether or not the mcrypt extension should be used. * + * @see Crypt_Base::Crypt_Base() * @return Crypt_RC4 * @access public */ function Crypt_RC4() { - if ( !defined('CRYPT_RC4_MODE') ) { - switch (true) { - case extension_loaded('mcrypt') && (defined('MCRYPT_ARCFOUR') || defined('MCRYPT_RC4')) && in_array('arcfour', mcrypt_list_algorithms()): - define('CRYPT_RC4_MODE', CRYPT_RC4_MODE_MCRYPT); - break; - default: - define('CRYPT_RC4_MODE', CRYPT_RC4_MODE_INTERNAL); - } - } - - switch ( CRYPT_RC4_MODE ) { - case CRYPT_RC4_MODE_MCRYPT: - switch (true) { - case defined('MCRYPT_ARCFOUR'): - $this->mode = MCRYPT_ARCFOUR; - break; - case defined('MCRYPT_RC4'); - $this->mode = MCRYPT_RC4; - } - $this->encryptStream = mcrypt_module_open($this->mode, '', MCRYPT_MODE_STREAM, ''); - $this->decryptStream = mcrypt_module_open($this->mode, '', MCRYPT_MODE_STREAM, ''); - - } - } - - /** - * Sets the key. - * - * Keys can be between 1 and 256 bytes long. If they are longer then 256 bytes, the first 256 bytes will - * be used. If no key is explicitly set, it'll be assumed to be a single null byte. - * - * @access public - * @param String $key - */ - function setKey($key) - { - $this->key = $key; - - if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) { - mcrypt_generic_init($this->encryptStream, $this->key, ''); - mcrypt_generic_init($this->decryptStream, $this->key, ''); - return; - } - - $keyLength = strlen($key); - $keyStream = array(); - for ($i = 0; $i < 256; $i++) { - $keyStream[$i] = $i; - } - $j = 0; - for ($i = 0; $i < 256; $i++) { - $j = ($j + $keyStream[$i] + ord($key[$i % $keyLength])) & 255; - $temp = $keyStream[$i]; - $keyStream[$i] = $keyStream[$j]; - $keyStream[$j] = $temp; - } - - $this->encryptIndex = $this->decryptIndex = array(0, 0); - $this->encryptStream = $this->decryptStream = $keyStream; - } - - /** - * Sets the password. - * - * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows: - * {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2}: - * $hash, $salt, $count, $dkLen - * - * @param String $password - * @param optional String $method - * @access public - */ - function setPassword($password, $method = 'pbkdf2') - { - $key = ''; - - switch ($method) { - default: // 'pbkdf2' - list(, , $hash, $salt, $count) = func_get_args(); - if (!isset($hash)) { - $hash = 'sha1'; - } - // WPA and WPA2 use the SSID as the salt - if (!isset($salt)) { - $salt = 'phpseclib/salt'; - } - // RFC2898#section-4.2 uses 1,000 iterations by default - // WPA and WPA2 use 4,096. - if (!isset($count)) { - $count = 1000; - } - if (!isset($dkLen)) { - $dkLen = 128; - } - - if (!class_exists('Crypt_Hash')) { - require_once('Crypt/Hash.php'); - } - - $i = 1; - while (strlen($key) < $dkLen) { - //$dk.= $this->_pbkdf($password, $salt, $count, $i++); - $hmac = new Crypt_Hash(); - $hmac->setHash($hash); - $hmac->setKey($password); - $f = $u = $hmac->hash($salt . pack('N', $i++)); - for ($j = 2; $j <= $count; $j++) { - $u = $hmac->hash($u); - $f^= $u; - } - $key.= $f; - } - } - - $this->setKey(substr($key, 0, $dkLen)); + parent::Crypt_Base(CRYPT_MODE_STREAM); } /** @@ -312,15 +206,35 @@ class Crypt_RC4 { { } + /** + * Sets the key. + * + * Keys can be between 1 and 256 bytes long. If they are longer then 256 bytes, the first 256 bytes will + * be used. If no key is explicitly set, it'll be assumed to be a single null byte. + * + * @access public + * @see Crypt_Base::setKey() + * @param String $key + */ + function setKey($key) + { + parent::setKey(substr($key, 0, 256)); + } + /** * Encrypts a message. * + * @see Crypt_Base::decrypt() * @see Crypt_RC4::_crypt() * @access public * @param String $plaintext + * @return String $ciphertext */ function encrypt($plaintext) { + if ($this->engine == CRYPT_MODE_MCRYPT) { + return parent::encrypt($plaintext); + } return $this->_crypt($plaintext, CRYPT_RC4_ENCRYPT); } @@ -330,15 +244,51 @@ class Crypt_RC4 { * $this->decrypt($this->encrypt($plaintext)) == $this->encrypt($this->encrypt($plaintext)). * Atleast if the continuous buffer is disabled. * + * @see Crypt_Base::encrypt() * @see Crypt_RC4::_crypt() * @access public * @param String $ciphertext + * @return String $plaintext */ function decrypt($ciphertext) { + if ($this->engine == CRYPT_MODE_MCRYPT) { + return parent::decrypt($ciphertext); + } return $this->_crypt($ciphertext, CRYPT_RC4_DECRYPT); } + + /** + * Setup the key (expansion) + * + * @see Crypt_Base::_setupKey() + * @access private + */ + function _setupKey() + { + $key = $this->key; + $keyLength = strlen($key); + $keyStream = array(); + for ($i = 0; $i < 256; $i++) { + $keyStream[$i] = $i; + } + $j = 0; + for ($i = 0; $i < 256; $i++) { + $j = ($j + $keyStream[$i] + ord($key[$i % $keyLength])) & 255; + $temp = $keyStream[$i]; + $keyStream[$i] = $keyStream[$j]; + $keyStream[$j] = $temp; + } + + $this->stream = array(); + $this->stream[CRYPT_RC4_DECRYPT] = $this->stream[CRYPT_RC4_ENCRYPT] = array( + 0, // index $i + 0, // index $j + $keyStream + ); + } + /** * Encrypts or decrypts a message. * @@ -347,173 +297,41 @@ class Crypt_RC4 { * @access private * @param String $text * @param Integer $mode + * @return String $text */ function _crypt($text, $mode) { - if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) { - $keyStream = $mode == CRYPT_RC4_ENCRYPT ? 'encryptStream' : 'decryptStream'; - - if (!$this->continuousBuffer) { - mcrypt_generic_init($this->$keyStream, $this->key, ''); - } - - return mcrypt_generic($this->$keyStream, $text); - } - - if ($this->encryptStream === false) { - $this->setKey($this->key); - } - - switch ($mode) { - case CRYPT_RC4_ENCRYPT: - $keyStream = $this->encryptStream; - list($i, $j) = $this->encryptIndex; - break; - case CRYPT_RC4_DECRYPT: - $keyStream = $this->decryptStream; - list($i, $j) = $this->decryptIndex; - } - - $newText = ''; - for ($k = 0; $k < strlen($text); $k++) { - $i = ($i + 1) & 255; - $j = ($j + $keyStream[$i]) & 255; - $temp = $keyStream[$i]; - $keyStream[$i] = $keyStream[$j]; - $keyStream[$j] = $temp; - $temp = $keyStream[($keyStream[$i] + $keyStream[$j]) & 255]; - $newText.= chr(ord($text[$k]) ^ $temp); + if ($this->changed) { + $this->_setup(); + $this->changed = false; } + $stream = &$this->stream[$mode]; if ($this->continuousBuffer) { - switch ($mode) { - case CRYPT_RC4_ENCRYPT: - $this->encryptStream = $keyStream; - $this->encryptIndex = array($i, $j); - break; - case CRYPT_RC4_DECRYPT: - $this->decryptStream = $keyStream; - $this->decryptIndex = array($i, $j); - } + $i = &$stream[0]; + $j = &$stream[1]; + $keyStream = &$stream[2]; + } else { + $i = $stream[0]; + $j = $stream[1]; + $keyStream = $stream[2]; } - return $newText; - } + $len = strlen($text); + for ($k = 0; $k < $len; ++$k) { + $i = ($i + 1) & 255; + $ksi = $keyStream[$i]; + $j = ($j + $ksi) & 255; + $ksj = $keyStream[$j]; - /** - * Treat consecutive "packets" as if they are a continuous buffer. - * - * Say you have a 16-byte plaintext $plaintext. Using the default behavior, the two following code snippets - * will yield different outputs: - * - * - * echo $rc4->encrypt(substr($plaintext, 0, 8)); - * echo $rc4->encrypt(substr($plaintext, 8, 8)); - * - * - * echo $rc4->encrypt($plaintext); - * - * - * The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates - * another, as demonstrated with the following: - * - * - * $rc4->encrypt(substr($plaintext, 0, 8)); - * echo $rc4->decrypt($des->encrypt(substr($plaintext, 8, 8))); - * - * - * echo $rc4->decrypt($des->encrypt(substr($plaintext, 8, 8))); - * - * - * With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different - * outputs. The reason is due to the fact that the initialization vector's change after every encryption / - * decryption round when the continuous buffer is enabled. When it's disabled, they remain constant. - * - * Put another way, when the continuous buffer is enabled, the state of the Crypt_DES() object changes after each - * encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that - * continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them), - * however, they are also less intuitive and more likely to cause you problems. - * - * @see Crypt_RC4::disableContinuousBuffer() - * @access public - */ - function enableContinuousBuffer() - { - if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) { - mcrypt_generic_init($this->encryptStream, $this->key, ''); - mcrypt_generic_init($this->decryptStream, $this->key, ''); + $keyStream[$i] = $ksj; + $keyStream[$j] = $ksi; + $text[$k] = chr(ord($text[$k]) ^ $keyStream[($ksj + $ksi) & 255]); } - $this->continuousBuffer = true; - } - - /** - * Treat consecutive packets as if they are a discontinuous buffer. - * - * The default behavior. - * - * @see Crypt_RC4::enableContinuousBuffer() - * @access public - */ - function disableContinuousBuffer() - { - if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_INTERNAL ) { - $this->encryptIndex = $this->decryptIndex = array(0, 0); - $this->encryptStream = $this->decryptStream = false; - } - - $this->continuousBuffer = false; - } - - /** - * Dummy function. - * - * Since RC4 is a stream cipher and not a block cipher, no padding is necessary. The only reason this function is - * included is so that you can switch between a block cipher and a stream cipher transparently. - * - * @see Crypt_RC4::disablePadding() - * @access public - */ - function enablePadding() - { - } - - /** - * Dummy function. - * - * @see Crypt_RC4::enablePadding() - * @access public - */ - function disablePadding() - { - } - - /** - * Class destructor. - * - * Will be called, automatically, if you're using PHP5. If you're using PHP4, call it yourself. Only really - * needs to be called if mcrypt is being used. - * - * @access public - */ - function __destruct() - { - if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) { - $this->_closeMCrypt(); - } - } - - /** - * Properly close the MCrypt objects. - * - * @access prviate - */ - function _closeMCrypt() - { - mcrypt_module_close($this->encryptStream); - mcrypt_module_close($this->decryptStream); + return $text; } } // vim: ts=4:sw=4:et: -// vim6: fdl=1: \ No newline at end of file +// vim6: fdl=1: diff --git a/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/RSA.php b/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/RSA.php index db1ba1581b..92ebfdf723 100644 --- a/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/RSA.php +++ b/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/RSA.php @@ -65,17 +65,9 @@ * @author Jim Wigginton * @copyright MMIX Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @version $Id: RSA.php,v 1.19 2010/09/12 21:58:54 terrafrost Exp $ * @link http://phpseclib.sourceforge.net */ -/** - * Include Math_BigInteger - */ -if (!class_exists('Math_BigInteger')) { - require_once('Math/BigInteger.php'); -} - /** * Include Crypt_Random */ @@ -83,15 +75,15 @@ if (!class_exists('Math_BigInteger')) { // will trigger a call to __autoload() if you're wanting to auto-load classes // call function_exists() a second time to stop the require_once from being called outside // of the auto loader -if (!function_exists('crypt_random_string') && !class_exists('Crypt_Random') && !function_exists('crypt_random_string')) { - require_once('Crypt/Random.php'); +if (!function_exists('crypt_random_string')) { + require_once('Random.php'); } /** * Include Crypt_Hash */ if (!class_exists('Crypt_Hash')) { - require_once('Crypt/Hash.php'); + require_once('Hash.php'); } /**#@+ @@ -181,7 +173,6 @@ define('CRYPT_RSA_MODE_OPENSSL', 2); */ define('CRYPT_RSA_OPENSSL_CONFIG', dirname(__FILE__) . '/../openssl.cnf'); - /**#@+ * @access public * @see Crypt_RSA::createKey() @@ -449,6 +440,14 @@ class Crypt_RSA { */ var $configFile; + /** + * Public key comment field. + * + * @var String + * @access private + */ + var $comment = 'phpseclib-generated-key'; + /** * The constructor * @@ -461,22 +460,54 @@ class Crypt_RSA { */ function Crypt_RSA() { + if (!class_exists('Math_BigInteger')) { + require_once('Math/BigInteger.php'); + } + $this->configFile = CRYPT_RSA_OPENSSL_CONFIG; if ( !defined('CRYPT_RSA_MODE') ) { - switch (true) { - case extension_loaded('openssl') && version_compare(PHP_VERSION, '4.2.0', '>='): - define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_OPENSSL); + // Math/BigInteger's openssl requirements are a little less stringent than Crypt/RSA's. in particular, + // Math/BigInteger doesn't require an openssl.cfg file whereas Crypt/RSA does. so if Math/BigInteger + // can't use OpenSSL it can be pretty trivially assumed, then, that Crypt/RSA can't either. + if ( defined('MATH_BIGINTEGER_OPENSSL_DISABLE') ) { + define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL); + } + + switch ( !defined('CRYPT_RSA_MODE') ) { // ie. only run this if the above didn't set CRYPT_RSA_MODE already + case extension_loaded('openssl') && version_compare(PHP_VERSION, '4.2.0', '>=') && file_exists($this->configFile): + // some versions of XAMPP have mismatched versions of OpenSSL which causes it not to work + ob_start(); + phpinfo(); + $content = ob_get_contents(); + ob_end_clean(); + + preg_match_all('#OpenSSL (Header|Library) Version(.*)#im', $content, $matches); + + $versions = array(); + if (!empty($matches[1])) { + for ($i = 0; $i < count($matches[1]); $i++) { + $versions[$matches[1][$i]] = trim(str_replace('=>', '', strip_tags($matches[2][$i]))); + } + } + + // it doesn't appear that OpenSSL versions were reported upon until PHP 5.3+ + switch (true) { + case !isset($versions['Header']): + case !isset($versions['Library']): + case $versions['Header'] == $versions['Library']: + define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_OPENSSL); + break; + default: + define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL); + define('MATH_BIGINTEGER_OPENSSL_DISABLE', true); + } break; - default: + case true: define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL); } } - if (!defined('CRYPT_RSA_COMMENT')) { - define('CRYPT_RSA_COMMENT', 'phpseclib-generated-key'); - } - $this->zero = new Math_BigInteger(); $this->one = new Math_BigInteger(1); @@ -642,12 +673,12 @@ class Crypt_RSA { $exponents[$i] = $e->modInverse($temp); } - list($lcm) = $lcm['top']->divide($lcm['bottom']); - $gcd = $lcm->gcd($e); + list($temp) = $lcm['top']->divide($lcm['bottom']); + $gcd = $temp->gcd($e); $i0 = 1; } while (!$gcd->equals($this->one)); - $d = $e->modInverse($lcm); + $d = $e->modInverse($temp); $coefficients[2] = $primes[2]->modInverse($primes[1]); @@ -720,16 +751,16 @@ class Crypt_RSA { $key = "PuTTY-User-Key-File-2: ssh-rsa\r\nEncryption: "; $encryption = (!empty($this->password) || is_string($this->password)) ? 'aes256-cbc' : 'none'; $key.= $encryption; - $key.= "\r\nComment: " . CRYPT_RSA_COMMENT . "\r\n"; + $key.= "\r\nComment: " . $this->comment . "\r\n"; $public = pack('Na*Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($raw['publicExponent']), $raw['publicExponent'], strlen($raw['modulus']), $raw['modulus'] ); $source = pack('Na*Na*Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($encryption), $encryption, - strlen(CRYPT_RSA_COMMENT), CRYPT_RSA_COMMENT, strlen($public), $public + strlen($this->comment), $this->comment, strlen($public), $public ); $public = base64_encode($public); - $key.= "Public-Lines: " . ((strlen($public) + 32) >> 6) . "\r\n"; + $key.= "Public-Lines: " . ((strlen($public) + 63) >> 6) . "\r\n"; $key.= chunk_split($public, 64); $private = pack('Na*Na*Na*Na*', strlen($raw['privateExponent']), $raw['privateExponent'], strlen($raw['prime1']), $raw['prime1'], @@ -760,7 +791,7 @@ class Crypt_RSA { } $private = base64_encode($private); - $key.= 'Private-Lines: ' . ((strlen($private) + 32) >> 6) . "\r\n"; + $key.= 'Private-Lines: ' . ((strlen($private) + 63) >> 6) . "\r\n"; $key.= chunk_split($private, 64); if (!class_exists('Crypt_Hash')) { require_once('Crypt/Hash.php'); @@ -853,7 +884,7 @@ class Crypt_RSA { // mpint e // mpint n $RSAPublicKey = pack('Na*Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($publicExponent), $publicExponent, strlen($modulus), $modulus); - $RSAPublicKey = 'ssh-rsa ' . base64_encode($RSAPublicKey) . ' ' . CRYPT_RSA_COMMENT; + $RSAPublicKey = 'ssh-rsa ' . base64_encode($RSAPublicKey) . ' ' . $this->comment; return $RSAPublicKey; default: // eg. CRYPT_RSA_PUBLIC_FORMAT_PKCS1_RAW or CRYPT_RSA_PUBLIC_FORMAT_PKCS1 @@ -960,13 +991,19 @@ class Crypt_RSA { if (preg_match('#DEK-Info: (.+),(.+)#', $key, $matches)) { $iv = pack('H*', trim($matches[2])); $symkey = pack('H*', md5($this->password . substr($iv, 0, 8))); // symkey is short for symmetric key - $symkey.= substr(pack('H*', md5($symkey . $this->password . $iv)), 0, 8); + $symkey.= pack('H*', md5($symkey . $this->password . substr($iv, 0, 8))); $ciphertext = preg_replace('#.+(\r|\n|\r\n)\1|[\r\n]|-.+-| #s', '', $key); $ciphertext = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $ciphertext) ? base64_decode($ciphertext) : false; if ($ciphertext === false) { $ciphertext = $key; } switch ($matches[1]) { + case 'AES-256-CBC': + if (!class_exists('Crypt_AES')) { + require_once('Crypt/AES.php'); + } + $crypto = new Crypt_AES(); + break; case 'AES-128-CBC': if (!class_exists('Crypt_AES')) { require_once('Crypt/AES.php'); @@ -984,6 +1021,7 @@ class Crypt_RSA { if (!class_exists('Crypt_TripleDES')) { require_once('Crypt/TripleDES.php'); } + $symkey = substr($symkey, 0, 24); $crypto = new Crypt_TripleDES(); break; case 'DES-CBC': @@ -1121,11 +1159,15 @@ class Crypt_RSA { return $components; case CRYPT_RSA_PUBLIC_FORMAT_OPENSSH: - $key = base64_decode(preg_replace('#^ssh-rsa | .+$#', '', $key)); + $parts = explode(' ', $key, 3); + + $key = isset($parts[1]) ? base64_decode($parts[1]) : false; if ($key === false) { return false; } + $comment = isset($parts[2]) ? $parts[2] : false; + $cleanup = substr($key, 0, 11) == "\0\0\0\7ssh-rsa"; if (strlen($key) <= 4) { @@ -1147,12 +1189,14 @@ class Crypt_RSA { $realModulus = new Math_BigInteger($this->_string_shift($key, $length), -256); return strlen($key) ? false : array( 'modulus' => $realModulus, - 'publicExponent' => $modulus + 'publicExponent' => $modulus, + 'comment' => $comment ); } else { return strlen($key) ? false : array( 'modulus' => $modulus, - 'publicExponent' => $publicExponent + 'publicExponent' => $publicExponent, + 'comment' => $comment ); } // http://www.w3.org/TR/xmldsig-core/#sec-RSAKeyValue @@ -1180,6 +1224,7 @@ class Crypt_RSA { return false; } $encryption = trim(preg_replace('#Encryption: (.+)#', '$1', $key[1])); + $comment = trim(preg_replace('#Comment: (.+)#', '$1', $key[2])); $publicLength = trim(preg_replace('#Public-Lines: (\d+)#', '$1', $key[3])); $public = base64_decode(implode('', array_map('trim', array_slice($key, 4, $publicLength)))); @@ -1297,9 +1342,6 @@ class Crypt_RSA { break; case 'D': $this->current = &$this->components['privateExponent']; - break; - default: - unset($this->current); } $this->current = ''; } @@ -1315,11 +1357,10 @@ class Crypt_RSA { */ function _stop_element_handler($parser, $name) { - //$name = strtoupper($name); - if ($name == 'RSAKEYVALUE') { - return; + if (isset($this->current)) { + $this->current = new Math_BigInteger(base64_decode($this->current), 256); + unset($this->current); } - $this->current = new Math_BigInteger(base64_decode($this->current), 256); } /** @@ -1350,6 +1391,53 @@ class Crypt_RSA { */ function loadKey($key, $type = false) { + if (is_object($key) && strtolower(get_class($key)) == 'crypt_rsa') { + $this->privateKeyFormat = $key->privateKeyFormat; + $this->publicKeyFormat = $key->publicKeyFormat; + $this->k = $key->k; + $this->hLen = $key->hLen; + $this->sLen = $key->sLen; + $this->mgfHLen = $key->mgfHLen; + $this->encryptionMode = $key->encryptionMode; + $this->signatureMode = $key->signatureMode; + $this->password = $key->password; + $this->configFile = $key->configFile; + $this->comment = $key->comment; + + if (is_object($key->hash)) { + $this->hash = new Crypt_Hash($key->hash->getHash()); + } + if (is_object($key->mgfHash)) { + $this->mgfHash = new Crypt_Hash($key->mgfHash->getHash()); + } + + if (is_object($key->modulus)) { + $this->modulus = $key->modulus->copy(); + } + if (is_object($key->exponent)) { + $this->exponent = $key->exponent->copy(); + } + if (is_object($key->publicExponent)) { + $this->publicExponent = $key->publicExponent->copy(); + } + + $this->primes = array(); + $this->exponents = array(); + $this->coefficients = array(); + + foreach ($this->primes as $prime) { + $this->primes[] = $prime->copy(); + } + foreach ($this->exponents as $exponent) { + $this->exponents[] = $exponent->copy(); + } + foreach ($this->coefficients as $coefficient) { + $this->coefficients[] = $coefficient->copy(); + } + + return true; + } + if ($type === false) { $types = array( CRYPT_RSA_PUBLIC_FORMAT_RAW, @@ -1373,6 +1461,9 @@ class Crypt_RSA { return false; } + if (isset($components['comment']) && $components['comment'] !== false) { + $this->comment = $components['comment']; + } $this->modulus = $components['modulus']; $this->k = strlen($this->modulus->toBytes()); $this->exponent = isset($components['privateExponent']) ? $components['privateExponent'] : $components['publicExponent']; @@ -1428,6 +1519,11 @@ class Crypt_RSA { */ function setPublicKey($key = false, $type = false) { + // if a public key has already been loaded return false + if (!empty($this->publicExponent)) { + return false; + } + if ($key === false && !empty($this->modulus)) { $this->publicExponent = $this->exponent; return true; @@ -1552,6 +1648,18 @@ class Crypt_RSA { return $key !== false ? $key : ''; } + /** + * __clone() magic method + * + * @access public + */ + function __clone() + { + $key = new Crypt_RSA(); + $key->loadKey($this); + return $key; + } + /** * Generates the smallest and largest numbers requiring $bits bits * @@ -1582,7 +1690,7 @@ class Crypt_RSA { * DER-decode the length * * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See - * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 § 8.1.3} for more information. + * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information. * * @access private * @param String $string @@ -1603,7 +1711,7 @@ class Crypt_RSA { * DER-encode the length * * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See - * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 § 8.1.3} for more information. + * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information. * * @access private * @param Integer $length @@ -1872,7 +1980,7 @@ class Crypt_RSA { * * Protects against a particular type of timing attack described. * - * See {@link http://codahale.com/a-lesson-in-timing-attacks/ A Lesson In Timing Attacks (or, Don’t use MessageDigest.isEquals)} + * See {@link http://codahale.com/a-lesson-in-timing-attacks/ A Lesson In Timing Attacks (or, Don't use MessageDigest.isEquals)} * * Thanks for the heads up singpolyma! * @@ -2135,6 +2243,7 @@ class Crypt_RSA { } // EME-PKCS1-v1_5 encoding + $psLen = $this->k - $mLen - 3; $ps = ''; while (strlen($ps) != $psLen) { @@ -2142,7 +2251,14 @@ class Crypt_RSA { $temp = str_replace("\x00", '', $temp); $ps.= $temp; } - $em = chr(0) . chr(2) . $ps . chr(0) . $m; + $type = 2; + // see the comments of _rsaes_pkcs1_v1_5_decrypt() to understand why this is being done + if (defined('CRYPT_RSA_PKCS15_COMPAT') && (!isset($this->publicExponent) || $this->exponent !== $this->publicExponent)) { + $type = 1; + // "The padding string PS shall consist of k-3-||D|| octets. ... for block type 01, they shall have value FF" + $ps = str_repeat("\xFF", $psLen); + } + $em = chr(0) . chr($type) . $ps . chr(0) . $m; // RSA encryption $m = $this->_os2ip($em); @@ -2515,6 +2631,28 @@ class Crypt_RSA { $this->signatureMode = $mode; } + /** + * Set public key comment. + * + * @access public + * @param String $comment + */ + function setComment($comment) + { + $this->comment = $comment; + } + + /** + * Get public key comment. + * + * @access public + * @return String + */ + function getComment() + { + return $this->comment; + } + /** * Encryption * diff --git a/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/Random.php b/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/Random.php index a60857df95..8532aab5a5 100644 --- a/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/Random.php +++ b/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/Random.php @@ -21,10 +21,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -38,10 +38,16 @@ * @author Jim Wigginton * @copyright MMVII Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @version $Id: Random.php,v 1.9 2010/04/24 06:40:48 terrafrost Exp $ * @link http://phpseclib.sourceforge.net */ +/** + * "Is Windows" test + * + * @access private + */ +define('CRYPT_RANDOM_IS_WINDOWS', strtoupper(substr(PHP_OS, 0, 3)) === 'WIN'); + /** * Generate a random string. * @@ -53,9 +59,9 @@ * @return String * @access public */ -function crypt_random_string($length) { - // PHP_OS & "\xDF\xDF\xDF" == strtoupper(substr(PHP_OS, 0, 3)), but a lot faster - if ((PHP_OS & "\xDF\xDF\xDF") === 'WIN') { +function crypt_random_string($length) +{ + if (CRYPT_RANDOM_IS_WINDOWS) { // method 1. prior to PHP 5.3 this would call rand() on windows hence the function_exists('class_alias') call. // ie. class_alias is a function that was introduced in PHP 5.3 if (function_exists('mcrypt_create_iv') && function_exists('class_alias')) { @@ -143,7 +149,7 @@ function crypt_random_string($length) { serialize($_POST) . serialize($_GET) . serialize($_COOKIE) . - serialize($_GLOBAL) . + serialize($GLOBALS) . serialize($_SESSION) . serialize($_OLD_SESSION) )); diff --git a/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/Rijndael.php b/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/Rijndael.php index 335d5233c4..c63e0ff7e3 100644 --- a/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/Rijndael.php +++ b/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/Rijndael.php @@ -4,25 +4,26 @@ /** * Pure-PHP implementation of Rijndael. * - * Does not use mcrypt, even when available, for reasons that are explained below. + * Uses mcrypt, if available/possible, and an internal implementation, otherwise. * * PHP versions 4 and 5 * - * If {@link Crypt_Rijndael::setBlockLength() setBlockLength()} isn't called, it'll be assumed to be 128 bits. If - * {@link Crypt_Rijndael::setKeyLength() setKeyLength()} isn't called, it'll be calculated from - * {@link Crypt_Rijndael::setKey() setKey()}. ie. if the key is 128-bits, the key length will be 128-bits. If it's - * 136-bits it'll be null-padded to 160-bits and 160 bits will be the key length until + * If {@link Crypt_Rijndael::setBlockLength() setBlockLength()} isn't called, it'll be assumed to be 128 bits. If + * {@link Crypt_Rijndael::setKeyLength() setKeyLength()} isn't called, it'll be calculated from + * {@link Crypt_Rijndael::setKey() setKey()}. ie. if the key is 128-bits, the key length will be 128-bits. If it's + * 136-bits it'll be null-padded to 192-bits and 192 bits will be the key length until * {@link Crypt_Rijndael::setKey() setKey()} is called, again, at which point, it'll be recalculated. * * Not all Rijndael implementations may support 160-bits or 224-bits as the block length / key length. mcrypt, for example, * does not. AES, itself, only supports block lengths of 128 and key lengths of 128, 192, and 256. * {@link http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=10 Rijndael-ammended.pdf#page=10} defines the * algorithm for block lengths of 192 and 256 but not for block lengths / key lengths of 160 and 224. Indeed, 160 and 224 - * are first defined as valid key / block lengths in - * {@link http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=44 Rijndael-ammended.pdf#page=44}: + * are first defined as valid key / block lengths in + * {@link http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=44 Rijndael-ammended.pdf#page=44}: * Extensions: Other block and Cipher Key lengths. + * Note: Use of 160/224-bit Keys must be explicitly set by setKeyLength(160) respectively setKeyLength(224). * - * {@internal The variable names are the same as those in + * {@internal The variable names are the same as those in * {@link http://www.csrc.nist.gov/publications/fips/fips197/fips-197.pdf#page=10 fips-197.pdf#page=10}.}} * * Here's a short example of how to use this library: @@ -50,10 +51,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -67,10 +68,18 @@ * @author Jim Wigginton * @copyright MMVIII Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @version $Id: Rijndael.php,v 1.12 2010/02/09 06:10:26 terrafrost Exp $ * @link http://phpseclib.sourceforge.net */ +/** + * Include Crypt_Base + * + * Base cipher class + */ +if (!class_exists('Crypt_Base')) { + require_once('Base.php'); +} + /**#@+ * @access public * @see Crypt_Rijndael::encrypt() @@ -83,31 +92,31 @@ * * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29 */ -define('CRYPT_RIJNDAEL_MODE_CTR', -1); +define('CRYPT_RIJNDAEL_MODE_CTR', CRYPT_MODE_CTR); /** * Encrypt / decrypt using the Electronic Code Book mode. * * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29 */ -define('CRYPT_RIJNDAEL_MODE_ECB', 1); +define('CRYPT_RIJNDAEL_MODE_ECB', CRYPT_MODE_ECB); /** * Encrypt / decrypt using the Code Book Chaining mode. * * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29 */ -define('CRYPT_RIJNDAEL_MODE_CBC', 2); +define('CRYPT_RIJNDAEL_MODE_CBC', CRYPT_MODE_CBC); /** * Encrypt / decrypt using the Cipher Feedback mode. * * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29 */ -define('CRYPT_RIJNDAEL_MODE_CFB', 3); +define('CRYPT_RIJNDAEL_MODE_CFB', CRYPT_MODE_CFB); /** * Encrypt / decrypt using the Cipher Feedback mode. * * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29 */ -define('CRYPT_RIJNDAEL_MODE_OFB', 4); +define('CRYPT_RIJNDAEL_MODE_OFB', CRYPT_MODE_OFB); /**#@-*/ /**#@+ @@ -117,11 +126,11 @@ define('CRYPT_RIJNDAEL_MODE_OFB', 4); /** * Toggles the internal implementation */ -define('CRYPT_RIJNDAEL_MODE_INTERNAL', 1); +define('CRYPT_RIJNDAEL_MODE_INTERNAL', CRYPT_MODE_INTERNAL); /** * Toggles the mcrypt implementation */ -define('CRYPT_RIJNDAEL_MODE_MCRYPT', 2); +define('CRYPT_RIJNDAEL_MODE_MCRYPT', CRYPT_MODE_MCRYPT); /**#@-*/ /** @@ -132,80 +141,51 @@ define('CRYPT_RIJNDAEL_MODE_MCRYPT', 2); * @access public * @package Crypt_Rijndael */ -class Crypt_Rijndael { +class Crypt_Rijndael extends Crypt_Base { /** - * The Encryption Mode + * The default password key_size used by setPassword() * - * @see Crypt_Rijndael::Crypt_Rijndael() + * @see Crypt_Base::password_key_size + * @see Crypt_Base::setPassword() * @var Integer * @access private */ - var $mode; + var $password_key_size = 16; /** - * The Key + * The namespace used by the cipher for its constants. * - * @see Crypt_Rijndael::setKey() + * @see Crypt_Base::const_namespace * @var String * @access private */ - var $key = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; + var $const_namespace = 'RIJNDAEL'; /** - * The Initialization Vector + * The mcrypt specific name of the cipher * - * @see Crypt_Rijndael::setIV() + * Mcrypt is useable for 128/192/256-bit $block_size/$key_size. For 160/224 not. + * Crypt_Rijndael determines automatically whether mcrypt is useable + * or not for the current $block_size/$key_size. + * In case of, $cipher_name_mcrypt will be set dynamicaly at run time accordingly. + * + * @see Crypt_Base::cipher_name_mcrypt + * @see Crypt_Base::engine + * @see _setupEngine() * @var String * @access private */ - var $iv = ''; + var $cipher_name_mcrypt = 'rijndael-128'; /** - * A "sliding" Initialization Vector + * The default salt used by setPassword() * - * @see Crypt_Rijndael::enableContinuousBuffer() + * @see Crypt_Base::password_default_salt + * @see Crypt_Base::setPassword() * @var String * @access private */ - var $encryptIV = ''; - - /** - * A "sliding" Initialization Vector - * - * @see Crypt_Rijndael::enableContinuousBuffer() - * @var String - * @access private - */ - var $decryptIV = ''; - - /** - * Continuous Buffer status - * - * @see Crypt_Rijndael::enableContinuousBuffer() - * @var Boolean - * @access private - */ - var $continuousBuffer = false; - - /** - * Padding status - * - * @see Crypt_Rijndael::enablePadding() - * @var Boolean - * @access private - */ - var $padding = true; - - /** - * Does the key schedule need to be (re)calculated? - * - * @see setKey() - * @see setBlockLength() - * @see setKeyLength() - * @var Boolean - * @access private - */ - var $changed = true; + var $password_default_salt = 'phpseclib'; /** * Has the key length explicitly been set or should it be derived from the key, itself? @@ -234,25 +214,14 @@ class Crypt_Rijndael { */ var $dw; - /** - * The Block Length - * - * @see setBlockLength() - * @var Integer - * @access private - * @internal The max value is 32, the min value is 16. All valid values are multiples of 4. Exists in conjunction with - * $Nb because we need this value and not $Nb to pad strings appropriately. - */ - var $block_size = 16; - /** * The Block Length divided by 32 * * @see setBlockLength() * @var Integer * @access private - * @internal The max value is 256 / 32 = 8, the min value is 128 / 32 = 4. Exists in conjunction with $block_size - * because the encryption / decryption / key schedule creation requires this number and not $block_size. We could + * @internal The max value is 256 / 32 = 8, the min value is 128 / 32 = 4. Exists in conjunction with $block_size + * because the encryption / decryption / key schedule creation requires this number and not $block_size. We could * derive this from $block_size or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu * of that, we'll just precompute it once. * @@ -265,8 +234,8 @@ class Crypt_Rijndael { * @see setKeyLength() * @var Integer * @access private - * @internal The max value is 256 / 8 = 32, the min value is 128 / 8 = 16. Exists in conjunction with $key_size - * because the encryption / decryption / key schedule creation requires this number and not $key_size. We could + * @internal The max value is 256 / 8 = 32, the min value is 128 / 8 = 16. Exists in conjunction with $Nk + * because the encryption / decryption / key schedule creation requires this number and not $key_size. We could * derive this from $key_size or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu * of that, we'll just precompute it once. */ @@ -300,224 +269,439 @@ class Crypt_Rijndael { var $c; /** - * Precomputed mixColumns table + * Holds the last used key- and block_size information * - * @see Crypt_Rijndael() * @var Array * @access private */ - var $t0; + var $kl; /** * Precomputed mixColumns table * - * @see Crypt_Rijndael() + * According to (section 5.2.1), + * precomputed tables can be used in the mixColumns phase. in that example, they're assigned t0...t3, so + * those are the names we'll use. + * + * @see Crypt_Rijndael:_encryptBlock() + * @see Crypt_Rijndael:_decryptBlock() * @var Array * @access private */ - var $t1; + var $t0 = array( + 0xC66363A5, 0xF87C7C84, 0xEE777799, 0xF67B7B8D, 0xFFF2F20D, 0xD66B6BBD, 0xDE6F6FB1, 0x91C5C554, + 0x60303050, 0x02010103, 0xCE6767A9, 0x562B2B7D, 0xE7FEFE19, 0xB5D7D762, 0x4DABABE6, 0xEC76769A, + 0x8FCACA45, 0x1F82829D, 0x89C9C940, 0xFA7D7D87, 0xEFFAFA15, 0xB25959EB, 0x8E4747C9, 0xFBF0F00B, + 0x41ADADEC, 0xB3D4D467, 0x5FA2A2FD, 0x45AFAFEA, 0x239C9CBF, 0x53A4A4F7, 0xE4727296, 0x9BC0C05B, + 0x75B7B7C2, 0xE1FDFD1C, 0x3D9393AE, 0x4C26266A, 0x6C36365A, 0x7E3F3F41, 0xF5F7F702, 0x83CCCC4F, + 0x6834345C, 0x51A5A5F4, 0xD1E5E534, 0xF9F1F108, 0xE2717193, 0xABD8D873, 0x62313153, 0x2A15153F, + 0x0804040C, 0x95C7C752, 0x46232365, 0x9DC3C35E, 0x30181828, 0x379696A1, 0x0A05050F, 0x2F9A9AB5, + 0x0E070709, 0x24121236, 0x1B80809B, 0xDFE2E23D, 0xCDEBEB26, 0x4E272769, 0x7FB2B2CD, 0xEA75759F, + 0x1209091B, 0x1D83839E, 0x582C2C74, 0x341A1A2E, 0x361B1B2D, 0xDC6E6EB2, 0xB45A5AEE, 0x5BA0A0FB, + 0xA45252F6, 0x763B3B4D, 0xB7D6D661, 0x7DB3B3CE, 0x5229297B, 0xDDE3E33E, 0x5E2F2F71, 0x13848497, + 0xA65353F5, 0xB9D1D168, 0x00000000, 0xC1EDED2C, 0x40202060, 0xE3FCFC1F, 0x79B1B1C8, 0xB65B5BED, + 0xD46A6ABE, 0x8DCBCB46, 0x67BEBED9, 0x7239394B, 0x944A4ADE, 0x984C4CD4, 0xB05858E8, 0x85CFCF4A, + 0xBBD0D06B, 0xC5EFEF2A, 0x4FAAAAE5, 0xEDFBFB16, 0x864343C5, 0x9A4D4DD7, 0x66333355, 0x11858594, + 0x8A4545CF, 0xE9F9F910, 0x04020206, 0xFE7F7F81, 0xA05050F0, 0x783C3C44, 0x259F9FBA, 0x4BA8A8E3, + 0xA25151F3, 0x5DA3A3FE, 0x804040C0, 0x058F8F8A, 0x3F9292AD, 0x219D9DBC, 0x70383848, 0xF1F5F504, + 0x63BCBCDF, 0x77B6B6C1, 0xAFDADA75, 0x42212163, 0x20101030, 0xE5FFFF1A, 0xFDF3F30E, 0xBFD2D26D, + 0x81CDCD4C, 0x180C0C14, 0x26131335, 0xC3ECEC2F, 0xBE5F5FE1, 0x359797A2, 0x884444CC, 0x2E171739, + 0x93C4C457, 0x55A7A7F2, 0xFC7E7E82, 0x7A3D3D47, 0xC86464AC, 0xBA5D5DE7, 0x3219192B, 0xE6737395, + 0xC06060A0, 0x19818198, 0x9E4F4FD1, 0xA3DCDC7F, 0x44222266, 0x542A2A7E, 0x3B9090AB, 0x0B888883, + 0x8C4646CA, 0xC7EEEE29, 0x6BB8B8D3, 0x2814143C, 0xA7DEDE79, 0xBC5E5EE2, 0x160B0B1D, 0xADDBDB76, + 0xDBE0E03B, 0x64323256, 0x743A3A4E, 0x140A0A1E, 0x924949DB, 0x0C06060A, 0x4824246C, 0xB85C5CE4, + 0x9FC2C25D, 0xBDD3D36E, 0x43ACACEF, 0xC46262A6, 0x399191A8, 0x319595A4, 0xD3E4E437, 0xF279798B, + 0xD5E7E732, 0x8BC8C843, 0x6E373759, 0xDA6D6DB7, 0x018D8D8C, 0xB1D5D564, 0x9C4E4ED2, 0x49A9A9E0, + 0xD86C6CB4, 0xAC5656FA, 0xF3F4F407, 0xCFEAEA25, 0xCA6565AF, 0xF47A7A8E, 0x47AEAEE9, 0x10080818, + 0x6FBABAD5, 0xF0787888, 0x4A25256F, 0x5C2E2E72, 0x381C1C24, 0x57A6A6F1, 0x73B4B4C7, 0x97C6C651, + 0xCBE8E823, 0xA1DDDD7C, 0xE874749C, 0x3E1F1F21, 0x964B4BDD, 0x61BDBDDC, 0x0D8B8B86, 0x0F8A8A85, + 0xE0707090, 0x7C3E3E42, 0x71B5B5C4, 0xCC6666AA, 0x904848D8, 0x06030305, 0xF7F6F601, 0x1C0E0E12, + 0xC26161A3, 0x6A35355F, 0xAE5757F9, 0x69B9B9D0, 0x17868691, 0x99C1C158, 0x3A1D1D27, 0x279E9EB9, + 0xD9E1E138, 0xEBF8F813, 0x2B9898B3, 0x22111133, 0xD26969BB, 0xA9D9D970, 0x078E8E89, 0x339494A7, + 0x2D9B9BB6, 0x3C1E1E22, 0x15878792, 0xC9E9E920, 0x87CECE49, 0xAA5555FF, 0x50282878, 0xA5DFDF7A, + 0x038C8C8F, 0x59A1A1F8, 0x09898980, 0x1A0D0D17, 0x65BFBFDA, 0xD7E6E631, 0x844242C6, 0xD06868B8, + 0x824141C3, 0x299999B0, 0x5A2D2D77, 0x1E0F0F11, 0x7BB0B0CB, 0xA85454FC, 0x6DBBBBD6, 0x2C16163A + ); /** * Precomputed mixColumns table * - * @see Crypt_Rijndael() + * @see Crypt_Rijndael:_encryptBlock() + * @see Crypt_Rijndael:_decryptBlock() * @var Array * @access private */ - var $t2; + var $t1 = array( + 0xA5C66363, 0x84F87C7C, 0x99EE7777, 0x8DF67B7B, 0x0DFFF2F2, 0xBDD66B6B, 0xB1DE6F6F, 0x5491C5C5, + 0x50603030, 0x03020101, 0xA9CE6767, 0x7D562B2B, 0x19E7FEFE, 0x62B5D7D7, 0xE64DABAB, 0x9AEC7676, + 0x458FCACA, 0x9D1F8282, 0x4089C9C9, 0x87FA7D7D, 0x15EFFAFA, 0xEBB25959, 0xC98E4747, 0x0BFBF0F0, + 0xEC41ADAD, 0x67B3D4D4, 0xFD5FA2A2, 0xEA45AFAF, 0xBF239C9C, 0xF753A4A4, 0x96E47272, 0x5B9BC0C0, + 0xC275B7B7, 0x1CE1FDFD, 0xAE3D9393, 0x6A4C2626, 0x5A6C3636, 0x417E3F3F, 0x02F5F7F7, 0x4F83CCCC, + 0x5C683434, 0xF451A5A5, 0x34D1E5E5, 0x08F9F1F1, 0x93E27171, 0x73ABD8D8, 0x53623131, 0x3F2A1515, + 0x0C080404, 0x5295C7C7, 0x65462323, 0x5E9DC3C3, 0x28301818, 0xA1379696, 0x0F0A0505, 0xB52F9A9A, + 0x090E0707, 0x36241212, 0x9B1B8080, 0x3DDFE2E2, 0x26CDEBEB, 0x694E2727, 0xCD7FB2B2, 0x9FEA7575, + 0x1B120909, 0x9E1D8383, 0x74582C2C, 0x2E341A1A, 0x2D361B1B, 0xB2DC6E6E, 0xEEB45A5A, 0xFB5BA0A0, + 0xF6A45252, 0x4D763B3B, 0x61B7D6D6, 0xCE7DB3B3, 0x7B522929, 0x3EDDE3E3, 0x715E2F2F, 0x97138484, + 0xF5A65353, 0x68B9D1D1, 0x00000000, 0x2CC1EDED, 0x60402020, 0x1FE3FCFC, 0xC879B1B1, 0xEDB65B5B, + 0xBED46A6A, 0x468DCBCB, 0xD967BEBE, 0x4B723939, 0xDE944A4A, 0xD4984C4C, 0xE8B05858, 0x4A85CFCF, + 0x6BBBD0D0, 0x2AC5EFEF, 0xE54FAAAA, 0x16EDFBFB, 0xC5864343, 0xD79A4D4D, 0x55663333, 0x94118585, + 0xCF8A4545, 0x10E9F9F9, 0x06040202, 0x81FE7F7F, 0xF0A05050, 0x44783C3C, 0xBA259F9F, 0xE34BA8A8, + 0xF3A25151, 0xFE5DA3A3, 0xC0804040, 0x8A058F8F, 0xAD3F9292, 0xBC219D9D, 0x48703838, 0x04F1F5F5, + 0xDF63BCBC, 0xC177B6B6, 0x75AFDADA, 0x63422121, 0x30201010, 0x1AE5FFFF, 0x0EFDF3F3, 0x6DBFD2D2, + 0x4C81CDCD, 0x14180C0C, 0x35261313, 0x2FC3ECEC, 0xE1BE5F5F, 0xA2359797, 0xCC884444, 0x392E1717, + 0x5793C4C4, 0xF255A7A7, 0x82FC7E7E, 0x477A3D3D, 0xACC86464, 0xE7BA5D5D, 0x2B321919, 0x95E67373, + 0xA0C06060, 0x98198181, 0xD19E4F4F, 0x7FA3DCDC, 0x66442222, 0x7E542A2A, 0xAB3B9090, 0x830B8888, + 0xCA8C4646, 0x29C7EEEE, 0xD36BB8B8, 0x3C281414, 0x79A7DEDE, 0xE2BC5E5E, 0x1D160B0B, 0x76ADDBDB, + 0x3BDBE0E0, 0x56643232, 0x4E743A3A, 0x1E140A0A, 0xDB924949, 0x0A0C0606, 0x6C482424, 0xE4B85C5C, + 0x5D9FC2C2, 0x6EBDD3D3, 0xEF43ACAC, 0xA6C46262, 0xA8399191, 0xA4319595, 0x37D3E4E4, 0x8BF27979, + 0x32D5E7E7, 0x438BC8C8, 0x596E3737, 0xB7DA6D6D, 0x8C018D8D, 0x64B1D5D5, 0xD29C4E4E, 0xE049A9A9, + 0xB4D86C6C, 0xFAAC5656, 0x07F3F4F4, 0x25CFEAEA, 0xAFCA6565, 0x8EF47A7A, 0xE947AEAE, 0x18100808, + 0xD56FBABA, 0x88F07878, 0x6F4A2525, 0x725C2E2E, 0x24381C1C, 0xF157A6A6, 0xC773B4B4, 0x5197C6C6, + 0x23CBE8E8, 0x7CA1DDDD, 0x9CE87474, 0x213E1F1F, 0xDD964B4B, 0xDC61BDBD, 0x860D8B8B, 0x850F8A8A, + 0x90E07070, 0x427C3E3E, 0xC471B5B5, 0xAACC6666, 0xD8904848, 0x05060303, 0x01F7F6F6, 0x121C0E0E, + 0xA3C26161, 0x5F6A3535, 0xF9AE5757, 0xD069B9B9, 0x91178686, 0x5899C1C1, 0x273A1D1D, 0xB9279E9E, + 0x38D9E1E1, 0x13EBF8F8, 0xB32B9898, 0x33221111, 0xBBD26969, 0x70A9D9D9, 0x89078E8E, 0xA7339494, + 0xB62D9B9B, 0x223C1E1E, 0x92158787, 0x20C9E9E9, 0x4987CECE, 0xFFAA5555, 0x78502828, 0x7AA5DFDF, + 0x8F038C8C, 0xF859A1A1, 0x80098989, 0x171A0D0D, 0xDA65BFBF, 0x31D7E6E6, 0xC6844242, 0xB8D06868, + 0xC3824141, 0xB0299999, 0x775A2D2D, 0x111E0F0F, 0xCB7BB0B0, 0xFCA85454, 0xD66DBBBB, 0x3A2C1616 + ); /** * Precomputed mixColumns table * - * @see Crypt_Rijndael() + * @see Crypt_Rijndael:_encryptBlock() + * @see Crypt_Rijndael:_decryptBlock() * @var Array * @access private */ - var $t3; + var $t2 = array( + 0x63A5C663, 0x7C84F87C, 0x7799EE77, 0x7B8DF67B, 0xF20DFFF2, 0x6BBDD66B, 0x6FB1DE6F, 0xC55491C5, + 0x30506030, 0x01030201, 0x67A9CE67, 0x2B7D562B, 0xFE19E7FE, 0xD762B5D7, 0xABE64DAB, 0x769AEC76, + 0xCA458FCA, 0x829D1F82, 0xC94089C9, 0x7D87FA7D, 0xFA15EFFA, 0x59EBB259, 0x47C98E47, 0xF00BFBF0, + 0xADEC41AD, 0xD467B3D4, 0xA2FD5FA2, 0xAFEA45AF, 0x9CBF239C, 0xA4F753A4, 0x7296E472, 0xC05B9BC0, + 0xB7C275B7, 0xFD1CE1FD, 0x93AE3D93, 0x266A4C26, 0x365A6C36, 0x3F417E3F, 0xF702F5F7, 0xCC4F83CC, + 0x345C6834, 0xA5F451A5, 0xE534D1E5, 0xF108F9F1, 0x7193E271, 0xD873ABD8, 0x31536231, 0x153F2A15, + 0x040C0804, 0xC75295C7, 0x23654623, 0xC35E9DC3, 0x18283018, 0x96A13796, 0x050F0A05, 0x9AB52F9A, + 0x07090E07, 0x12362412, 0x809B1B80, 0xE23DDFE2, 0xEB26CDEB, 0x27694E27, 0xB2CD7FB2, 0x759FEA75, + 0x091B1209, 0x839E1D83, 0x2C74582C, 0x1A2E341A, 0x1B2D361B, 0x6EB2DC6E, 0x5AEEB45A, 0xA0FB5BA0, + 0x52F6A452, 0x3B4D763B, 0xD661B7D6, 0xB3CE7DB3, 0x297B5229, 0xE33EDDE3, 0x2F715E2F, 0x84971384, + 0x53F5A653, 0xD168B9D1, 0x00000000, 0xED2CC1ED, 0x20604020, 0xFC1FE3FC, 0xB1C879B1, 0x5BEDB65B, + 0x6ABED46A, 0xCB468DCB, 0xBED967BE, 0x394B7239, 0x4ADE944A, 0x4CD4984C, 0x58E8B058, 0xCF4A85CF, + 0xD06BBBD0, 0xEF2AC5EF, 0xAAE54FAA, 0xFB16EDFB, 0x43C58643, 0x4DD79A4D, 0x33556633, 0x85941185, + 0x45CF8A45, 0xF910E9F9, 0x02060402, 0x7F81FE7F, 0x50F0A050, 0x3C44783C, 0x9FBA259F, 0xA8E34BA8, + 0x51F3A251, 0xA3FE5DA3, 0x40C08040, 0x8F8A058F, 0x92AD3F92, 0x9DBC219D, 0x38487038, 0xF504F1F5, + 0xBCDF63BC, 0xB6C177B6, 0xDA75AFDA, 0x21634221, 0x10302010, 0xFF1AE5FF, 0xF30EFDF3, 0xD26DBFD2, + 0xCD4C81CD, 0x0C14180C, 0x13352613, 0xEC2FC3EC, 0x5FE1BE5F, 0x97A23597, 0x44CC8844, 0x17392E17, + 0xC45793C4, 0xA7F255A7, 0x7E82FC7E, 0x3D477A3D, 0x64ACC864, 0x5DE7BA5D, 0x192B3219, 0x7395E673, + 0x60A0C060, 0x81981981, 0x4FD19E4F, 0xDC7FA3DC, 0x22664422, 0x2A7E542A, 0x90AB3B90, 0x88830B88, + 0x46CA8C46, 0xEE29C7EE, 0xB8D36BB8, 0x143C2814, 0xDE79A7DE, 0x5EE2BC5E, 0x0B1D160B, 0xDB76ADDB, + 0xE03BDBE0, 0x32566432, 0x3A4E743A, 0x0A1E140A, 0x49DB9249, 0x060A0C06, 0x246C4824, 0x5CE4B85C, + 0xC25D9FC2, 0xD36EBDD3, 0xACEF43AC, 0x62A6C462, 0x91A83991, 0x95A43195, 0xE437D3E4, 0x798BF279, + 0xE732D5E7, 0xC8438BC8, 0x37596E37, 0x6DB7DA6D, 0x8D8C018D, 0xD564B1D5, 0x4ED29C4E, 0xA9E049A9, + 0x6CB4D86C, 0x56FAAC56, 0xF407F3F4, 0xEA25CFEA, 0x65AFCA65, 0x7A8EF47A, 0xAEE947AE, 0x08181008, + 0xBAD56FBA, 0x7888F078, 0x256F4A25, 0x2E725C2E, 0x1C24381C, 0xA6F157A6, 0xB4C773B4, 0xC65197C6, + 0xE823CBE8, 0xDD7CA1DD, 0x749CE874, 0x1F213E1F, 0x4BDD964B, 0xBDDC61BD, 0x8B860D8B, 0x8A850F8A, + 0x7090E070, 0x3E427C3E, 0xB5C471B5, 0x66AACC66, 0x48D89048, 0x03050603, 0xF601F7F6, 0x0E121C0E, + 0x61A3C261, 0x355F6A35, 0x57F9AE57, 0xB9D069B9, 0x86911786, 0xC15899C1, 0x1D273A1D, 0x9EB9279E, + 0xE138D9E1, 0xF813EBF8, 0x98B32B98, 0x11332211, 0x69BBD269, 0xD970A9D9, 0x8E89078E, 0x94A73394, + 0x9BB62D9B, 0x1E223C1E, 0x87921587, 0xE920C9E9, 0xCE4987CE, 0x55FFAA55, 0x28785028, 0xDF7AA5DF, + 0x8C8F038C, 0xA1F859A1, 0x89800989, 0x0D171A0D, 0xBFDA65BF, 0xE631D7E6, 0x42C68442, 0x68B8D068, + 0x41C38241, 0x99B02999, 0x2D775A2D, 0x0F111E0F, 0xB0CB7BB0, 0x54FCA854, 0xBBD66DBB, 0x163A2C16 + ); + + /** + * Precomputed mixColumns table + * + * @see Crypt_Rijndael:_encryptBlock() + * @see Crypt_Rijndael:_decryptBlock() + * @var Array + * @access private + */ + var $t3 = array( + 0x6363A5C6, 0x7C7C84F8, 0x777799EE, 0x7B7B8DF6, 0xF2F20DFF, 0x6B6BBDD6, 0x6F6FB1DE, 0xC5C55491, + 0x30305060, 0x01010302, 0x6767A9CE, 0x2B2B7D56, 0xFEFE19E7, 0xD7D762B5, 0xABABE64D, 0x76769AEC, + 0xCACA458F, 0x82829D1F, 0xC9C94089, 0x7D7D87FA, 0xFAFA15EF, 0x5959EBB2, 0x4747C98E, 0xF0F00BFB, + 0xADADEC41, 0xD4D467B3, 0xA2A2FD5F, 0xAFAFEA45, 0x9C9CBF23, 0xA4A4F753, 0x727296E4, 0xC0C05B9B, + 0xB7B7C275, 0xFDFD1CE1, 0x9393AE3D, 0x26266A4C, 0x36365A6C, 0x3F3F417E, 0xF7F702F5, 0xCCCC4F83, + 0x34345C68, 0xA5A5F451, 0xE5E534D1, 0xF1F108F9, 0x717193E2, 0xD8D873AB, 0x31315362, 0x15153F2A, + 0x04040C08, 0xC7C75295, 0x23236546, 0xC3C35E9D, 0x18182830, 0x9696A137, 0x05050F0A, 0x9A9AB52F, + 0x0707090E, 0x12123624, 0x80809B1B, 0xE2E23DDF, 0xEBEB26CD, 0x2727694E, 0xB2B2CD7F, 0x75759FEA, + 0x09091B12, 0x83839E1D, 0x2C2C7458, 0x1A1A2E34, 0x1B1B2D36, 0x6E6EB2DC, 0x5A5AEEB4, 0xA0A0FB5B, + 0x5252F6A4, 0x3B3B4D76, 0xD6D661B7, 0xB3B3CE7D, 0x29297B52, 0xE3E33EDD, 0x2F2F715E, 0x84849713, + 0x5353F5A6, 0xD1D168B9, 0x00000000, 0xEDED2CC1, 0x20206040, 0xFCFC1FE3, 0xB1B1C879, 0x5B5BEDB6, + 0x6A6ABED4, 0xCBCB468D, 0xBEBED967, 0x39394B72, 0x4A4ADE94, 0x4C4CD498, 0x5858E8B0, 0xCFCF4A85, + 0xD0D06BBB, 0xEFEF2AC5, 0xAAAAE54F, 0xFBFB16ED, 0x4343C586, 0x4D4DD79A, 0x33335566, 0x85859411, + 0x4545CF8A, 0xF9F910E9, 0x02020604, 0x7F7F81FE, 0x5050F0A0, 0x3C3C4478, 0x9F9FBA25, 0xA8A8E34B, + 0x5151F3A2, 0xA3A3FE5D, 0x4040C080, 0x8F8F8A05, 0x9292AD3F, 0x9D9DBC21, 0x38384870, 0xF5F504F1, + 0xBCBCDF63, 0xB6B6C177, 0xDADA75AF, 0x21216342, 0x10103020, 0xFFFF1AE5, 0xF3F30EFD, 0xD2D26DBF, + 0xCDCD4C81, 0x0C0C1418, 0x13133526, 0xECEC2FC3, 0x5F5FE1BE, 0x9797A235, 0x4444CC88, 0x1717392E, + 0xC4C45793, 0xA7A7F255, 0x7E7E82FC, 0x3D3D477A, 0x6464ACC8, 0x5D5DE7BA, 0x19192B32, 0x737395E6, + 0x6060A0C0, 0x81819819, 0x4F4FD19E, 0xDCDC7FA3, 0x22226644, 0x2A2A7E54, 0x9090AB3B, 0x8888830B, + 0x4646CA8C, 0xEEEE29C7, 0xB8B8D36B, 0x14143C28, 0xDEDE79A7, 0x5E5EE2BC, 0x0B0B1D16, 0xDBDB76AD, + 0xE0E03BDB, 0x32325664, 0x3A3A4E74, 0x0A0A1E14, 0x4949DB92, 0x06060A0C, 0x24246C48, 0x5C5CE4B8, + 0xC2C25D9F, 0xD3D36EBD, 0xACACEF43, 0x6262A6C4, 0x9191A839, 0x9595A431, 0xE4E437D3, 0x79798BF2, + 0xE7E732D5, 0xC8C8438B, 0x3737596E, 0x6D6DB7DA, 0x8D8D8C01, 0xD5D564B1, 0x4E4ED29C, 0xA9A9E049, + 0x6C6CB4D8, 0x5656FAAC, 0xF4F407F3, 0xEAEA25CF, 0x6565AFCA, 0x7A7A8EF4, 0xAEAEE947, 0x08081810, + 0xBABAD56F, 0x787888F0, 0x25256F4A, 0x2E2E725C, 0x1C1C2438, 0xA6A6F157, 0xB4B4C773, 0xC6C65197, + 0xE8E823CB, 0xDDDD7CA1, 0x74749CE8, 0x1F1F213E, 0x4B4BDD96, 0xBDBDDC61, 0x8B8B860D, 0x8A8A850F, + 0x707090E0, 0x3E3E427C, 0xB5B5C471, 0x6666AACC, 0x4848D890, 0x03030506, 0xF6F601F7, 0x0E0E121C, + 0x6161A3C2, 0x35355F6A, 0x5757F9AE, 0xB9B9D069, 0x86869117, 0xC1C15899, 0x1D1D273A, 0x9E9EB927, + 0xE1E138D9, 0xF8F813EB, 0x9898B32B, 0x11113322, 0x6969BBD2, 0xD9D970A9, 0x8E8E8907, 0x9494A733, + 0x9B9BB62D, 0x1E1E223C, 0x87879215, 0xE9E920C9, 0xCECE4987, 0x5555FFAA, 0x28287850, 0xDFDF7AA5, + 0x8C8C8F03, 0xA1A1F859, 0x89898009, 0x0D0D171A, 0xBFBFDA65, 0xE6E631D7, 0x4242C684, 0x6868B8D0, + 0x4141C382, 0x9999B029, 0x2D2D775A, 0x0F0F111E, 0xB0B0CB7B, 0x5454FCA8, 0xBBBBD66D, 0x16163A2C + ); /** * Precomputed invMixColumns table * - * @see Crypt_Rijndael() + * @see Crypt_Rijndael:_encryptBlock() + * @see Crypt_Rijndael:_decryptBlock() * @var Array * @access private */ - var $dt0; + var $dt0 = array( + 0x51F4A750, 0x7E416553, 0x1A17A4C3, 0x3A275E96, 0x3BAB6BCB, 0x1F9D45F1, 0xACFA58AB, 0x4BE30393, + 0x2030FA55, 0xAD766DF6, 0x88CC7691, 0xF5024C25, 0x4FE5D7FC, 0xC52ACBD7, 0x26354480, 0xB562A38F, + 0xDEB15A49, 0x25BA1B67, 0x45EA0E98, 0x5DFEC0E1, 0xC32F7502, 0x814CF012, 0x8D4697A3, 0x6BD3F9C6, + 0x038F5FE7, 0x15929C95, 0xBF6D7AEB, 0x955259DA, 0xD4BE832D, 0x587421D3, 0x49E06929, 0x8EC9C844, + 0x75C2896A, 0xF48E7978, 0x99583E6B, 0x27B971DD, 0xBEE14FB6, 0xF088AD17, 0xC920AC66, 0x7DCE3AB4, + 0x63DF4A18, 0xE51A3182, 0x97513360, 0x62537F45, 0xB16477E0, 0xBB6BAE84, 0xFE81A01C, 0xF9082B94, + 0x70486858, 0x8F45FD19, 0x94DE6C87, 0x527BF8B7, 0xAB73D323, 0x724B02E2, 0xE31F8F57, 0x6655AB2A, + 0xB2EB2807, 0x2FB5C203, 0x86C57B9A, 0xD33708A5, 0x302887F2, 0x23BFA5B2, 0x02036ABA, 0xED16825C, + 0x8ACF1C2B, 0xA779B492, 0xF307F2F0, 0x4E69E2A1, 0x65DAF4CD, 0x0605BED5, 0xD134621F, 0xC4A6FE8A, + 0x342E539D, 0xA2F355A0, 0x058AE132, 0xA4F6EB75, 0x0B83EC39, 0x4060EFAA, 0x5E719F06, 0xBD6E1051, + 0x3E218AF9, 0x96DD063D, 0xDD3E05AE, 0x4DE6BD46, 0x91548DB5, 0x71C45D05, 0x0406D46F, 0x605015FF, + 0x1998FB24, 0xD6BDE997, 0x894043CC, 0x67D99E77, 0xB0E842BD, 0x07898B88, 0xE7195B38, 0x79C8EEDB, + 0xA17C0A47, 0x7C420FE9, 0xF8841EC9, 0x00000000, 0x09808683, 0x322BED48, 0x1E1170AC, 0x6C5A724E, + 0xFD0EFFFB, 0x0F853856, 0x3DAED51E, 0x362D3927, 0x0A0FD964, 0x685CA621, 0x9B5B54D1, 0x24362E3A, + 0x0C0A67B1, 0x9357E70F, 0xB4EE96D2, 0x1B9B919E, 0x80C0C54F, 0x61DC20A2, 0x5A774B69, 0x1C121A16, + 0xE293BA0A, 0xC0A02AE5, 0x3C22E043, 0x121B171D, 0x0E090D0B, 0xF28BC7AD, 0x2DB6A8B9, 0x141EA9C8, + 0x57F11985, 0xAF75074C, 0xEE99DDBB, 0xA37F60FD, 0xF701269F, 0x5C72F5BC, 0x44663BC5, 0x5BFB7E34, + 0x8B432976, 0xCB23C6DC, 0xB6EDFC68, 0xB8E4F163, 0xD731DCCA, 0x42638510, 0x13972240, 0x84C61120, + 0x854A247D, 0xD2BB3DF8, 0xAEF93211, 0xC729A16D, 0x1D9E2F4B, 0xDCB230F3, 0x0D8652EC, 0x77C1E3D0, + 0x2BB3166C, 0xA970B999, 0x119448FA, 0x47E96422, 0xA8FC8CC4, 0xA0F03F1A, 0x567D2CD8, 0x223390EF, + 0x87494EC7, 0xD938D1C1, 0x8CCAA2FE, 0x98D40B36, 0xA6F581CF, 0xA57ADE28, 0xDAB78E26, 0x3FADBFA4, + 0x2C3A9DE4, 0x5078920D, 0x6A5FCC9B, 0x547E4662, 0xF68D13C2, 0x90D8B8E8, 0x2E39F75E, 0x82C3AFF5, + 0x9F5D80BE, 0x69D0937C, 0x6FD52DA9, 0xCF2512B3, 0xC8AC993B, 0x10187DA7, 0xE89C636E, 0xDB3BBB7B, + 0xCD267809, 0x6E5918F4, 0xEC9AB701, 0x834F9AA8, 0xE6956E65, 0xAAFFE67E, 0x21BCCF08, 0xEF15E8E6, + 0xBAE79BD9, 0x4A6F36CE, 0xEA9F09D4, 0x29B07CD6, 0x31A4B2AF, 0x2A3F2331, 0xC6A59430, 0x35A266C0, + 0x744EBC37, 0xFC82CAA6, 0xE090D0B0, 0x33A7D815, 0xF104984A, 0x41ECDAF7, 0x7FCD500E, 0x1791F62F, + 0x764DD68D, 0x43EFB04D, 0xCCAA4D54, 0xE49604DF, 0x9ED1B5E3, 0x4C6A881B, 0xC12C1FB8, 0x4665517F, + 0x9D5EEA04, 0x018C355D, 0xFA877473, 0xFB0B412E, 0xB3671D5A, 0x92DBD252, 0xE9105633, 0x6DD64713, + 0x9AD7618C, 0x37A10C7A, 0x59F8148E, 0xEB133C89, 0xCEA927EE, 0xB761C935, 0xE11CE5ED, 0x7A47B13C, + 0x9CD2DF59, 0x55F2733F, 0x1814CE79, 0x73C737BF, 0x53F7CDEA, 0x5FFDAA5B, 0xDF3D6F14, 0x7844DB86, + 0xCAAFF381, 0xB968C43E, 0x3824342C, 0xC2A3405F, 0x161DC372, 0xBCE2250C, 0x283C498B, 0xFF0D9541, + 0x39A80171, 0x080CB3DE, 0xD8B4E49C, 0x6456C190, 0x7BCB8461, 0xD532B670, 0x486C5C74, 0xD0B85742 + ); /** * Precomputed invMixColumns table * - * @see Crypt_Rijndael() + * @see Crypt_Rijndael:_encryptBlock() + * @see Crypt_Rijndael:_decryptBlock() * @var Array * @access private */ - var $dt1; + var $dt1 = array( + 0x5051F4A7, 0x537E4165, 0xC31A17A4, 0x963A275E, 0xCB3BAB6B, 0xF11F9D45, 0xABACFA58, 0x934BE303, + 0x552030FA, 0xF6AD766D, 0x9188CC76, 0x25F5024C, 0xFC4FE5D7, 0xD7C52ACB, 0x80263544, 0x8FB562A3, + 0x49DEB15A, 0x6725BA1B, 0x9845EA0E, 0xE15DFEC0, 0x02C32F75, 0x12814CF0, 0xA38D4697, 0xC66BD3F9, + 0xE7038F5F, 0x9515929C, 0xEBBF6D7A, 0xDA955259, 0x2DD4BE83, 0xD3587421, 0x2949E069, 0x448EC9C8, + 0x6A75C289, 0x78F48E79, 0x6B99583E, 0xDD27B971, 0xB6BEE14F, 0x17F088AD, 0x66C920AC, 0xB47DCE3A, + 0x1863DF4A, 0x82E51A31, 0x60975133, 0x4562537F, 0xE0B16477, 0x84BB6BAE, 0x1CFE81A0, 0x94F9082B, + 0x58704868, 0x198F45FD, 0x8794DE6C, 0xB7527BF8, 0x23AB73D3, 0xE2724B02, 0x57E31F8F, 0x2A6655AB, + 0x07B2EB28, 0x032FB5C2, 0x9A86C57B, 0xA5D33708, 0xF2302887, 0xB223BFA5, 0xBA02036A, 0x5CED1682, + 0x2B8ACF1C, 0x92A779B4, 0xF0F307F2, 0xA14E69E2, 0xCD65DAF4, 0xD50605BE, 0x1FD13462, 0x8AC4A6FE, + 0x9D342E53, 0xA0A2F355, 0x32058AE1, 0x75A4F6EB, 0x390B83EC, 0xAA4060EF, 0x065E719F, 0x51BD6E10, + 0xF93E218A, 0x3D96DD06, 0xAEDD3E05, 0x464DE6BD, 0xB591548D, 0x0571C45D, 0x6F0406D4, 0xFF605015, + 0x241998FB, 0x97D6BDE9, 0xCC894043, 0x7767D99E, 0xBDB0E842, 0x8807898B, 0x38E7195B, 0xDB79C8EE, + 0x47A17C0A, 0xE97C420F, 0xC9F8841E, 0x00000000, 0x83098086, 0x48322BED, 0xAC1E1170, 0x4E6C5A72, + 0xFBFD0EFF, 0x560F8538, 0x1E3DAED5, 0x27362D39, 0x640A0FD9, 0x21685CA6, 0xD19B5B54, 0x3A24362E, + 0xB10C0A67, 0x0F9357E7, 0xD2B4EE96, 0x9E1B9B91, 0x4F80C0C5, 0xA261DC20, 0x695A774B, 0x161C121A, + 0x0AE293BA, 0xE5C0A02A, 0x433C22E0, 0x1D121B17, 0x0B0E090D, 0xADF28BC7, 0xB92DB6A8, 0xC8141EA9, + 0x8557F119, 0x4CAF7507, 0xBBEE99DD, 0xFDA37F60, 0x9FF70126, 0xBC5C72F5, 0xC544663B, 0x345BFB7E, + 0x768B4329, 0xDCCB23C6, 0x68B6EDFC, 0x63B8E4F1, 0xCAD731DC, 0x10426385, 0x40139722, 0x2084C611, + 0x7D854A24, 0xF8D2BB3D, 0x11AEF932, 0x6DC729A1, 0x4B1D9E2F, 0xF3DCB230, 0xEC0D8652, 0xD077C1E3, + 0x6C2BB316, 0x99A970B9, 0xFA119448, 0x2247E964, 0xC4A8FC8C, 0x1AA0F03F, 0xD8567D2C, 0xEF223390, + 0xC787494E, 0xC1D938D1, 0xFE8CCAA2, 0x3698D40B, 0xCFA6F581, 0x28A57ADE, 0x26DAB78E, 0xA43FADBF, + 0xE42C3A9D, 0x0D507892, 0x9B6A5FCC, 0x62547E46, 0xC2F68D13, 0xE890D8B8, 0x5E2E39F7, 0xF582C3AF, + 0xBE9F5D80, 0x7C69D093, 0xA96FD52D, 0xB3CF2512, 0x3BC8AC99, 0xA710187D, 0x6EE89C63, 0x7BDB3BBB, + 0x09CD2678, 0xF46E5918, 0x01EC9AB7, 0xA8834F9A, 0x65E6956E, 0x7EAAFFE6, 0x0821BCCF, 0xE6EF15E8, + 0xD9BAE79B, 0xCE4A6F36, 0xD4EA9F09, 0xD629B07C, 0xAF31A4B2, 0x312A3F23, 0x30C6A594, 0xC035A266, + 0x37744EBC, 0xA6FC82CA, 0xB0E090D0, 0x1533A7D8, 0x4AF10498, 0xF741ECDA, 0x0E7FCD50, 0x2F1791F6, + 0x8D764DD6, 0x4D43EFB0, 0x54CCAA4D, 0xDFE49604, 0xE39ED1B5, 0x1B4C6A88, 0xB8C12C1F, 0x7F466551, + 0x049D5EEA, 0x5D018C35, 0x73FA8774, 0x2EFB0B41, 0x5AB3671D, 0x5292DBD2, 0x33E91056, 0x136DD647, + 0x8C9AD761, 0x7A37A10C, 0x8E59F814, 0x89EB133C, 0xEECEA927, 0x35B761C9, 0xEDE11CE5, 0x3C7A47B1, + 0x599CD2DF, 0x3F55F273, 0x791814CE, 0xBF73C737, 0xEA53F7CD, 0x5B5FFDAA, 0x14DF3D6F, 0x867844DB, + 0x81CAAFF3, 0x3EB968C4, 0x2C382434, 0x5FC2A340, 0x72161DC3, 0x0CBCE225, 0x8B283C49, 0x41FF0D95, + 0x7139A801, 0xDE080CB3, 0x9CD8B4E4, 0x906456C1, 0x617BCB84, 0x70D532B6, 0x74486C5C, 0x42D0B857 + ); /** * Precomputed invMixColumns table * - * @see Crypt_Rijndael() + * @see Crypt_Rijndael:_encryptBlock() + * @see Crypt_Rijndael:_decryptBlock() * @var Array * @access private */ - var $dt2; + var $dt2 = array( + 0xA75051F4, 0x65537E41, 0xA4C31A17, 0x5E963A27, 0x6BCB3BAB, 0x45F11F9D, 0x58ABACFA, 0x03934BE3, + 0xFA552030, 0x6DF6AD76, 0x769188CC, 0x4C25F502, 0xD7FC4FE5, 0xCBD7C52A, 0x44802635, 0xA38FB562, + 0x5A49DEB1, 0x1B6725BA, 0x0E9845EA, 0xC0E15DFE, 0x7502C32F, 0xF012814C, 0x97A38D46, 0xF9C66BD3, + 0x5FE7038F, 0x9C951592, 0x7AEBBF6D, 0x59DA9552, 0x832DD4BE, 0x21D35874, 0x692949E0, 0xC8448EC9, + 0x896A75C2, 0x7978F48E, 0x3E6B9958, 0x71DD27B9, 0x4FB6BEE1, 0xAD17F088, 0xAC66C920, 0x3AB47DCE, + 0x4A1863DF, 0x3182E51A, 0x33609751, 0x7F456253, 0x77E0B164, 0xAE84BB6B, 0xA01CFE81, 0x2B94F908, + 0x68587048, 0xFD198F45, 0x6C8794DE, 0xF8B7527B, 0xD323AB73, 0x02E2724B, 0x8F57E31F, 0xAB2A6655, + 0x2807B2EB, 0xC2032FB5, 0x7B9A86C5, 0x08A5D337, 0x87F23028, 0xA5B223BF, 0x6ABA0203, 0x825CED16, + 0x1C2B8ACF, 0xB492A779, 0xF2F0F307, 0xE2A14E69, 0xF4CD65DA, 0xBED50605, 0x621FD134, 0xFE8AC4A6, + 0x539D342E, 0x55A0A2F3, 0xE132058A, 0xEB75A4F6, 0xEC390B83, 0xEFAA4060, 0x9F065E71, 0x1051BD6E, + 0x8AF93E21, 0x063D96DD, 0x05AEDD3E, 0xBD464DE6, 0x8DB59154, 0x5D0571C4, 0xD46F0406, 0x15FF6050, + 0xFB241998, 0xE997D6BD, 0x43CC8940, 0x9E7767D9, 0x42BDB0E8, 0x8B880789, 0x5B38E719, 0xEEDB79C8, + 0x0A47A17C, 0x0FE97C42, 0x1EC9F884, 0x00000000, 0x86830980, 0xED48322B, 0x70AC1E11, 0x724E6C5A, + 0xFFFBFD0E, 0x38560F85, 0xD51E3DAE, 0x3927362D, 0xD9640A0F, 0xA621685C, 0x54D19B5B, 0x2E3A2436, + 0x67B10C0A, 0xE70F9357, 0x96D2B4EE, 0x919E1B9B, 0xC54F80C0, 0x20A261DC, 0x4B695A77, 0x1A161C12, + 0xBA0AE293, 0x2AE5C0A0, 0xE0433C22, 0x171D121B, 0x0D0B0E09, 0xC7ADF28B, 0xA8B92DB6, 0xA9C8141E, + 0x198557F1, 0x074CAF75, 0xDDBBEE99, 0x60FDA37F, 0x269FF701, 0xF5BC5C72, 0x3BC54466, 0x7E345BFB, + 0x29768B43, 0xC6DCCB23, 0xFC68B6ED, 0xF163B8E4, 0xDCCAD731, 0x85104263, 0x22401397, 0x112084C6, + 0x247D854A, 0x3DF8D2BB, 0x3211AEF9, 0xA16DC729, 0x2F4B1D9E, 0x30F3DCB2, 0x52EC0D86, 0xE3D077C1, + 0x166C2BB3, 0xB999A970, 0x48FA1194, 0x642247E9, 0x8CC4A8FC, 0x3F1AA0F0, 0x2CD8567D, 0x90EF2233, + 0x4EC78749, 0xD1C1D938, 0xA2FE8CCA, 0x0B3698D4, 0x81CFA6F5, 0xDE28A57A, 0x8E26DAB7, 0xBFA43FAD, + 0x9DE42C3A, 0x920D5078, 0xCC9B6A5F, 0x4662547E, 0x13C2F68D, 0xB8E890D8, 0xF75E2E39, 0xAFF582C3, + 0x80BE9F5D, 0x937C69D0, 0x2DA96FD5, 0x12B3CF25, 0x993BC8AC, 0x7DA71018, 0x636EE89C, 0xBB7BDB3B, + 0x7809CD26, 0x18F46E59, 0xB701EC9A, 0x9AA8834F, 0x6E65E695, 0xE67EAAFF, 0xCF0821BC, 0xE8E6EF15, + 0x9BD9BAE7, 0x36CE4A6F, 0x09D4EA9F, 0x7CD629B0, 0xB2AF31A4, 0x23312A3F, 0x9430C6A5, 0x66C035A2, + 0xBC37744E, 0xCAA6FC82, 0xD0B0E090, 0xD81533A7, 0x984AF104, 0xDAF741EC, 0x500E7FCD, 0xF62F1791, + 0xD68D764D, 0xB04D43EF, 0x4D54CCAA, 0x04DFE496, 0xB5E39ED1, 0x881B4C6A, 0x1FB8C12C, 0x517F4665, + 0xEA049D5E, 0x355D018C, 0x7473FA87, 0x412EFB0B, 0x1D5AB367, 0xD25292DB, 0x5633E910, 0x47136DD6, + 0x618C9AD7, 0x0C7A37A1, 0x148E59F8, 0x3C89EB13, 0x27EECEA9, 0xC935B761, 0xE5EDE11C, 0xB13C7A47, + 0xDF599CD2, 0x733F55F2, 0xCE791814, 0x37BF73C7, 0xCDEA53F7, 0xAA5B5FFD, 0x6F14DF3D, 0xDB867844, + 0xF381CAAF, 0xC43EB968, 0x342C3824, 0x405FC2A3, 0xC372161D, 0x250CBCE2, 0x498B283C, 0x9541FF0D, + 0x017139A8, 0xB3DE080C, 0xE49CD8B4, 0xC1906456, 0x84617BCB, 0xB670D532, 0x5C74486C, 0x5742D0B8 + ); /** * Precomputed invMixColumns table * - * @see Crypt_Rijndael() + * @see Crypt_Rijndael:_encryptBlock() + * @see Crypt_Rijndael:_decryptBlock() * @var Array * @access private */ - var $dt3; + var $dt3 = array( + 0xF4A75051, 0x4165537E, 0x17A4C31A, 0x275E963A, 0xAB6BCB3B, 0x9D45F11F, 0xFA58ABAC, 0xE303934B, + 0x30FA5520, 0x766DF6AD, 0xCC769188, 0x024C25F5, 0xE5D7FC4F, 0x2ACBD7C5, 0x35448026, 0x62A38FB5, + 0xB15A49DE, 0xBA1B6725, 0xEA0E9845, 0xFEC0E15D, 0x2F7502C3, 0x4CF01281, 0x4697A38D, 0xD3F9C66B, + 0x8F5FE703, 0x929C9515, 0x6D7AEBBF, 0x5259DA95, 0xBE832DD4, 0x7421D358, 0xE0692949, 0xC9C8448E, + 0xC2896A75, 0x8E7978F4, 0x583E6B99, 0xB971DD27, 0xE14FB6BE, 0x88AD17F0, 0x20AC66C9, 0xCE3AB47D, + 0xDF4A1863, 0x1A3182E5, 0x51336097, 0x537F4562, 0x6477E0B1, 0x6BAE84BB, 0x81A01CFE, 0x082B94F9, + 0x48685870, 0x45FD198F, 0xDE6C8794, 0x7BF8B752, 0x73D323AB, 0x4B02E272, 0x1F8F57E3, 0x55AB2A66, + 0xEB2807B2, 0xB5C2032F, 0xC57B9A86, 0x3708A5D3, 0x2887F230, 0xBFA5B223, 0x036ABA02, 0x16825CED, + 0xCF1C2B8A, 0x79B492A7, 0x07F2F0F3, 0x69E2A14E, 0xDAF4CD65, 0x05BED506, 0x34621FD1, 0xA6FE8AC4, + 0x2E539D34, 0xF355A0A2, 0x8AE13205, 0xF6EB75A4, 0x83EC390B, 0x60EFAA40, 0x719F065E, 0x6E1051BD, + 0x218AF93E, 0xDD063D96, 0x3E05AEDD, 0xE6BD464D, 0x548DB591, 0xC45D0571, 0x06D46F04, 0x5015FF60, + 0x98FB2419, 0xBDE997D6, 0x4043CC89, 0xD99E7767, 0xE842BDB0, 0x898B8807, 0x195B38E7, 0xC8EEDB79, + 0x7C0A47A1, 0x420FE97C, 0x841EC9F8, 0x00000000, 0x80868309, 0x2BED4832, 0x1170AC1E, 0x5A724E6C, + 0x0EFFFBFD, 0x8538560F, 0xAED51E3D, 0x2D392736, 0x0FD9640A, 0x5CA62168, 0x5B54D19B, 0x362E3A24, + 0x0A67B10C, 0x57E70F93, 0xEE96D2B4, 0x9B919E1B, 0xC0C54F80, 0xDC20A261, 0x774B695A, 0x121A161C, + 0x93BA0AE2, 0xA02AE5C0, 0x22E0433C, 0x1B171D12, 0x090D0B0E, 0x8BC7ADF2, 0xB6A8B92D, 0x1EA9C814, + 0xF1198557, 0x75074CAF, 0x99DDBBEE, 0x7F60FDA3, 0x01269FF7, 0x72F5BC5C, 0x663BC544, 0xFB7E345B, + 0x4329768B, 0x23C6DCCB, 0xEDFC68B6, 0xE4F163B8, 0x31DCCAD7, 0x63851042, 0x97224013, 0xC6112084, + 0x4A247D85, 0xBB3DF8D2, 0xF93211AE, 0x29A16DC7, 0x9E2F4B1D, 0xB230F3DC, 0x8652EC0D, 0xC1E3D077, + 0xB3166C2B, 0x70B999A9, 0x9448FA11, 0xE9642247, 0xFC8CC4A8, 0xF03F1AA0, 0x7D2CD856, 0x3390EF22, + 0x494EC787, 0x38D1C1D9, 0xCAA2FE8C, 0xD40B3698, 0xF581CFA6, 0x7ADE28A5, 0xB78E26DA, 0xADBFA43F, + 0x3A9DE42C, 0x78920D50, 0x5FCC9B6A, 0x7E466254, 0x8D13C2F6, 0xD8B8E890, 0x39F75E2E, 0xC3AFF582, + 0x5D80BE9F, 0xD0937C69, 0xD52DA96F, 0x2512B3CF, 0xAC993BC8, 0x187DA710, 0x9C636EE8, 0x3BBB7BDB, + 0x267809CD, 0x5918F46E, 0x9AB701EC, 0x4F9AA883, 0x956E65E6, 0xFFE67EAA, 0xBCCF0821, 0x15E8E6EF, + 0xE79BD9BA, 0x6F36CE4A, 0x9F09D4EA, 0xB07CD629, 0xA4B2AF31, 0x3F23312A, 0xA59430C6, 0xA266C035, + 0x4EBC3774, 0x82CAA6FC, 0x90D0B0E0, 0xA7D81533, 0x04984AF1, 0xECDAF741, 0xCD500E7F, 0x91F62F17, + 0x4DD68D76, 0xEFB04D43, 0xAA4D54CC, 0x9604DFE4, 0xD1B5E39E, 0x6A881B4C, 0x2C1FB8C1, 0x65517F46, + 0x5EEA049D, 0x8C355D01, 0x877473FA, 0x0B412EFB, 0x671D5AB3, 0xDBD25292, 0x105633E9, 0xD647136D, + 0xD7618C9A, 0xA10C7A37, 0xF8148E59, 0x133C89EB, 0xA927EECE, 0x61C935B7, 0x1CE5EDE1, 0x47B13C7A, + 0xD2DF599C, 0xF2733F55, 0x14CE7918, 0xC737BF73, 0xF7CDEA53, 0xFDAA5B5F, 0x3D6F14DF, 0x44DB8678, + 0xAFF381CA, 0x68C43EB9, 0x24342C38, 0xA3405FC2, 0x1DC37216, 0xE2250CBC, 0x3C498B28, 0x0D9541FF, + 0xA8017139, 0x0CB3DE08, 0xB4E49CD8, 0x56C19064, 0xCB84617B, 0x32B670D5, 0x6C5C7448, 0xB85742D0 + ); /** - * Is the mode one that is paddable? + * The SubByte S-Box * - * @see Crypt_Rijndael::Crypt_Rijndael() - * @var Boolean + * @see Crypt_Rijndael::_encryptBlock() + * @var Array * @access private */ - var $paddable = false; + var $sbox = array( + 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, + 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, + 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, + 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, + 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, + 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, + 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, + 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, + 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, + 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, + 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, + 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, + 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, + 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, + 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, + 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16 + ); /** - * Encryption buffer for CTR, OFB and CFB modes + * The inverse SubByte S-Box * - * @see Crypt_Rijndael::encrypt() - * @var String + * @see Crypt_Rijndael::_decryptBlock() + * @var Array * @access private */ - var $enbuffer = array('encrypted' => '', 'xor' => '', 'pos' => 0); - - /** - * Decryption buffer for CTR, OFB and CFB modes - * - * @see Crypt_Rijndael::decrypt() - * @var String - * @access private - */ - var $debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0); + var $isbox = array( + 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB, + 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, + 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, + 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25, + 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, + 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, + 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06, + 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, + 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, + 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E, + 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, + 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, + 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F, + 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, + 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D + ); /** * Default Constructor. * - * Determines whether or not the mcrypt extension should be used. $mode should only, at present, be - * CRYPT_RIJNDAEL_MODE_ECB or CRYPT_RIJNDAEL_MODE_CBC. If not explictly set, CRYPT_RIJNDAEL_MODE_CBC will be used. + * Determines whether or not the mcrypt extension should be used. * + * $mode could be: + * + * - CRYPT_RIJNDAEL_MODE_ECB + * + * - CRYPT_RIJNDAEL_MODE_CBC + * + * - CRYPT_RIJNDAEL_MODE_CTR + * + * - CRYPT_RIJNDAEL_MODE_CFB + * + * - CRYPT_RIJNDAEL_MODE_OFB + * + * If not explictly set, CRYPT_RIJNDAEL_MODE_CBC will be used. + * + * @see Crypt_Base::Crypt_Base() * @param optional Integer $mode - * @return Crypt_Rijndael * @access public */ function Crypt_Rijndael($mode = CRYPT_RIJNDAEL_MODE_CBC) { - switch ($mode) { - case CRYPT_RIJNDAEL_MODE_ECB: - case CRYPT_RIJNDAEL_MODE_CBC: - $this->paddable = true; - $this->mode = $mode; - break; - case CRYPT_RIJNDAEL_MODE_CTR: - case CRYPT_RIJNDAEL_MODE_CFB: - case CRYPT_RIJNDAEL_MODE_OFB: - $this->mode = $mode; - break; - default: - $this->paddable = true; - $this->mode = CRYPT_RIJNDAEL_MODE_CBC; - } - - $t3 = &$this->t3; - $t2 = &$this->t2; - $t1 = &$this->t1; - $t0 = &$this->t0; - - $dt3 = &$this->dt3; - $dt2 = &$this->dt2; - $dt1 = &$this->dt1; - $dt0 = &$this->dt0; - - // according to (section 5.2.1), - // precomputed tables can be used in the mixColumns phase. in that example, they're assigned t0...t3, so - // those are the names we'll use. - $t3 = array( - 0x6363A5C6, 0x7C7C84F8, 0x777799EE, 0x7B7B8DF6, 0xF2F20DFF, 0x6B6BBDD6, 0x6F6FB1DE, 0xC5C55491, - 0x30305060, 0x01010302, 0x6767A9CE, 0x2B2B7D56, 0xFEFE19E7, 0xD7D762B5, 0xABABE64D, 0x76769AEC, - 0xCACA458F, 0x82829D1F, 0xC9C94089, 0x7D7D87FA, 0xFAFA15EF, 0x5959EBB2, 0x4747C98E, 0xF0F00BFB, - 0xADADEC41, 0xD4D467B3, 0xA2A2FD5F, 0xAFAFEA45, 0x9C9CBF23, 0xA4A4F753, 0x727296E4, 0xC0C05B9B, - 0xB7B7C275, 0xFDFD1CE1, 0x9393AE3D, 0x26266A4C, 0x36365A6C, 0x3F3F417E, 0xF7F702F5, 0xCCCC4F83, - 0x34345C68, 0xA5A5F451, 0xE5E534D1, 0xF1F108F9, 0x717193E2, 0xD8D873AB, 0x31315362, 0x15153F2A, - 0x04040C08, 0xC7C75295, 0x23236546, 0xC3C35E9D, 0x18182830, 0x9696A137, 0x05050F0A, 0x9A9AB52F, - 0x0707090E, 0x12123624, 0x80809B1B, 0xE2E23DDF, 0xEBEB26CD, 0x2727694E, 0xB2B2CD7F, 0x75759FEA, - 0x09091B12, 0x83839E1D, 0x2C2C7458, 0x1A1A2E34, 0x1B1B2D36, 0x6E6EB2DC, 0x5A5AEEB4, 0xA0A0FB5B, - 0x5252F6A4, 0x3B3B4D76, 0xD6D661B7, 0xB3B3CE7D, 0x29297B52, 0xE3E33EDD, 0x2F2F715E, 0x84849713, - 0x5353F5A6, 0xD1D168B9, 0x00000000, 0xEDED2CC1, 0x20206040, 0xFCFC1FE3, 0xB1B1C879, 0x5B5BEDB6, - 0x6A6ABED4, 0xCBCB468D, 0xBEBED967, 0x39394B72, 0x4A4ADE94, 0x4C4CD498, 0x5858E8B0, 0xCFCF4A85, - 0xD0D06BBB, 0xEFEF2AC5, 0xAAAAE54F, 0xFBFB16ED, 0x4343C586, 0x4D4DD79A, 0x33335566, 0x85859411, - 0x4545CF8A, 0xF9F910E9, 0x02020604, 0x7F7F81FE, 0x5050F0A0, 0x3C3C4478, 0x9F9FBA25, 0xA8A8E34B, - 0x5151F3A2, 0xA3A3FE5D, 0x4040C080, 0x8F8F8A05, 0x9292AD3F, 0x9D9DBC21, 0x38384870, 0xF5F504F1, - 0xBCBCDF63, 0xB6B6C177, 0xDADA75AF, 0x21216342, 0x10103020, 0xFFFF1AE5, 0xF3F30EFD, 0xD2D26DBF, - 0xCDCD4C81, 0x0C0C1418, 0x13133526, 0xECEC2FC3, 0x5F5FE1BE, 0x9797A235, 0x4444CC88, 0x1717392E, - 0xC4C45793, 0xA7A7F255, 0x7E7E82FC, 0x3D3D477A, 0x6464ACC8, 0x5D5DE7BA, 0x19192B32, 0x737395E6, - 0x6060A0C0, 0x81819819, 0x4F4FD19E, 0xDCDC7FA3, 0x22226644, 0x2A2A7E54, 0x9090AB3B, 0x8888830B, - 0x4646CA8C, 0xEEEE29C7, 0xB8B8D36B, 0x14143C28, 0xDEDE79A7, 0x5E5EE2BC, 0x0B0B1D16, 0xDBDB76AD, - 0xE0E03BDB, 0x32325664, 0x3A3A4E74, 0x0A0A1E14, 0x4949DB92, 0x06060A0C, 0x24246C48, 0x5C5CE4B8, - 0xC2C25D9F, 0xD3D36EBD, 0xACACEF43, 0x6262A6C4, 0x9191A839, 0x9595A431, 0xE4E437D3, 0x79798BF2, - 0xE7E732D5, 0xC8C8438B, 0x3737596E, 0x6D6DB7DA, 0x8D8D8C01, 0xD5D564B1, 0x4E4ED29C, 0xA9A9E049, - 0x6C6CB4D8, 0x5656FAAC, 0xF4F407F3, 0xEAEA25CF, 0x6565AFCA, 0x7A7A8EF4, 0xAEAEE947, 0x08081810, - 0xBABAD56F, 0x787888F0, 0x25256F4A, 0x2E2E725C, 0x1C1C2438, 0xA6A6F157, 0xB4B4C773, 0xC6C65197, - 0xE8E823CB, 0xDDDD7CA1, 0x74749CE8, 0x1F1F213E, 0x4B4BDD96, 0xBDBDDC61, 0x8B8B860D, 0x8A8A850F, - 0x707090E0, 0x3E3E427C, 0xB5B5C471, 0x6666AACC, 0x4848D890, 0x03030506, 0xF6F601F7, 0x0E0E121C, - 0x6161A3C2, 0x35355F6A, 0x5757F9AE, 0xB9B9D069, 0x86869117, 0xC1C15899, 0x1D1D273A, 0x9E9EB927, - 0xE1E138D9, 0xF8F813EB, 0x9898B32B, 0x11113322, 0x6969BBD2, 0xD9D970A9, 0x8E8E8907, 0x9494A733, - 0x9B9BB62D, 0x1E1E223C, 0x87879215, 0xE9E920C9, 0xCECE4987, 0x5555FFAA, 0x28287850, 0xDFDF7AA5, - 0x8C8C8F03, 0xA1A1F859, 0x89898009, 0x0D0D171A, 0xBFBFDA65, 0xE6E631D7, 0x4242C684, 0x6868B8D0, - 0x4141C382, 0x9999B029, 0x2D2D775A, 0x0F0F111E, 0xB0B0CB7B, 0x5454FCA8, 0xBBBBD66D, 0x16163A2C - ); - - $dt3 = array( - 0xF4A75051, 0x4165537E, 0x17A4C31A, 0x275E963A, 0xAB6BCB3B, 0x9D45F11F, 0xFA58ABAC, 0xE303934B, - 0x30FA5520, 0x766DF6AD, 0xCC769188, 0x024C25F5, 0xE5D7FC4F, 0x2ACBD7C5, 0x35448026, 0x62A38FB5, - 0xB15A49DE, 0xBA1B6725, 0xEA0E9845, 0xFEC0E15D, 0x2F7502C3, 0x4CF01281, 0x4697A38D, 0xD3F9C66B, - 0x8F5FE703, 0x929C9515, 0x6D7AEBBF, 0x5259DA95, 0xBE832DD4, 0x7421D358, 0xE0692949, 0xC9C8448E, - 0xC2896A75, 0x8E7978F4, 0x583E6B99, 0xB971DD27, 0xE14FB6BE, 0x88AD17F0, 0x20AC66C9, 0xCE3AB47D, - 0xDF4A1863, 0x1A3182E5, 0x51336097, 0x537F4562, 0x6477E0B1, 0x6BAE84BB, 0x81A01CFE, 0x082B94F9, - 0x48685870, 0x45FD198F, 0xDE6C8794, 0x7BF8B752, 0x73D323AB, 0x4B02E272, 0x1F8F57E3, 0x55AB2A66, - 0xEB2807B2, 0xB5C2032F, 0xC57B9A86, 0x3708A5D3, 0x2887F230, 0xBFA5B223, 0x036ABA02, 0x16825CED, - 0xCF1C2B8A, 0x79B492A7, 0x07F2F0F3, 0x69E2A14E, 0xDAF4CD65, 0x05BED506, 0x34621FD1, 0xA6FE8AC4, - 0x2E539D34, 0xF355A0A2, 0x8AE13205, 0xF6EB75A4, 0x83EC390B, 0x60EFAA40, 0x719F065E, 0x6E1051BD, - 0x218AF93E, 0xDD063D96, 0x3E05AEDD, 0xE6BD464D, 0x548DB591, 0xC45D0571, 0x06D46F04, 0x5015FF60, - 0x98FB2419, 0xBDE997D6, 0x4043CC89, 0xD99E7767, 0xE842BDB0, 0x898B8807, 0x195B38E7, 0xC8EEDB79, - 0x7C0A47A1, 0x420FE97C, 0x841EC9F8, 0x00000000, 0x80868309, 0x2BED4832, 0x1170AC1E, 0x5A724E6C, - 0x0EFFFBFD, 0x8538560F, 0xAED51E3D, 0x2D392736, 0x0FD9640A, 0x5CA62168, 0x5B54D19B, 0x362E3A24, - 0x0A67B10C, 0x57E70F93, 0xEE96D2B4, 0x9B919E1B, 0xC0C54F80, 0xDC20A261, 0x774B695A, 0x121A161C, - 0x93BA0AE2, 0xA02AE5C0, 0x22E0433C, 0x1B171D12, 0x090D0B0E, 0x8BC7ADF2, 0xB6A8B92D, 0x1EA9C814, - 0xF1198557, 0x75074CAF, 0x99DDBBEE, 0x7F60FDA3, 0x01269FF7, 0x72F5BC5C, 0x663BC544, 0xFB7E345B, - 0x4329768B, 0x23C6DCCB, 0xEDFC68B6, 0xE4F163B8, 0x31DCCAD7, 0x63851042, 0x97224013, 0xC6112084, - 0x4A247D85, 0xBB3DF8D2, 0xF93211AE, 0x29A16DC7, 0x9E2F4B1D, 0xB230F3DC, 0x8652EC0D, 0xC1E3D077, - 0xB3166C2B, 0x70B999A9, 0x9448FA11, 0xE9642247, 0xFC8CC4A8, 0xF03F1AA0, 0x7D2CD856, 0x3390EF22, - 0x494EC787, 0x38D1C1D9, 0xCAA2FE8C, 0xD40B3698, 0xF581CFA6, 0x7ADE28A5, 0xB78E26DA, 0xADBFA43F, - 0x3A9DE42C, 0x78920D50, 0x5FCC9B6A, 0x7E466254, 0x8D13C2F6, 0xD8B8E890, 0x39F75E2E, 0xC3AFF582, - 0x5D80BE9F, 0xD0937C69, 0xD52DA96F, 0x2512B3CF, 0xAC993BC8, 0x187DA710, 0x9C636EE8, 0x3BBB7BDB, - 0x267809CD, 0x5918F46E, 0x9AB701EC, 0x4F9AA883, 0x956E65E6, 0xFFE67EAA, 0xBCCF0821, 0x15E8E6EF, - 0xE79BD9BA, 0x6F36CE4A, 0x9F09D4EA, 0xB07CD629, 0xA4B2AF31, 0x3F23312A, 0xA59430C6, 0xA266C035, - 0x4EBC3774, 0x82CAA6FC, 0x90D0B0E0, 0xA7D81533, 0x04984AF1, 0xECDAF741, 0xCD500E7F, 0x91F62F17, - 0x4DD68D76, 0xEFB04D43, 0xAA4D54CC, 0x9604DFE4, 0xD1B5E39E, 0x6A881B4C, 0x2C1FB8C1, 0x65517F46, - 0x5EEA049D, 0x8C355D01, 0x877473FA, 0x0B412EFB, 0x671D5AB3, 0xDBD25292, 0x105633E9, 0xD647136D, - 0xD7618C9A, 0xA10C7A37, 0xF8148E59, 0x133C89EB, 0xA927EECE, 0x61C935B7, 0x1CE5EDE1, 0x47B13C7A, - 0xD2DF599C, 0xF2733F55, 0x14CE7918, 0xC737BF73, 0xF7CDEA53, 0xFDAA5B5F, 0x3D6F14DF, 0x44DB8678, - 0xAFF381CA, 0x68C43EB9, 0x24342C38, 0xA3405FC2, 0x1DC37216, 0xE2250CBC, 0x3C498B28, 0x0D9541FF, - 0xA8017139, 0x0CB3DE08, 0xB4E49CD8, 0x56C19064, 0xCB84617B, 0x32B670D5, 0x6C5C7448, 0xB85742D0 - ); - - for ($i = 0; $i < 256; $i++) { - $t2[] = (($t3[$i] << 8) & 0xFFFFFF00) | (($t3[$i] >> 24) & 0x000000FF); - $t1[] = (($t3[$i] << 16) & 0xFFFF0000) | (($t3[$i] >> 16) & 0x0000FFFF); - $t0[] = (($t3[$i] << 24) & 0xFF000000) | (($t3[$i] >> 8) & 0x00FFFFFF); - - $dt2[] = (($dt3[$i] << 8) & 0xFFFFFF00) | (($dt3[$i] >> 24) & 0x000000FF); - $dt1[] = (($dt3[$i] << 16) & 0xFFFF0000) | (($dt3[$i] >> 16) & 0x0000FFFF); - $dt0[] = (($dt3[$i] << 24) & 0xFF000000) | (($dt3[$i] >> 8) & 0x00FFFFFF); - } + parent::Crypt_Base($mode); } /** @@ -530,112 +714,82 @@ class Crypt_Rijndael { * * If the key is not explicitly set, it'll be assumed to be all null bytes. * + * Note: 160/224-bit keys must explicitly set by setKeyLength(), otherwise they will be round/pad up to 192/256 bits. + * + * @see Crypt_Base:setKey() + * @see setKeyLength() * @access public * @param String $key */ function setKey($key) { - $this->key = $key; - $this->changed = true; - } + parent::setKey($key); - /** - * Sets the initialization vector. (optional) - * - * SetIV is not required when CRYPT_RIJNDAEL_MODE_ECB is being used. If not explictly set, it'll be assumed - * to be all zero's. - * - * @access public - * @param String $iv - */ - function setIV($iv) - { - $this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($iv, 0, $this->block_size), $this->block_size, chr(0)); + if (!$this->explicit_key_length) { + $length = strlen($key); + switch (true) { + case $length <= 16: + $this->key_size = 16; + break; + case $length <= 24: + $this->key_size = 24; + break; + default: + $this->key_size = 32; + } + $this->_setupEngine(); + } } /** * Sets the key length * * Valid key lengths are 128, 160, 192, 224, and 256. If the length is less than 128, it will be rounded up to - * 128. If the length is greater then 128 and invalid, it will be rounded down to the closest valid amount. + * 128. If the length is greater than 128 and invalid, it will be rounded down to the closest valid amount. + * + * Note: phpseclib extends Rijndael (and AES) for using 160- and 224-bit keys but they are officially not defined + * and the most (if not all) implementations are not able using 160/224-bit keys but round/pad them up to + * 192/256 bits as, for example, mcrypt will do. + * + * That said, if you want be compatible with other Rijndael and AES implementations, + * you should not setKeyLength(160) or setKeyLength(224). + * + * Additional: In case of 160- and 224-bit keys, phpseclib will/can, for that reason, not use + * the mcrypt php extention, even if available. + * This results then in slower encryption. * * @access public * @param Integer $length */ function setKeyLength($length) { - $length >>= 5; - if ($length > 8) { - $length = 8; - } else if ($length < 4) { - $length = 4; + switch (true) { + case $length == 160: + $this->key_size = 20; + break; + case $length == 224: + $this->key_size = 28; + break; + case $length <= 128: + $this->key_size = 16; + break; + case $length <= 192: + $this->key_size = 24; + break; + default: + $this->key_size = 32; } - $this->Nk = $length; - $this->key_size = $length << 2; $this->explicit_key_length = true; $this->changed = true; - } - - /** - * Sets the password. - * - * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows: - * {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2}: - * $hash, $salt, $method - * Set $dkLen by calling setKeyLength() - * - * @param String $password - * @param optional String $method - * @access public - */ - function setPassword($password, $method = 'pbkdf2') - { - $key = ''; - - switch ($method) { - default: // 'pbkdf2' - list(, , $hash, $salt, $count) = func_get_args(); - if (!isset($hash)) { - $hash = 'sha1'; - } - // WPA and WPA2 use the SSID as the salt - if (!isset($salt)) { - $salt = 'phpseclib'; - } - // RFC2898#section-4.2 uses 1,000 iterations by default - // WPA and WPA2 use 4,096. - if (!isset($count)) { - $count = 1000; - } - - if (!class_exists('Crypt_Hash')) { - require_once('Crypt/Hash.php'); - } - - $i = 1; - while (strlen($key) < $this->key_size) { // $dkLen == $this->key_size - //$dk.= $this->_pbkdf($password, $salt, $count, $i++); - $hmac = new Crypt_Hash(); - $hmac->setHash($hash); - $hmac->setKey($password); - $f = $u = $hmac->hash($salt . pack('N', $i++)); - for ($j = 2; $j <= $count; $j++) { - $u = $hmac->hash($u); - $f^= $u; - } - $key.= $f; - } - } - - $this->setKey(substr($key, 0, $this->key_size)); + $this->_setupEngine(); } /** * Sets the block length * * Valid block lengths are 128, 160, 192, 224, and 256. If the length is less than 128, it will be rounded up to - * 128. If the length is greater then 128 and invalid, it will be rounded down to the closest valid amount. + * 128. If the length is greater than 128 and invalid, it will be rounded down to the closest valid amount. * * @access public * @param Integer $length @@ -651,314 +805,76 @@ class Crypt_Rijndael { $this->Nb = $length; $this->block_size = $length << 2; $this->changed = true; + $this->_setupEngine(); } /** - * Generate CTR XOR encryption key + * Setup the fastest possible $engine * - * Encrypt the output of this and XOR it against the ciphertext / plaintext to get the - * plaintext / ciphertext in CTR mode. + * Determines if the mcrypt (MODE_MCRYPT) $engine available + * and usable for the current $block_size and $key_size. * - * @see Crypt_Rijndael::decrypt() - * @see Crypt_Rijndael::encrypt() - * @access public - * @param Integer $length - * @param String $iv + * If not, the slower MODE_INTERNAL $engine will be set. + * + * @see setKey() + * @see setKeyLength() + * @see setBlockLength() + * @access private */ - function _generate_xor($length, &$iv) + function _setupEngine() { - $xor = ''; - $block_size = $this->block_size; - $num_blocks = floor(($length + ($block_size - 1)) / $block_size); - for ($i = 0; $i < $num_blocks; $i++) { - $xor.= $iv; - for ($j = 4; $j <= $block_size; $j+=4) { - $temp = substr($iv, -$j, 4); - switch ($temp) { - case "\xFF\xFF\xFF\xFF": - $iv = substr_replace($iv, "\x00\x00\x00\x00", -$j, 4); - break; - case "\x7F\xFF\xFF\xFF": - $iv = substr_replace($iv, "\x80\x00\x00\x00", -$j, 4); - break 2; - default: - extract(unpack('Ncount', $temp)); - $iv = substr_replace($iv, pack('N', $count + 1), -$j, 4); - break 2; - } + if (constant('CRYPT_' . $this->const_namespace . '_MODE') == CRYPT_MODE_INTERNAL) { + // No mcrypt support at all for rijndael + return; + } + + // The required mcrypt module name for the current $block_size of rijndael + $cipher_name_mcrypt = 'rijndael-' . ($this->block_size << 3); + + // Determining the availibility/usability of $cipher_name_mcrypt + switch (true) { + case $this->key_size % 8: // mcrypt is not usable for 160/224-bit keys, only for 128/192/256-bit keys + case !in_array($cipher_name_mcrypt, mcrypt_list_algorithms()): // $cipher_name_mcrypt is not available for the current $block_size + $engine = CRYPT_MODE_INTERNAL; + break; + default: + $engine = CRYPT_MODE_MCRYPT; + } + + if ($this->engine == $engine && $this->cipher_name_mcrypt == $cipher_name_mcrypt) { + // allready set, so we not unnecessary close $this->enmcrypt/demcrypt/ecb + return; + } + + // Set the $engine + $this->engine = $engine; + $this->cipher_name_mcrypt = $cipher_name_mcrypt; + + if ($this->enmcrypt) { + // Closing the current mcrypt resource(s). _mcryptSetup() will, if needed, + // (re)open them with the module named in $this->cipher_name_mcrypt + mcrypt_module_close($this->enmcrypt); + mcrypt_module_close($this->demcrypt); + $this->enmcrypt = null; + $this->demcrypt = null; + + if ($this->ecb) { + mcrypt_module_close($this->ecb); + $this->ecb = null; } } - - return $xor; } /** - * Encrypts a message. + * Setup the CRYPT_MODE_MCRYPT $engine * - * $plaintext will be padded with additional bytes such that it's length is a multiple of the block size. Other Rjindael - * implementations may or may not pad in the same manner. Other common approaches to padding and the reasons why it's - * necessary are discussed in the following - * URL: - * - * {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html} - * - * An alternative to padding is to, separately, send the length of the file. This is what SSH, in fact, does. - * strlen($plaintext) will still need to be a multiple of 8, however, arbitrary values can be added to make it that - * length. - * - * @see Crypt_Rijndael::decrypt() - * @access public - * @param String $plaintext + * @see Crypt_Base::_setupMcrypt() + * @access private */ - function encrypt($plaintext) + function _setupMcrypt() { - $this->_setup(); - if ($this->paddable) { - $plaintext = $this->_pad($plaintext); - } - - $block_size = $this->block_size; - $buffer = &$this->enbuffer; - $ciphertext = ''; - switch ($this->mode) { - case CRYPT_RIJNDAEL_MODE_ECB: - for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { - $ciphertext.= $this->_encryptBlock(substr($plaintext, $i, $block_size)); - } - break; - case CRYPT_RIJNDAEL_MODE_CBC: - $xor = $this->encryptIV; - for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { - $block = substr($plaintext, $i, $block_size); - $block = $this->_encryptBlock($block ^ $xor); - $xor = $block; - $ciphertext.= $block; - } - if ($this->continuousBuffer) { - $this->encryptIV = $xor; - } - break; - case CRYPT_RIJNDAEL_MODE_CTR: - $xor = $this->encryptIV; - if (strlen($buffer['encrypted'])) { - for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { - $block = substr($plaintext, $i, $block_size); - $buffer['encrypted'].= $this->_encryptBlock($this->_generate_xor($block_size, $xor)); - $key = $this->_string_shift($buffer['encrypted'], $block_size); - $ciphertext.= $block ^ $key; - } - } else { - for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { - $block = substr($plaintext, $i, $block_size); - $key = $this->_encryptBlock($this->_generate_xor($block_size, $xor)); - $ciphertext.= $block ^ $key; - } - } - if ($this->continuousBuffer) { - $this->encryptIV = $xor; - if ($start = strlen($plaintext) % $block_size) { - $buffer['encrypted'] = substr($key, $start) . $buffer['encrypted']; - } - } - break; - case CRYPT_RIJNDAEL_MODE_CFB: - // cfb loosely routines inspired by openssl's: - // http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1 - if ($this->continuousBuffer) { - $iv = &$this->encryptIV; - $pos = &$buffer['pos']; - } else { - $iv = $this->encryptIV; - $pos = 0; - } - $len = strlen($plaintext); - $i = 0; - if ($pos) { - $orig_pos = $pos; - $max = $block_size - $pos; - if ($len >= $max) { - $i = $max; - $len-= $max; - $pos = 0; - } else { - $i = $len; - $pos+= $len; - $len = 0; - } - // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize - $ciphertext = substr($iv, $orig_pos) ^ $plaintext; - $iv = substr_replace($iv, $ciphertext, $orig_pos, $i); - } - while ($len >= $block_size) { - $iv = $this->_encryptBlock($iv) ^ substr($plaintext, $i, $block_size); - $ciphertext.= $iv; - $len-= $block_size; - $i+= $block_size; - } - if ($len) { - $iv = $this->_encryptBlock($iv); - $block = $iv ^ substr($plaintext, $i); - $iv = substr_replace($iv, $block, 0, $len); - $ciphertext.= $block; - $pos = $len; - } - break; - case CRYPT_RIJNDAEL_MODE_OFB: - $xor = $this->encryptIV; - if (strlen($buffer['xor'])) { - for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { - $xor = $this->_encryptBlock($xor); - $buffer['xor'].= $xor; - $key = $this->_string_shift($buffer['xor'], $block_size); - $ciphertext.= substr($plaintext, $i, $block_size) ^ $key; - } - } else { - for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { - $xor = $this->_encryptBlock($xor); - $ciphertext.= substr($plaintext, $i, $block_size) ^ $xor; - } - $key = $xor; - } - if ($this->continuousBuffer) { - $this->encryptIV = $xor; - if ($start = strlen($plaintext) % $block_size) { - $buffer['xor'] = substr($key, $start) . $buffer['xor']; - } - } - } - - return $ciphertext; - } - - /** - * Decrypts a message. - * - * If strlen($ciphertext) is not a multiple of the block size, null bytes will be added to the end of the string until - * it is. - * - * @see Crypt_Rijndael::encrypt() - * @access public - * @param String $ciphertext - */ - function decrypt($ciphertext) - { - $this->_setup(); - - if ($this->paddable) { - // we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic : - // "The data is padded with "\0" to make sure the length of the data is n * blocksize." - $ciphertext = str_pad($ciphertext, strlen($ciphertext) + ($this->block_size - strlen($ciphertext) % $this->block_size) % $this->block_size, chr(0)); - } - - $block_size = $this->block_size; - $buffer = &$this->debuffer; - $plaintext = ''; - switch ($this->mode) { - case CRYPT_RIJNDAEL_MODE_ECB: - for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { - $plaintext.= $this->_decryptBlock(substr($ciphertext, $i, $block_size)); - } - break; - case CRYPT_RIJNDAEL_MODE_CBC: - $xor = $this->decryptIV; - for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { - $block = substr($ciphertext, $i, $block_size); - $plaintext.= $this->_decryptBlock($block) ^ $xor; - $xor = $block; - } - if ($this->continuousBuffer) { - $this->decryptIV = $xor; - } - break; - case CRYPT_RIJNDAEL_MODE_CTR: - $xor = $this->decryptIV; - if (strlen($buffer['ciphertext'])) { - for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { - $block = substr($ciphertext, $i, $block_size); - $buffer['ciphertext'].= $this->_encryptBlock($this->_generate_xor($block_size, $xor)); - $key = $this->_string_shift($buffer['ciphertext'], $block_size); - $plaintext.= $block ^ $key; - } - } else { - for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { - $block = substr($ciphertext, $i, $block_size); - $key = $this->_encryptBlock($this->_generate_xor($block_size, $xor)); - $plaintext.= $block ^ $key; - } - } - if ($this->continuousBuffer) { - $this->decryptIV = $xor; - if ($start = strlen($ciphertext) % $block_size) { - $buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext']; - } - } - break; - case CRYPT_RIJNDAEL_MODE_CFB: - if ($this->continuousBuffer) { - $iv = &$this->decryptIV; - $pos = &$buffer['pos']; - } else { - $iv = $this->decryptIV; - $pos = 0; - } - $len = strlen($ciphertext); - $i = 0; - if ($pos) { - $orig_pos = $pos; - $max = $block_size - $pos; - if ($len >= $max) { - $i = $max; - $len-= $max; - $pos = 0; - } else { - $i = $len; - $pos+= $len; - $len = 0; - } - // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize - $plaintext = substr($iv, $orig_pos) ^ $ciphertext; - $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i); - } - while ($len >= $block_size) { - $iv = $this->_encryptBlock($iv); - $cb = substr($ciphertext, $i, $block_size); - $plaintext.= $iv ^ $cb; - $iv = $cb; - $len-= $block_size; - $i+= $block_size; - } - if ($len) { - $iv = $this->_encryptBlock($iv); - $plaintext.= $iv ^ substr($ciphertext, $i); - $iv = substr_replace($iv, substr($ciphertext, $i), 0, $len); - $pos = $len; - } - break; - case CRYPT_RIJNDAEL_MODE_OFB: - $xor = $this->decryptIV; - if (strlen($buffer['xor'])) { - for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { - $xor = $this->_encryptBlock($xor); - $buffer['xor'].= $xor; - $key = $this->_string_shift($buffer['xor'], $block_size); - $plaintext.= substr($ciphertext, $i, $block_size) ^ $key; - } - } else { - for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { - $xor = $this->_encryptBlock($xor); - $plaintext.= substr($ciphertext, $i, $block_size) ^ $xor; - } - $key = $xor; - } - if ($this->continuousBuffer) { - $this->decryptIV = $xor; - if ($start = strlen($ciphertext) % $block_size) { - $buffer['xor'] = substr($key, $start) . $buffer['xor']; - } - } - } - - return $this->paddable ? $this->_unpad($plaintext) : $plaintext; + $this->key = str_pad(substr($this->key, 0, $this->key_size), $this->key_size, "\0"); + parent::_setupMcrypt(); } /** @@ -970,17 +886,24 @@ class Crypt_Rijndael { */ function _encryptBlock($in) { - $state = array(); - $words = unpack('N*word', $in); + static $t0, $t1, $t2, $t3, $sbox; + if (!$t0) { + for ($i = 0; $i < 256; ++$i) { + $t0[] = (int)$this->t0[$i]; + $t1[] = (int)$this->t1[$i]; + $t2[] = (int)$this->t2[$i]; + $t3[] = (int)$this->t3[$i]; + $sbox[] = (int)$this->sbox[$i]; + } + } + $state = array(); + $words = unpack('N*', $in); + + $c = $this->c; $w = $this->w; - $t0 = $this->t0; - $t1 = $this->t1; - $t2 = $this->t2; - $t3 = $this->t3; $Nb = $this->Nb; $Nr = $this->Nr; - $c = $this->c; // addRoundKey $i = -1; @@ -988,11 +911,11 @@ class Crypt_Rijndael { $state[] = $word ^ $w[0][++$i]; } - // fips-197.pdf#page=19, "Figure 5. Pseudo Code for the Cipher", states that this loop has four components - - // subBytes, shiftRows, mixColumns, and addRoundKey. fips-197.pdf#page=30, "Implementation Suggestions Regarding + // fips-197.pdf#page=19, "Figure 5. Pseudo Code for the Cipher", states that this loop has four components - + // subBytes, shiftRows, mixColumns, and addRoundKey. fips-197.pdf#page=30, "Implementation Suggestions Regarding // Various Platforms" suggests that performs enhanced implementations are described in Rijndael-ammended.pdf. // Rijndael-ammended.pdf#page=20, "Implementation aspects / 32-bit processor", discusses such an optimization. - // Unfortunately, the description given there is not quite correct. Per aes.spec.v316.pdf#page=19 [1], + // Unfortunately, the description given there is not quite correct. Per aes.spec.v316.pdf#page=19 [1], // equation (7.4.7) is supposed to use addition instead of subtraction, so we'll do that here, as well. // [1] http://fp.gladman.plus.com/cryptography_technology/rijndael/aes.spec.v316.pdf @@ -1019,7 +942,10 @@ class Crypt_Rijndael { // subWord for ($i = 0; $i < $Nb; ++$i) { - $state[$i] = $this->_subWord($state[$i]); + $state[$i] = $sbox[$state[$i] & 0x000000FF] | + ($sbox[$state[$i] >> 8 & 0x000000FF] << 8) | + ($sbox[$state[$i] >> 16 & 0x000000FF] << 16) | + ($sbox[$state[$i] >> 24 & 0x000000FF] << 24); } // shiftRows + addRoundKey @@ -1039,7 +965,6 @@ class Crypt_Rijndael { $l = ($l + 1) % $Nb; } - // 100% ugly switch/case code... but ~5% faster (meaning: ~half second faster de/encrypting 1MB text, tested with php5.4.9 on linux/32bit with an AMD Athlon II P360 CPU) then the commented smart code below. Don't know it's worth or not switch ($Nb) { case 8: return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6], $temp[7]); @@ -1052,13 +977,6 @@ class Crypt_Rijndael { default: return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3]); } - /* - $state = $temp; - - array_unshift($state, 'N*'); - - return call_user_func_array('pack', $state); - */ } /** @@ -1070,17 +988,24 @@ class Crypt_Rijndael { */ function _decryptBlock($in) { - $state = array(); - $words = unpack('N*word', $in); + static $dt0, $dt1, $dt2, $dt3, $isbox; + if (!$dt0) { + for ($i = 0; $i < 256; ++$i) { + $dt0[] = (int)$this->dt0[$i]; + $dt1[] = (int)$this->dt1[$i]; + $dt2[] = (int)$this->dt2[$i]; + $dt3[] = (int)$this->dt3[$i]; + $isbox[] = (int)$this->isbox[$i]; + } + } + $state = array(); + $words = unpack('N*', $in); + + $c = $this->c; $dw = $this->dw; - $dt0 = $this->dt0; - $dt1 = $this->dt1; - $dt2 = $this->dt2; - $dt3 = $this->dt3; $Nb = $this->Nb; $Nr = $this->Nr; - $c = $this->c; // addRoundKey $i = -1; @@ -1116,11 +1041,15 @@ class Crypt_Rijndael { $l = $Nb - $c[3]; while ($i < $Nb) { - $temp[$i] = $dw[0][$i] ^ - $this->_invSubWord(($state[$i] & 0xFF000000) | - ($state[$j] & 0x00FF0000) | - ($state[$k] & 0x0000FF00) | - ($state[$l] & 0x000000FF)); + $word = ($state[$i] & 0xFF000000) | + ($state[$j] & 0x00FF0000) | + ($state[$k] & 0x0000FF00) | + ($state[$l] & 0x000000FF); + + $temp[$i] = $dw[0][$i] ^ ($isbox[$word & 0x000000FF] | + ($isbox[$word >> 8 & 0x000000FF] << 8) | + ($isbox[$word >> 16 & 0x000000FF] << 16) | + ($isbox[$word >> 24 & 0x000000FF] << 24)); ++$i; $j = ($j + 1) % $Nb; $k = ($k + 1) % $Nb; @@ -1139,24 +1068,15 @@ class Crypt_Rijndael { default: return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3]); } - /* - $state = $temp; - - array_unshift($state, 'N*'); - - return call_user_func_array('pack', $state); - */ } /** - * Setup Rijndael - * - * Validates all the variables and calculates $Nr - the number of rounds that need to be performed - and $w - the key - * key schedule. + * Setup the key (expansion) * + * @see Crypt_Base::_setupKey() * @access private */ - function _setup() + function _setupKey() { // Each number in $rcon is equal to the previous number multiplied by two in Rijndael's finite field. // See http://en.wikipedia.org/wiki/Finite_field_arithmetic#Multiplicative_inverse @@ -1169,25 +1089,15 @@ class Crypt_Rijndael { 0x7D000000, 0xFA000000, 0xEF000000, 0xC5000000, 0x91000000 ); - if (!$this->changed) { + $this->key = str_pad(substr($this->key, 0, $this->key_size), $this->key_size, "\0"); + + if (isset($this->kl['key']) && $this->key === $this->kl['key'] && $this->key_size === $this->kl['key_size'] && $this->block_size === $this->kl['block_size']) { + // already expanded return; } + $this->kl = array('key' => $this->key, 'key_size' => $this->key_size, 'block_size' => $this->block_size); - if (!$this->explicit_key_length) { - // we do >> 2, here, and not >> 5, as we do above, since strlen($this->key) tells us the number of bytes - not bits - $length = strlen($this->key) >> 2; - if ($length > 8) { - $length = 8; - } else if ($length < 4) { - $length = 4; - } - $this->Nk = $length; - $this->key_size = $length << 2; - } - - $this->key = str_pad(substr($this->key, 0, $this->key_size), $this->key_size, chr(0)); - $this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($this->iv, 0, $this->block_size), $this->block_size, chr(0)); - + $this->Nk = $this->key_size >> 2; // see Rijndael-ammended.pdf#page=44 $this->Nr = max($this->Nk, $this->Nb) + 6; @@ -1208,9 +1118,7 @@ class Crypt_Rijndael { $this->c = array(0, 1, 3, 4); } - $key = $this->key; - - $w = array_values(unpack('N*words', $key)); + $w = array_values(unpack('N*words', $this->key)); $length = $this->Nb * ($this->Nr + 1); for ($i = $this->Nk; $i < $length; $i++) { @@ -1230,12 +1138,12 @@ class Crypt_Rijndael { // convert the key schedule from a vector of $Nb * ($Nr + 1) length to a matrix with $Nr + 1 rows and $Nb columns // and generate the inverse key schedule. more specifically, - // according to (section 5.3.3), + // according to (section 5.3.3), // "The key expansion for the Inverse Cipher is defined as follows: // 1. Apply the Key Expansion. // 2. Apply InvMixColumn to all Round Keys except the first and the last one." // also, see fips-197.pdf#page=27, "5.3.5 Equivalent Inverse Cipher" - $temp = array(); + $temp = $this->w = $this->dw = array(); for ($i = $row = $col = 0; $i < $length; $i++, $col++) { if ($col == $this->Nb) { if ($row == 0) { @@ -1245,9 +1153,9 @@ class Crypt_Rijndael { $j = 0; while ($j < $this->Nb) { $dw = $this->_subWord($this->w[$row][$j]); - $temp[$j] = $this->dt0[$dw >> 24 & 0x000000FF] ^ - $this->dt1[$dw >> 16 & 0x000000FF] ^ - $this->dt2[$dw >> 8 & 0x000000FF] ^ + $temp[$j] = $this->dt0[$dw >> 24 & 0x000000FF] ^ + $this->dt1[$dw >> 16 & 0x000000FF] ^ + $this->dt2[$dw >> 8 & 0x000000FF] ^ $this->dt3[$dw & 0x000000FF]; $j++; } @@ -1262,264 +1170,205 @@ class Crypt_Rijndael { $this->dw[$row] = $this->w[$row]; - $this->changed = false; + // In case of $this->use_inline_crypt === true we have to use 1-dim key arrays (both ascending) + if ($this->use_inline_crypt) { + $this->dw = array_reverse($this->dw); + $w = array_pop($this->w); + $dw = array_pop($this->dw); + foreach ($this->w as $r => $wr) { + foreach ($wr as $c => $wc) { + $w[] = $wc; + $dw[] = $this->dw[$r][$c]; + } + } + $this->w = $w; + $this->dw = $dw; + } } /** * Performs S-Box substitutions * * @access private + * @param Integer $word */ function _subWord($word) { - static $sbox0, $sbox1, $sbox2, $sbox3; + $sbox = $this->sbox; - if (empty($sbox0)) { - $sbox0 = array( - 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, - 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, - 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, - 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, - 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, - 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, - 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, - 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, - 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, - 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, - 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, - 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, - 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, - 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, - 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, - 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16 + return $sbox[$word & 0x000000FF] | + ($sbox[$word >> 8 & 0x000000FF] << 8) | + ($sbox[$word >> 16 & 0x000000FF] << 16) | + ($sbox[$word >> 24 & 0x000000FF] << 24); + } + + /** + * Setup the performance-optimized function for de/encrypt() + * + * @see Crypt_Base::_setupInlineCrypt() + * @access private + */ + function _setupInlineCrypt() + { + // Note: _setupInlineCrypt() will be called only if $this->changed === true + // So here we are'nt under the same heavy timing-stress as we are in _de/encryptBlock() or de/encrypt(). + // However...the here generated function- $code, stored as php callback in $this->inline_crypt, must work as fast as even possible. + + $lambda_functions =& Crypt_Rijndael::_getLambdaFunctions(); + + // The first 10 generated $lambda_functions will use the key-words hardcoded for better performance. + // For memory reason we limit those ultra-optimized functions. + // After that, we use pure (extracted) integer vars for the key-words which is faster than accessing them via array. + if (count($lambda_functions) < 10) { + $w = $this->w; + $dw = $this->dw; + $init_encrypt = ''; + $init_decrypt = ''; + } else { + for ($i = 0, $cw = count($this->w); $i < $cw; ++$i) { + $w[] = '$w[' . $i . ']'; + $dw[] = '$dw[' . $i . ']'; + } + $init_encrypt = '$w = $self->w;'; + $init_decrypt = '$dw = $self->dw;'; + } + + $code_hash = md5(str_pad("Crypt_Rijndael, {$this->mode}, {$this->block_size}, ", 32, "\0") . implode(',', $w)); + + if (!isset($lambda_functions[$code_hash])) { + $Nr = $this->Nr; + $Nb = $this->Nb; + $c = $this->c; + + // Generating encrypt code: + $init_encrypt.= ' + static $t0, $t1, $t2, $t3, $sbox; + if (!$t0) { + for ($i = 0; $i < 256; ++$i) { + $t0[$i] = (int)$self->t0[$i]; + $t1[$i] = (int)$self->t1[$i]; + $t2[$i] = (int)$self->t2[$i]; + $t3[$i] = (int)$self->t3[$i]; + $sbox[$i] = (int)$self->sbox[$i]; + } + } + '; + + $s = 'e'; + $e = 's'; + $wc = $Nb - 1; + + // Preround: addRoundKey + $encrypt_block = '$in = unpack("N*", $in);'."\n"; + for ($i = 0; $i < $Nb; ++$i) { + $encrypt_block .= '$s'.$i.' = $in['.($i + 1).'] ^ '.$w[++$wc].";\n"; + } + + // Mainrounds: shiftRows + subWord + mixColumns + addRoundKey + for ($round = 1; $round < $Nr; ++$round) { + list($s, $e) = array($e, $s); + for ($i = 0; $i < $Nb; ++$i) { + $encrypt_block.= + '$'.$e.$i.' = + $t0[($'.$s.$i .' >> 24) & 0xff] ^ + $t1[($'.$s.(($i + $c[1]) % $Nb).' >> 16) & 0xff] ^ + $t2[($'.$s.(($i + $c[2]) % $Nb).' >> 8) & 0xff] ^ + $t3[ $'.$s.(($i + $c[3]) % $Nb).' & 0xff] ^ + '.$w[++$wc].";\n"; + } + } + + // Finalround: subWord + shiftRows + addRoundKey + for ($i = 0; $i < $Nb; ++$i) { + $encrypt_block.= + '$'.$e.$i.' = + $sbox[ $'.$e.$i.' & 0xff] | + ($sbox[($'.$e.$i.' >> 8) & 0xff] << 8) | + ($sbox[($'.$e.$i.' >> 16) & 0xff] << 16) | + ($sbox[($'.$e.$i.' >> 24) & 0xff] << 24);'."\n"; + } + $encrypt_block .= '$in = pack("N*"'."\n"; + for ($i = 0; $i < $Nb; ++$i) { + $encrypt_block.= ', + ($'.$e.$i .' & 0xFF000000) ^ + ($'.$e.(($i + $c[1]) % $Nb).' & 0x00FF0000) ^ + ($'.$e.(($i + $c[2]) % $Nb).' & 0x0000FF00) ^ + ($'.$e.(($i + $c[3]) % $Nb).' & 0x000000FF) ^ + '.$w[$i]."\n"; + } + $encrypt_block .= ');'; + + // Generating decrypt code: + $init_decrypt.= ' + static $dt0, $dt1, $dt2, $dt3, $isbox; + if (!$dt0) { + for ($i = 0; $i < 256; ++$i) { + $dt0[$i] = (int)$self->dt0[$i]; + $dt1[$i] = (int)$self->dt1[$i]; + $dt2[$i] = (int)$self->dt2[$i]; + $dt3[$i] = (int)$self->dt3[$i]; + $isbox[$i] = (int)$self->isbox[$i]; + } + } + '; + + $s = 'e'; + $e = 's'; + $wc = $Nb - 1; + + // Preround: addRoundKey + $decrypt_block = '$in = unpack("N*", $in);'."\n"; + for ($i = 0; $i < $Nb; ++$i) { + $decrypt_block .= '$s'.$i.' = $in['.($i + 1).'] ^ '.$dw[++$wc].';'."\n"; + } + + // Mainrounds: shiftRows + subWord + mixColumns + addRoundKey + for ($round = 1; $round < $Nr; ++$round) { + list($s, $e) = array($e, $s); + for ($i = 0; $i < $Nb; ++$i) { + $decrypt_block.= + '$'.$e.$i.' = + $dt0[($'.$s.$i .' >> 24) & 0xff] ^ + $dt1[($'.$s.(($Nb + $i - $c[1]) % $Nb).' >> 16) & 0xff] ^ + $dt2[($'.$s.(($Nb + $i - $c[2]) % $Nb).' >> 8) & 0xff] ^ + $dt3[ $'.$s.(($Nb + $i - $c[3]) % $Nb).' & 0xff] ^ + '.$dw[++$wc].";\n"; + } + } + + // Finalround: subWord + shiftRows + addRoundKey + for ($i = 0; $i < $Nb; ++$i) { + $decrypt_block.= + '$'.$e.$i.' = + $isbox[ $'.$e.$i.' & 0xff] | + ($isbox[($'.$e.$i.' >> 8) & 0xff] << 8) | + ($isbox[($'.$e.$i.' >> 16) & 0xff] << 16) | + ($isbox[($'.$e.$i.' >> 24) & 0xff] << 24);'."\n"; + } + $decrypt_block .= '$in = pack("N*"'."\n"; + for ($i = 0; $i < $Nb; ++$i) { + $decrypt_block.= ', + ($'.$e.$i. ' & 0xFF000000) ^ + ($'.$e.(($Nb + $i - $c[1]) % $Nb).' & 0x00FF0000) ^ + ($'.$e.(($Nb + $i - $c[2]) % $Nb).' & 0x0000FF00) ^ + ($'.$e.(($Nb + $i - $c[3]) % $Nb).' & 0x000000FF) ^ + '.$dw[$i]."\n"; + } + $decrypt_block .= ');'; + + $lambda_functions[$code_hash] = $this->_createInlineCryptFunction( + array( + 'init_crypt' => '', + 'init_encrypt' => $init_encrypt, + 'init_decrypt' => $init_decrypt, + 'encrypt_block' => $encrypt_block, + 'decrypt_block' => $decrypt_block + ) ); - - $sbox1 = array(); - $sbox2 = array(); - $sbox3 = array(); - - for ($i = 0; $i < 256; $i++) { - $sbox1[] = $sbox0[$i] << 8; - $sbox2[] = $sbox0[$i] << 16; - $sbox3[] = $sbox0[$i] << 24; - } } - - return $sbox0[$word & 0x000000FF] | - $sbox1[$word >> 8 & 0x000000FF] | - $sbox2[$word >> 16 & 0x000000FF] | - $sbox3[$word >> 24 & 0x000000FF]; - } - - - /** - * Performs inverse S-Box substitutions - * - * @access private - */ - function _invSubWord($word) - { - static $sbox0, $sbox1, $sbox2, $sbox3; - - if (empty($sbox0)) { - $sbox0 = array( - 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB, - 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, - 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, - 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25, - 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, - 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, - 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06, - 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, - 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, - 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E, - 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, - 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, - 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F, - 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, - 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, - 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D - ); - - $sbox1 = array(); - $sbox2 = array(); - $sbox3 = array(); - - for ($i = 0; $i < 256; $i++) { - $sbox1[] = $sbox0[$i] << 8; - $sbox2[] = $sbox0[$i] << 16; - $sbox3[] = $sbox0[$i] << 24; - } - } - - return $sbox0[$word & 0x000000FF] | - $sbox1[$word >> 8 & 0x000000FF] | - $sbox2[$word >> 16 & 0x000000FF] | - $sbox3[$word >> 24 & 0x000000FF]; - } - - /** - * Pad "packets". - * - * Rijndael works by encrypting between sixteen and thirty-two bytes at a time, provided that number is also a multiple - * of four. If you ever need to encrypt or decrypt something that isn't of the proper length, it becomes necessary to - * pad the input so that it is of the proper length. - * - * Padding is enabled by default. Sometimes, however, it is undesirable to pad strings. Such is the case in SSH, - * where "packets" are padded with random bytes before being encrypted. Unpad these packets and you risk stripping - * away characters that shouldn't be stripped away. (SSH knows how many bytes are added because the length is - * transmitted separately) - * - * @see Crypt_Rijndael::disablePadding() - * @access public - */ - function enablePadding() - { - $this->padding = true; - } - - /** - * Do not pad packets. - * - * @see Crypt_Rijndael::enablePadding() - * @access public - */ - function disablePadding() - { - $this->padding = false; - } - - /** - * Pads a string - * - * Pads a string using the RSA PKCS padding standards so that its length is a multiple of the blocksize. - * $block_size - (strlen($text) % $block_size) bytes are added, each of which is equal to - * chr($block_size - (strlen($text) % $block_size) - * - * If padding is disabled and $text is not a multiple of the blocksize, the string will be padded regardless - * and padding will, hence forth, be enabled. - * - * @see Crypt_Rijndael::_unpad() - * @access private - */ - function _pad($text) - { - $length = strlen($text); - - if (!$this->padding) { - if ($length % $this->block_size == 0) { - return $text; - } else { - user_error("The plaintext's length ($length) is not a multiple of the block size ({$this->block_size})"); - $this->padding = true; - } - } - - $pad = $this->block_size - ($length % $this->block_size); - - return str_pad($text, $length + $pad, chr($pad)); - } - - /** - * Unpads a string. - * - * If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong - * and false will be returned. - * - * @see Crypt_Rijndael::_pad() - * @access private - */ - function _unpad($text) - { - if (!$this->padding) { - return $text; - } - - $length = ord($text[strlen($text) - 1]); - - if (!$length || $length > $this->block_size) { - return false; - } - - return substr($text, 0, -$length); - } - - /** - * Treat consecutive "packets" as if they are a continuous buffer. - * - * Say you have a 32-byte plaintext $plaintext. Using the default behavior, the two following code snippets - * will yield different outputs: - * - * - * echo $rijndael->encrypt(substr($plaintext, 0, 16)); - * echo $rijndael->encrypt(substr($plaintext, 16, 16)); - * - * - * echo $rijndael->encrypt($plaintext); - * - * - * The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates - * another, as demonstrated with the following: - * - * - * $rijndael->encrypt(substr($plaintext, 0, 16)); - * echo $rijndael->decrypt($des->encrypt(substr($plaintext, 16, 16))); - * - * - * echo $rijndael->decrypt($des->encrypt(substr($plaintext, 16, 16))); - * - * - * With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different - * outputs. The reason is due to the fact that the initialization vector's change after every encryption / - * decryption round when the continuous buffer is enabled. When it's disabled, they remain constant. - * - * Put another way, when the continuous buffer is enabled, the state of the Crypt_Rijndael() object changes after each - * encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that - * continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them), - * however, they are also less intuitive and more likely to cause you problems. - * - * @see Crypt_Rijndael::disableContinuousBuffer() - * @access public - */ - function enableContinuousBuffer() - { - $this->continuousBuffer = true; - } - - /** - * Treat consecutive packets as if they are a discontinuous buffer. - * - * The default behavior. - * - * @see Crypt_Rijndael::enableContinuousBuffer() - * @access public - */ - function disableContinuousBuffer() - { - $this->continuousBuffer = false; - $this->encryptIV = $this->iv; - $this->decryptIV = $this->iv; - $this->enbuffer = array('encrypted' => '', 'xor' => '', 'pos' => 0); - $this->debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0); - } - - /** - * String Shift - * - * Inspired by array_shift - * - * @param String $string - * @param optional Integer $index - * @return String - * @access private - */ - function _string_shift(&$string, $index = 1) - { - $substr = substr($string, 0, $index); - $string = substr($string, $index); - return $substr; + $this->inline_crypt = $lambda_functions[$code_hash]; } } // vim: ts=4:sw=4:et: -// vim6: fdl=1: \ No newline at end of file +// vim6: fdl=1: diff --git a/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/TripleDES.php b/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/TripleDES.php index 3b4c8c3622..4030c6c9fb 100644 --- a/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/TripleDES.php +++ b/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/TripleDES.php @@ -33,10 +33,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -50,7 +50,6 @@ * @author Jim Wigginton * @copyright MMVII Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @version $Id: TripleDES.php,v 1.13 2010/02/26 03:40:25 terrafrost Exp $ * @link http://phpseclib.sourceforge.net */ @@ -81,253 +80,157 @@ define('CRYPT_DES_MODE_CBC3', CRYPT_DES_MODE_CBC); * @author Jim Wigginton * @version 0.1.0 * @access public - * @package Crypt_TerraDES + * @package Crypt_TripleDES */ -class Crypt_TripleDES { +class Crypt_TripleDES extends Crypt_DES { /** - * The Three Keys + * The default password key_size used by setPassword() * - * @see Crypt_TripleDES::setKey() - * @var String - * @access private - */ - var $key = "\0\0\0\0\0\0\0\0"; - - /** - * The Encryption Mode - * - * @see Crypt_TripleDES::Crypt_TripleDES() + * @see Crypt_DES::password_key_size + * @see Crypt_Base::password_key_size + * @see Crypt_Base::setPassword() * @var Integer * @access private */ - var $mode = CRYPT_DES_MODE_CBC; + var $password_key_size = 24; /** - * Continuous Buffer status + * The default salt used by setPassword() + * + * @see Crypt_Base::password_default_salt + * @see Crypt_Base::setPassword() + * @var String + * @access private + */ + var $password_default_salt = 'phpseclib'; + + /** + * The namespace used by the cipher for its constants. + * + * @see Crypt_DES::const_namespace + * @see Crypt_Base::const_namespace + * @var String + * @access private + */ + var $const_namespace = 'DES'; + + /** + * The mcrypt specific name of the cipher + * + * @see Crypt_DES::cipher_name_mcrypt + * @see Crypt_Base::cipher_name_mcrypt + * @var String + * @access private + */ + var $cipher_name_mcrypt = 'tripledes'; + + /** + * Optimizing value while CFB-encrypting + * + * @see Crypt_Base::cfb_init_len + * @var Integer + * @access private + */ + var $cfb_init_len = 750; + + /** + * max possible size of $key + * + * @see Crypt_TripleDES::setKey() + * @see Crypt_DES::setKey() + * @var String + * @access private + */ + var $key_size_max = 24; + + /** + * Internal flag whether using CRYPT_DES_MODE_3CBC or not * - * @see Crypt_TripleDES::enableContinuousBuffer() * @var Boolean * @access private */ - var $continuousBuffer = false; - - /** - * Padding status - * - * @see Crypt_TripleDES::enablePadding() - * @var Boolean - * @access private - */ - var $padding = true; - - /** - * The Initialization Vector - * - * @see Crypt_TripleDES::setIV() - * @var String - * @access private - */ - var $iv = "\0\0\0\0\0\0\0\0"; - - /** - * A "sliding" Initialization Vector - * - * @see Crypt_TripleDES::enableContinuousBuffer() - * @var String - * @access private - */ - var $encryptIV = "\0\0\0\0\0\0\0\0"; - - /** - * A "sliding" Initialization Vector - * - * @see Crypt_TripleDES::enableContinuousBuffer() - * @var String - * @access private - */ - var $decryptIV = "\0\0\0\0\0\0\0\0"; + var $mode_3cbc; /** * The Crypt_DES objects * + * Used only if $mode_3cbc === true + * * @var Array * @access private */ var $des; - /** - * mcrypt resource for encryption - * - * The mcrypt resource can be recreated every time something needs to be created or it can be created just once. - * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode. - * - * @see Crypt_TripleDES::encrypt() - * @var String - * @access private - */ - var $enmcrypt; - - /** - * mcrypt resource for decryption - * - * The mcrypt resource can be recreated every time something needs to be created or it can be created just once. - * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode. - * - * @see Crypt_TripleDES::decrypt() - * @var String - * @access private - */ - var $demcrypt; - - /** - * Does the enmcrypt resource need to be (re)initialized? - * - * @see Crypt_TripleDES::setKey() - * @see Crypt_TripleDES::setIV() - * @var Boolean - * @access private - */ - var $enchanged = true; - - /** - * Does the demcrypt resource need to be (re)initialized? - * - * @see Crypt_TripleDES::setKey() - * @see Crypt_TripleDES::setIV() - * @var Boolean - * @access private - */ - var $dechanged = true; - - /** - * Is the mode one that is paddable? - * - * @see Crypt_TripleDES::Crypt_TripleDES() - * @var Boolean - * @access private - */ - var $paddable = false; - - /** - * Encryption buffer for CTR, OFB and CFB modes - * - * @see Crypt_TripleDES::encrypt() - * @var Array - * @access private - */ - var $enbuffer = array('encrypted' => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true); - - /** - * Decryption buffer for CTR, OFB and CFB modes - * - * @see Crypt_TripleDES::decrypt() - * @var Array - * @access private - */ - var $debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0, 'demcrypt_init' => true); - - /** - * mcrypt resource for CFB mode - * - * @see Crypt_TripleDES::encrypt() - * @see Crypt_TripleDES::decrypt() - * @var String - * @access private - */ - var $ecb; - /** * Default Constructor. * - * Determines whether or not the mcrypt extension should be used. $mode should only, at present, be - * CRYPT_DES_MODE_ECB or CRYPT_DES_MODE_CBC. If not explictly set, CRYPT_DES_MODE_CBC will be used. + * Determines whether or not the mcrypt extension should be used. * + * $mode could be: + * + * - CRYPT_DES_MODE_ECB + * + * - CRYPT_DES_MODE_CBC + * + * - CRYPT_DES_MODE_CTR + * + * - CRYPT_DES_MODE_CFB + * + * - CRYPT_DES_MODE_OFB + * + * - CRYPT_DES_MODE_3CBC + * + * If not explictly set, CRYPT_DES_MODE_CBC will be used. + * + * @see Crypt_DES::Crypt_DES() + * @see Crypt_Base::Crypt_Base() * @param optional Integer $mode - * @return Crypt_TripleDES * @access public */ function Crypt_TripleDES($mode = CRYPT_DES_MODE_CBC) { - if ( !defined('CRYPT_DES_MODE') ) { - switch (true) { - case extension_loaded('mcrypt') && in_array('tripledes', mcrypt_list_algorithms()): - define('CRYPT_DES_MODE', CRYPT_DES_MODE_MCRYPT); - break; - default: - define('CRYPT_DES_MODE', CRYPT_DES_MODE_INTERNAL); - } - } + switch ($mode) { + // In case of CRYPT_DES_MODE_3CBC, we init as CRYPT_DES_MODE_CBC + // and additional flag us internally as 3CBC + case CRYPT_DES_MODE_3CBC: + parent::Crypt_DES(CRYPT_DES_MODE_CBC); + $this->mode_3cbc = true; - if ( $mode == CRYPT_DES_MODE_3CBC ) { - $this->mode = CRYPT_DES_MODE_3CBC; - $this->des = array( - new Crypt_DES(CRYPT_DES_MODE_CBC), - new Crypt_DES(CRYPT_DES_MODE_CBC), - new Crypt_DES(CRYPT_DES_MODE_CBC) - ); - $this->paddable = true; - - // we're going to be doing the padding, ourselves, so disable it in the Crypt_DES objects - $this->des[0]->disablePadding(); - $this->des[1]->disablePadding(); - $this->des[2]->disablePadding(); - - return; - } - - switch ( CRYPT_DES_MODE ) { - case CRYPT_DES_MODE_MCRYPT: - switch ($mode) { - case CRYPT_DES_MODE_ECB: - $this->paddable = true; - $this->mode = MCRYPT_MODE_ECB; - break; - case CRYPT_DES_MODE_CTR: - $this->mode = 'ctr'; - break; - case CRYPT_DES_MODE_CFB: - $this->mode = 'ncfb'; - $this->ecb = mcrypt_module_open(MCRYPT_3DES, '', MCRYPT_MODE_ECB, ''); - break; - case CRYPT_DES_MODE_OFB: - $this->mode = MCRYPT_MODE_NOFB; - break; - case CRYPT_DES_MODE_CBC: - default: - $this->paddable = true; - $this->mode = MCRYPT_MODE_CBC; - } - $this->enmcrypt = mcrypt_module_open(MCRYPT_3DES, '', $this->mode, ''); - $this->demcrypt = mcrypt_module_open(MCRYPT_3DES, '', $this->mode, ''); - - break; - default: + // This three $des'es will do the 3CBC work (if $key > 64bits) $this->des = array( - new Crypt_DES(CRYPT_DES_MODE_ECB), - new Crypt_DES(CRYPT_DES_MODE_ECB), - new Crypt_DES(CRYPT_DES_MODE_ECB) + new Crypt_DES(CRYPT_DES_MODE_CBC), + new Crypt_DES(CRYPT_DES_MODE_CBC), + new Crypt_DES(CRYPT_DES_MODE_CBC), ); - + // we're going to be doing the padding, ourselves, so disable it in the Crypt_DES objects $this->des[0]->disablePadding(); $this->des[1]->disablePadding(); $this->des[2]->disablePadding(); + break; + // If not 3CBC, we init as usual + default: + parent::Crypt_DES($mode); + } + } - switch ($mode) { - case CRYPT_DES_MODE_ECB: - case CRYPT_DES_MODE_CBC: - $this->paddable = true; - $this->mode = $mode; - break; - case CRYPT_DES_MODE_CTR: - case CRYPT_DES_MODE_CFB: - case CRYPT_DES_MODE_OFB: - $this->mode = $mode; - break; - default: - $this->paddable = true; - $this->mode = CRYPT_DES_MODE_CBC; - } + /** + * Sets the initialization vector. (optional) + * + * SetIV is not required when CRYPT_DES_MODE_ECB is being used. If not explictly set, it'll be assumed + * to be all zero's. + * + * @see Crypt_Base::setIV() + * @access public + * @param String $iv + */ + function setIV($iv) + { + parent::setIV($iv); + if ($this->mode_3cbc) { + $this->des[0]->setIV($iv); + $this->des[1]->setIV($iv); + $this->des[2]->setIV($iv); } } @@ -339,568 +242,77 @@ class Crypt_TripleDES { * * DES also requires that every eighth bit be a parity bit, however, we'll ignore that. * - * If the key is not explicitly set, it'll be assumed to be all zero's. + * If the key is not explicitly set, it'll be assumed to be all null bytes. * * @access public + * @see Crypt_DES::setKey() + * @see Crypt_Base::setKey() * @param String $key */ function setKey($key) { $length = strlen($key); if ($length > 8) { - $key = str_pad($key, 24, chr(0)); + $key = str_pad(substr($key, 0, 24), 24, chr(0)); // if $key is between 64 and 128-bits, use the first 64-bits as the last, per this: // http://php.net/function.mcrypt-encrypt#47973 //$key = $length <= 16 ? substr_replace($key, substr($key, 0, 8), 16) : substr($key, 0, 24); } else { $key = str_pad($key, 8, chr(0)); } - $this->key = $key; - switch (true) { - case CRYPT_DES_MODE == CRYPT_DES_MODE_INTERNAL: - case $this->mode == CRYPT_DES_MODE_3CBC: - $this->des[0]->setKey(substr($key, 0, 8)); - $this->des[1]->setKey(substr($key, 8, 8)); - $this->des[2]->setKey(substr($key, 16, 8)); + parent::setKey($key); + + // And in case of CRYPT_DES_MODE_3CBC: + // if key <= 64bits we not need the 3 $des to work, + // because we will then act as regular DES-CBC with just a <= 64bit key. + // So only if the key > 64bits (> 8 bytes) we will call setKey() for the 3 $des. + if ($this->mode_3cbc && $length > 8) { + $this->des[0]->setKey(substr($key, 0, 8)); + $this->des[1]->setKey(substr($key, 8, 8)); + $this->des[2]->setKey(substr($key, 16, 8)); } - $this->enchanged = $this->dechanged = true; - } - - /** - * Sets the password. - * - * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows: - * {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2}: - * $hash, $salt, $method - * - * @param String $password - * @param optional String $method - * @access public - */ - function setPassword($password, $method = 'pbkdf2') - { - $key = ''; - - switch ($method) { - default: // 'pbkdf2' - list(, , $hash, $salt, $count) = func_get_args(); - if (!isset($hash)) { - $hash = 'sha1'; - } - // WPA and WPA2 use the SSID as the salt - if (!isset($salt)) { - $salt = 'phpseclib'; - } - // RFC2898#section-4.2 uses 1,000 iterations by default - // WPA and WPA2 use 4,096. - if (!isset($count)) { - $count = 1000; - } - - if (!class_exists('Crypt_Hash')) { - require_once('Crypt/Hash.php'); - } - - $i = 1; - while (strlen($key) < 24) { // $dkLen == 24 - $hmac = new Crypt_Hash(); - $hmac->setHash($hash); - $hmac->setKey($password); - $f = $u = $hmac->hash($salt . pack('N', $i++)); - for ($j = 2; $j <= $count; $j++) { - $u = $hmac->hash($u); - $f^= $u; - } - $key.= $f; - } - } - - $this->setKey($key); - } - - /** - * Sets the initialization vector. (optional) - * - * SetIV is not required when CRYPT_DES_MODE_ECB is being used. If not explictly set, it'll be assumed - * to be all zero's. - * - * @access public - * @param String $iv - */ - function setIV($iv) - { - $this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($iv, 0, 8), 8, chr(0)); - if ($this->mode == CRYPT_DES_MODE_3CBC) { - $this->des[0]->setIV($iv); - $this->des[1]->setIV($iv); - $this->des[2]->setIV($iv); - } - $this->enchanged = $this->dechanged = true; - } - - /** - * Generate CTR XOR encryption key - * - * Encrypt the output of this and XOR it against the ciphertext / plaintext to get the - * plaintext / ciphertext in CTR mode. - * - * @see Crypt_TripleDES::decrypt() - * @see Crypt_TripleDES::encrypt() - * @access private - * @param String $iv - */ - function _generate_xor(&$iv) - { - $xor = $iv; - for ($j = 4; $j <= 8; $j+=4) { - $temp = substr($iv, -$j, 4); - switch ($temp) { - case "\xFF\xFF\xFF\xFF": - $iv = substr_replace($iv, "\x00\x00\x00\x00", -$j, 4); - break; - case "\x7F\xFF\xFF\xFF": - $iv = substr_replace($iv, "\x80\x00\x00\x00", -$j, 4); - break 2; - default: - extract(unpack('Ncount', $temp)); - $iv = substr_replace($iv, pack('N', $count + 1), -$j, 4); - break 2; - } - } - - return $xor; } /** * Encrypts a message. * + * @see Crypt_Base::encrypt() * @access public * @param String $plaintext + * @return String $cipertext */ function encrypt($plaintext) { - if ($this->paddable) { - $plaintext = $this->_pad($plaintext); - } + // parent::en/decrypt() is able to do all the work for all modes and keylengths, + // except for: CRYPT_DES_MODE_3CBC (inner chaining CBC) with a key > 64bits // if the key is smaller then 8, do what we'd normally do - if ($this->mode == CRYPT_DES_MODE_3CBC && strlen($this->key) > 8) { - $ciphertext = $this->des[2]->encrypt($this->des[1]->decrypt($this->des[0]->encrypt($plaintext))); - - return $ciphertext; + if ($this->mode_3cbc && strlen($this->key) > 8) { + return $this->des[2]->encrypt( + $this->des[1]->decrypt( + $this->des[0]->encrypt($this->_pad($plaintext)))); } - if ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) { - if ($this->enchanged) { - mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV); - if ($this->mode == 'ncfb') { - mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0"); - } - $this->enchanged = false; - } - - if ($this->mode != 'ncfb' || !$this->continuousBuffer) { - $ciphertext = mcrypt_generic($this->enmcrypt, $plaintext); - } else { - $iv = &$this->encryptIV; - $pos = &$this->enbuffer['pos']; - $len = strlen($plaintext); - $ciphertext = ''; - $i = 0; - if ($pos) { - $orig_pos = $pos; - $max = 8 - $pos; - if ($len >= $max) { - $i = $max; - $len-= $max; - $pos = 0; - } else { - $i = $len; - $pos+= $len; - $len = 0; - } - $ciphertext = substr($iv, $orig_pos) ^ $plaintext; - $iv = substr_replace($iv, $ciphertext, $orig_pos, $i); - $this->enbuffer['enmcrypt_init'] = true; - } - if ($len >= 8) { - if ($this->enbuffer['enmcrypt_init'] === false || $len > 950) { - if ($this->enbuffer['enmcrypt_init'] === true) { - mcrypt_generic_init($this->enmcrypt, $this->key, $iv); - $this->enbuffer['enmcrypt_init'] = false; - } - $ciphertext.= mcrypt_generic($this->enmcrypt, substr($plaintext, $i, $len - $len % 8)); - $iv = substr($ciphertext, -8); - $i = strlen($ciphertext); - $len%= 8; - } else { - while ($len >= 8) { - $iv = mcrypt_generic($this->ecb, $iv) ^ substr($plaintext, $i, 8); - $ciphertext.= $iv; - $len-= 8; - $i+= 8; - } - } - } - if ($len) { - $iv = mcrypt_generic($this->ecb, $iv); - $block = $iv ^ substr($plaintext, $i); - $iv = substr_replace($iv, $block, 0, $len); - $ciphertext.= $block; - $pos = $len; - } - return $ciphertext; - } - - if (!$this->continuousBuffer) { - mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV); - } - - return $ciphertext; - } - - if (strlen($this->key) <= 8) { - $this->des[0]->mode = $this->mode; - - return $this->des[0]->encrypt($plaintext); - } - - $des = $this->des; - - $buffer = &$this->enbuffer; - $continuousBuffer = $this->continuousBuffer; - $ciphertext = ''; - switch ($this->mode) { - case CRYPT_DES_MODE_ECB: - for ($i = 0; $i < strlen($plaintext); $i+=8) { - $block = substr($plaintext, $i, 8); - // all of these _processBlock calls could, in theory, be put in a function - say Crypt_TripleDES::_ede_encrypt() or something. - // only problem with that: it would slow encryption and decryption down. $this->des would have to be called every time that - // function is called, instead of once for the whole string of text that's being encrypted, which would, in turn, make - // encryption and decryption take more time, per this: - // - // http://blog.libssh2.org/index.php?/archives/21-Compiled-Variables.html - $block = $des[0]->_processBlock($block, CRYPT_DES_ENCRYPT); - $block = $des[1]->_processBlock($block, CRYPT_DES_DECRYPT); - $block = $des[2]->_processBlock($block, CRYPT_DES_ENCRYPT); - $ciphertext.= $block; - } - break; - case CRYPT_DES_MODE_CBC: - $xor = $this->encryptIV; - for ($i = 0; $i < strlen($plaintext); $i+=8) { - $block = substr($plaintext, $i, 8) ^ $xor; - $block = $des[0]->_processBlock($block, CRYPT_DES_ENCRYPT); - $block = $des[1]->_processBlock($block, CRYPT_DES_DECRYPT); - $block = $des[2]->_processBlock($block, CRYPT_DES_ENCRYPT); - $xor = $block; - $ciphertext.= $block; - } - if ($this->continuousBuffer) { - $this->encryptIV = $xor; - } - break; - case CRYPT_DES_MODE_CTR: - $xor = $this->encryptIV; - if (strlen($buffer['encrypted'])) { - for ($i = 0; $i < strlen($plaintext); $i+=8) { - $block = substr($plaintext, $i, 8); - $key = $this->_generate_xor($xor); - $key = $des[0]->_processBlock($key, CRYPT_DES_ENCRYPT); - $key = $des[1]->_processBlock($key, CRYPT_DES_DECRYPT); - $key = $des[2]->_processBlock($key, CRYPT_DES_ENCRYPT); - $buffer['encrypted'].= $key; - $key = $this->_string_shift($buffer['encrypted'], 8); - $ciphertext.= $block ^ $key; - } - } else { - for ($i = 0; $i < strlen($plaintext); $i+=8) { - $block = substr($plaintext, $i, 8); - $key = $this->_generate_xor($xor); - $key = $des[0]->_processBlock($key, CRYPT_DES_ENCRYPT); - $key = $des[1]->_processBlock($key, CRYPT_DES_DECRYPT); - $key = $des[2]->_processBlock($key, CRYPT_DES_ENCRYPT); - $ciphertext.= $block ^ $key; - } - } - if ($this->continuousBuffer) { - $this->encryptIV = $xor; - if ($start = strlen($plaintext) & 7) { - $buffer['encrypted'] = substr($key, $start) . $buffer['encrypted']; - } - } - break; - case CRYPT_DES_MODE_CFB: - if (strlen($buffer['xor'])) { - $ciphertext = $plaintext ^ $buffer['xor']; - $iv = $buffer['encrypted'] . $ciphertext; - $start = strlen($ciphertext); - $buffer['encrypted'].= $ciphertext; - $buffer['xor'] = substr($buffer['xor'], strlen($ciphertext)); - } else { - $ciphertext = ''; - $iv = $this->encryptIV; - $start = 0; - } - - for ($i = $start; $i < strlen($plaintext); $i+=8) { - $block = substr($plaintext, $i, 8); - $iv = $des[0]->_processBlock($iv, CRYPT_DES_ENCRYPT); - $iv = $des[1]->_processBlock($iv, CRYPT_DES_DECRYPT); - $xor= $des[2]->_processBlock($iv, CRYPT_DES_ENCRYPT); - - $iv = $block ^ $xor; - if ($continuousBuffer && strlen($iv) != 8) { - $buffer = array( - 'encrypted' => $iv, - 'xor' => substr($xor, strlen($iv)) - ); - } - $ciphertext.= $iv; - } - - if ($this->continuousBuffer) { - $this->encryptIV = $iv; - } - break; - case CRYPT_DES_MODE_OFB: - $xor = $this->encryptIV; - if (strlen($buffer['xor'])) { - for ($i = 0; $i < strlen($plaintext); $i+=8) { - $xor = $des[0]->_processBlock($xor, CRYPT_DES_ENCRYPT); - $xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT); - $xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT); - $buffer['xor'].= $xor; - $key = $this->_string_shift($buffer['xor'], 8); - $ciphertext.= substr($plaintext, $i, 8) ^ $key; - } - } else { - for ($i = 0; $i < strlen($plaintext); $i+=8) { - $xor = $des[0]->_processBlock($xor, CRYPT_DES_ENCRYPT); - $xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT); - $xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT); - $ciphertext.= substr($plaintext, $i, 8) ^ $xor; - } - $key = $xor; - } - if ($this->continuousBuffer) { - $this->encryptIV = $xor; - if ($start = strlen($plaintext) & 7) { - $buffer['xor'] = substr($key, $start) . $buffer['xor']; - } - } - } - - return $ciphertext; + return parent::encrypt($plaintext); } /** * Decrypts a message. * + * @see Crypt_Base::decrypt() * @access public * @param String $ciphertext + * @return String $plaintext */ function decrypt($ciphertext) { - if ($this->mode == CRYPT_DES_MODE_3CBC && strlen($this->key) > 8) { - $plaintext = $this->des[0]->decrypt($this->des[1]->encrypt($this->des[2]->decrypt($ciphertext))); - - return $this->_unpad($plaintext); + if ($this->mode_3cbc && strlen($this->key) > 8) { + return $this->_unpad($this->des[0]->decrypt( + $this->des[1]->encrypt( + $this->des[2]->decrypt(str_pad($ciphertext, (strlen($ciphertext) + 7) & 0xFFFFFFF8, "\0"))))); } - if ($this->paddable) { - // we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic : - // "The data is padded with "\0" to make sure the length of the data is n * blocksize." - $ciphertext = str_pad($ciphertext, (strlen($ciphertext) + 7) & 0xFFFFFFF8, chr(0)); - } - - if ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) { - if ($this->dechanged) { - mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV); - if ($this->mode == 'ncfb') { - mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0"); - } - $this->dechanged = false; - } - - if ($this->mode != 'ncfb' || !$this->continuousBuffer) { - $plaintext = mdecrypt_generic($this->demcrypt, $ciphertext); - } else { - $iv = &$this->decryptIV; - $pos = &$this->debuffer['pos']; - $len = strlen($ciphertext); - $plaintext = ''; - $i = 0; - if ($pos) { - $orig_pos = $pos; - $max = 8 - $pos; - if ($len >= $max) { - $i = $max; - $len-= $max; - $pos = 0; - } else { - $i = $len; - $pos+= $len; - $len = 0; - } - $plaintext = substr($iv, $orig_pos) ^ $ciphertext; - $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i); - } - if ($len >= 8) { - $cb = substr($ciphertext, $i, $len - $len % 8); - $plaintext.= mcrypt_generic($this->ecb, $iv . $cb) ^ $cb; - $iv = substr($cb, -8); - $len%= 8; - } - if ($len) { - $iv = mcrypt_generic($this->ecb, $iv); - $cb = substr($ciphertext, -$len); - $plaintext.= $iv ^ $cb; - $iv = substr_replace($iv, $cb, 0, $len); - $pos = $len; - } - return $plaintext; - } - - if (!$this->continuousBuffer) { - mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV); - } - - return $this->paddable ? $this->_unpad($plaintext) : $plaintext; - } - - if (strlen($this->key) <= 8) { - $this->des[0]->mode = $this->mode; - $plaintext = $this->des[0]->decrypt($ciphertext); - return $this->paddable ? $this->_unpad($plaintext) : $plaintext; - } - - $des = $this->des; - - $buffer = &$this->debuffer; - $continuousBuffer = $this->continuousBuffer; - $plaintext = ''; - switch ($this->mode) { - case CRYPT_DES_MODE_ECB: - for ($i = 0; $i < strlen($ciphertext); $i+=8) { - $block = substr($ciphertext, $i, 8); - $block = $des[2]->_processBlock($block, CRYPT_DES_DECRYPT); - $block = $des[1]->_processBlock($block, CRYPT_DES_ENCRYPT); - $block = $des[0]->_processBlock($block, CRYPT_DES_DECRYPT); - $plaintext.= $block; - } - break; - case CRYPT_DES_MODE_CBC: - $xor = $this->decryptIV; - for ($i = 0; $i < strlen($ciphertext); $i+=8) { - $orig = $block = substr($ciphertext, $i, 8); - $block = $des[2]->_processBlock($block, CRYPT_DES_DECRYPT); - $block = $des[1]->_processBlock($block, CRYPT_DES_ENCRYPT); - $block = $des[0]->_processBlock($block, CRYPT_DES_DECRYPT); - $plaintext.= $block ^ $xor; - $xor = $orig; - } - if ($this->continuousBuffer) { - $this->decryptIV = $xor; - } - break; - case CRYPT_DES_MODE_CTR: - $xor = $this->decryptIV; - if (strlen($buffer['ciphertext'])) { - for ($i = 0; $i < strlen($ciphertext); $i+=8) { - $block = substr($ciphertext, $i, 8); - $key = $this->_generate_xor($xor); - $key = $des[0]->_processBlock($key, CRYPT_DES_ENCRYPT); - $key = $des[1]->_processBlock($key, CRYPT_DES_DECRYPT); - $key = $des[2]->_processBlock($key, CRYPT_DES_ENCRYPT); - $buffer['ciphertext'].= $key; - $key = $this->_string_shift($buffer['ciphertext'], 8); - $plaintext.= $block ^ $key; - } - } else { - for ($i = 0; $i < strlen($ciphertext); $i+=8) { - $block = substr($ciphertext, $i, 8); - $key = $this->_generate_xor($xor); - $key = $des[0]->_processBlock($key, CRYPT_DES_ENCRYPT); - $key = $des[1]->_processBlock($key, CRYPT_DES_DECRYPT); - $key = $des[2]->_processBlock($key, CRYPT_DES_ENCRYPT); - $plaintext.= $block ^ $key; - } - } - if ($this->continuousBuffer) { - $this->decryptIV = $xor; - if ($start = strlen($plaintext) & 7) { - $buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext']; - } - } - break; - case CRYPT_DES_MODE_CFB: - if (strlen($buffer['ciphertext'])) { - $plaintext = $ciphertext ^ substr($this->decryptIV, strlen($buffer['ciphertext'])); - $buffer['ciphertext'].= substr($ciphertext, 0, strlen($plaintext)); - if (strlen($buffer['ciphertext']) != 8) { - $block = $this->decryptIV; - } else { - $block = $buffer['ciphertext']; - $xor = $des[0]->_processBlock($buffer['ciphertext'], CRYPT_DES_ENCRYPT); - $xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT); - $xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT); - $buffer['ciphertext'] = ''; - } - $start = strlen($plaintext); - } else { - $plaintext = ''; - $xor = $des[0]->_processBlock($this->decryptIV, CRYPT_DES_ENCRYPT); - $xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT); - $xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT); - $start = 0; - } - - for ($i = $start; $i < strlen($ciphertext); $i+=8) { - $block = substr($ciphertext, $i, 8); - $plaintext.= $block ^ $xor; - if ($continuousBuffer && strlen($block) != 8) { - $buffer['ciphertext'].= $block; - $block = $xor; - } else if (strlen($block) == 8) { - $xor = $des[0]->_processBlock($block, CRYPT_DES_ENCRYPT); - $xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT); - $xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT); - } - } - if ($this->continuousBuffer) { - $this->decryptIV = $block; - } - break; - case CRYPT_DES_MODE_OFB: - $xor = $this->decryptIV; - if (strlen($buffer['xor'])) { - for ($i = 0; $i < strlen($ciphertext); $i+=8) { - $xor = $des[0]->_processBlock($xor, CRYPT_DES_ENCRYPT); - $xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT); - $xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT); - $buffer['xor'].= $xor; - $key = $this->_string_shift($buffer['xor'], 8); - $plaintext.= substr($ciphertext, $i, 8) ^ $key; - } - } else { - for ($i = 0; $i < strlen($ciphertext); $i+=8) { - $xor = $des[0]->_processBlock($xor, CRYPT_DES_ENCRYPT); - $xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT); - $xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT); - $plaintext.= substr($ciphertext, $i, 8) ^ $xor; - } - $key = $xor; - } - if ($this->continuousBuffer) { - $this->decryptIV = $xor; - if ($start = strlen($ciphertext) & 7) { - $buffer['xor'] = substr($key, $start) . $buffer['xor']; - } - } - } - - return $this->paddable ? $this->_unpad($plaintext) : $plaintext; + return parent::decrypt($ciphertext); } /** @@ -937,13 +349,14 @@ class Crypt_TripleDES { * continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them), * however, they are also less intuitive and more likely to cause you problems. * + * @see Crypt_Base::enableContinuousBuffer() * @see Crypt_TripleDES::disableContinuousBuffer() * @access public */ function enableContinuousBuffer() { - $this->continuousBuffer = true; - if ($this->mode == CRYPT_DES_MODE_3CBC) { + parent::enableContinuousBuffer(); + if ($this->mode_3cbc) { $this->des[0]->enableContinuousBuffer(); $this->des[1]->enableContinuousBuffer(); $this->des[2]->enableContinuousBuffer(); @@ -955,20 +368,14 @@ class Crypt_TripleDES { * * The default behavior. * + * @see Crypt_Base::disableContinuousBuffer() * @see Crypt_TripleDES::enableContinuousBuffer() * @access public */ function disableContinuousBuffer() { - $this->continuousBuffer = false; - $this->encryptIV = $this->iv; - $this->decryptIV = $this->iv; - $this->enchanged = true; - $this->dechanged = true; - $this->enbuffer = array('encrypted' => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true); - $this->debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0, 'demcrypt_init' => true); - - if ($this->mode == CRYPT_DES_MODE_3CBC) { + parent::disableContinuousBuffer(); + if ($this->mode_3cbc) { $this->des[0]->disableContinuousBuffer(); $this->des[1]->disableContinuousBuffer(); $this->des[2]->disableContinuousBuffer(); @@ -976,103 +383,38 @@ class Crypt_TripleDES { } /** - * Pad "packets". + * Creates the key schedule * - * DES works by encrypting eight bytes at a time. If you ever need to encrypt or decrypt something that's not - * a multiple of eight, it becomes necessary to pad the input so that it's length is a multiple of eight. - * - * Padding is enabled by default. Sometimes, however, it is undesirable to pad strings. Such is the case in SSH1, - * where "packets" are padded with random bytes before being encrypted. Unpad these packets and you risk stripping - * away characters that shouldn't be stripped away. (SSH knows how many bytes are added because the length is - * transmitted separately) - * - * @see Crypt_TripleDES::disablePadding() - * @access public - */ - function enablePadding() - { - $this->padding = true; - } - - /** - * Do not pad packets. - * - * @see Crypt_TripleDES::enablePadding() - * @access public - */ - function disablePadding() - { - $this->padding = false; - } - - /** - * Pads a string - * - * Pads a string using the RSA PKCS padding standards so that its length is a multiple of the blocksize (8). - * 8 - (strlen($text) & 7) bytes are added, each of which is equal to chr(8 - (strlen($text) & 7) - * - * If padding is disabled and $text is not a multiple of the blocksize, the string will be padded regardless - * and padding will, hence forth, be enabled. - * - * @see Crypt_TripleDES::_unpad() + * @see Crypt_DES::_setupKey() + * @see Crypt_Base::_setupKey() * @access private */ - function _pad($text) + function _setupKey() { - $length = strlen($text); + switch (true) { + // if $key <= 64bits we configure our internal pure-php cipher engine + // to act as regular [1]DES, not as 3DES. mcrypt.so::tripledes does the same. + case strlen($this->key) <= 8: + $this->des_rounds = 1; + break; - if (!$this->padding) { - if (($length & 7) == 0) { - return $text; - } else { - user_error("The plaintext's length ($length) is not a multiple of the block size (8)", E_USER_NOTICE); - $this->padding = true; - } + // otherwise, if $key > 64bits, we configure our engine to work as 3DES. + default: + $this->des_rounds = 3; + + // (only) if 3CBC is used we have, of course, to setup the $des[0-2] keys also separately. + if ($this->mode_3cbc) { + $this->des[0]->_setupKey(); + $this->des[1]->_setupKey(); + $this->des[2]->_setupKey(); + + // because $des[0-2] will, now, do all the work we can return here + // not need unnecessary stress parent::_setupKey() with our, now unused, $key. + return; + } } - - $pad = 8 - ($length & 7); - return str_pad($text, $length + $pad, chr($pad)); - } - - /** - * Unpads a string - * - * If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong - * and false will be returned. - * - * @see Crypt_TripleDES::_pad() - * @access private - */ - function _unpad($text) - { - if (!$this->padding) { - return $text; - } - - $length = ord($text[strlen($text) - 1]); - - if (!$length || $length > 8) { - return false; - } - - return substr($text, 0, -$length); - } - - /** - * String Shift - * - * Inspired by array_shift - * - * @param String $string - * @param optional Integer $index - * @return String - * @access private - */ - function _string_shift(&$string, $index = 1) - { - $substr = substr($string, 0, $index); - $string = substr($string, $index); - return $substr; + // setup our key + parent::_setupKey(); } } diff --git a/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/Twofish.php b/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/Twofish.php new file mode 100644 index 0000000000..6342298d1a --- /dev/null +++ b/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/Twofish.php @@ -0,0 +1,924 @@ + + * setKey('12345678901234567890123456789012'); + * + * $plaintext = str_repeat('a', 1024); + * + * echo $twofish->decrypt($twofish->encrypt($plaintext)); + * ?> + * + * + * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @category Crypt + * @package Crypt_Twofish + * @author Jim Wigginton + * @author Hans-Juergen Petrich + * @copyright MMVII Jim Wigginton + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @version 1.0 + * @link http://phpseclib.sourceforge.net + */ + +/** + * Include Crypt_Base + * + * Base cipher class + */ +if (!class_exists('Crypt_Base')) { + require_once('Base.php'); +} + +/**#@+ + * @access public + * @see Crypt_Twofish::encrypt() + * @see Crypt_Twofish::decrypt() + */ +/** + * Encrypt / decrypt using the Counter mode. + * + * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29 + */ +define('CRYPT_TWOFISH_MODE_CTR', CRYPT_MODE_CTR); +/** + * Encrypt / decrypt using the Electronic Code Book mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29 + */ +define('CRYPT_TWOFISH_MODE_ECB', CRYPT_MODE_ECB); +/** + * Encrypt / decrypt using the Code Book Chaining mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29 + */ +define('CRYPT_TWOFISH_MODE_CBC', CRYPT_MODE_CBC); +/** + * Encrypt / decrypt using the Cipher Feedback mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29 + */ +define('CRYPT_TWOFISH_MODE_CFB', CRYPT_MODE_CFB); +/** + * Encrypt / decrypt using the Cipher Feedback mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29 + */ +define('CRYPT_TWOFISH_MODE_OFB', CRYPT_MODE_OFB); +/**#@-*/ + +/**#@+ + * @access private + * @see Crypt_Twofish::Crypt_Twofish() + */ +/** + * Toggles the internal implementation + */ +define('CRYPT_TWOFISH_MODE_INTERNAL', CRYPT_MODE_INTERNAL); +/** + * Toggles the mcrypt implementation + */ +define('CRYPT_TWOFISH_MODE_MCRYPT', CRYPT_MODE_MCRYPT); +/**#@-*/ + +/** + * Pure-PHP implementation of Twofish. + * + * @author Jim Wigginton + * @author Hans-Juergen Petrich + * @version 1.0 + * @access public + * @package Crypt_Twofish + */ +class Crypt_Twofish extends Crypt_Base { + /** + * The namespace used by the cipher for its constants. + * + * @see Crypt_Base::const_namespace + * @var String + * @access private + */ + var $const_namespace = 'TWOFISH'; + + /** + * The mcrypt specific name of the cipher + * + * @see Crypt_Base::cipher_name_mcrypt + * @var String + * @access private + */ + var $cipher_name_mcrypt = 'twofish'; + + /** + * Optimizing value while CFB-encrypting + * + * @see Crypt_Base::cfb_init_len + * @var Integer + * @access private + */ + var $cfb_init_len = 800; + + /** + * Q-Table + * + * @var Array + * @access private + */ + var $q0 = array ( + 0xA9, 0x67, 0xB3, 0xE8, 0x04, 0xFD, 0xA3, 0x76, + 0x9A, 0x92, 0x80, 0x78, 0xE4, 0xDD, 0xD1, 0x38, + 0x0D, 0xC6, 0x35, 0x98, 0x18, 0xF7, 0xEC, 0x6C, + 0x43, 0x75, 0x37, 0x26, 0xFA, 0x13, 0x94, 0x48, + 0xF2, 0xD0, 0x8B, 0x30, 0x84, 0x54, 0xDF, 0x23, + 0x19, 0x5B, 0x3D, 0x59, 0xF3, 0xAE, 0xA2, 0x82, + 0x63, 0x01, 0x83, 0x2E, 0xD9, 0x51, 0x9B, 0x7C, + 0xA6, 0xEB, 0xA5, 0xBE, 0x16, 0x0C, 0xE3, 0x61, + 0xC0, 0x8C, 0x3A, 0xF5, 0x73, 0x2C, 0x25, 0x0B, + 0xBB, 0x4E, 0x89, 0x6B, 0x53, 0x6A, 0xB4, 0xF1, + 0xE1, 0xE6, 0xBD, 0x45, 0xE2, 0xF4, 0xB6, 0x66, + 0xCC, 0x95, 0x03, 0x56, 0xD4, 0x1C, 0x1E, 0xD7, + 0xFB, 0xC3, 0x8E, 0xB5, 0xE9, 0xCF, 0xBF, 0xBA, + 0xEA, 0x77, 0x39, 0xAF, 0x33, 0xC9, 0x62, 0x71, + 0x81, 0x79, 0x09, 0xAD, 0x24, 0xCD, 0xF9, 0xD8, + 0xE5, 0xC5, 0xB9, 0x4D, 0x44, 0x08, 0x86, 0xE7, + 0xA1, 0x1D, 0xAA, 0xED, 0x06, 0x70, 0xB2, 0xD2, + 0x41, 0x7B, 0xA0, 0x11, 0x31, 0xC2, 0x27, 0x90, + 0x20, 0xF6, 0x60, 0xFF, 0x96, 0x5C, 0xB1, 0xAB, + 0x9E, 0x9C, 0x52, 0x1B, 0x5F, 0x93, 0x0A, 0xEF, + 0x91, 0x85, 0x49, 0xEE, 0x2D, 0x4F, 0x8F, 0x3B, + 0x47, 0x87, 0x6D, 0x46, 0xD6, 0x3E, 0x69, 0x64, + 0x2A, 0xCE, 0xCB, 0x2F, 0xFC, 0x97, 0x05, 0x7A, + 0xAC, 0x7F, 0xD5, 0x1A, 0x4B, 0x0E, 0xA7, 0x5A, + 0x28, 0x14, 0x3F, 0x29, 0x88, 0x3C, 0x4C, 0x02, + 0xB8, 0xDA, 0xB0, 0x17, 0x55, 0x1F, 0x8A, 0x7D, + 0x57, 0xC7, 0x8D, 0x74, 0xB7, 0xC4, 0x9F, 0x72, + 0x7E, 0x15, 0x22, 0x12, 0x58, 0x07, 0x99, 0x34, + 0x6E, 0x50, 0xDE, 0x68, 0x65, 0xBC, 0xDB, 0xF8, + 0xC8, 0xA8, 0x2B, 0x40, 0xDC, 0xFE, 0x32, 0xA4, + 0xCA, 0x10, 0x21, 0xF0, 0xD3, 0x5D, 0x0F, 0x00, + 0x6F, 0x9D, 0x36, 0x42, 0x4A, 0x5E, 0xC1, 0xE0 + ); + + /** + * Q-Table + * + * @var Array + * @access private + */ + var $q1 = array ( + 0x75, 0xF3, 0xC6, 0xF4, 0xDB, 0x7B, 0xFB, 0xC8, + 0x4A, 0xD3, 0xE6, 0x6B, 0x45, 0x7D, 0xE8, 0x4B, + 0xD6, 0x32, 0xD8, 0xFD, 0x37, 0x71, 0xF1, 0xE1, + 0x30, 0x0F, 0xF8, 0x1B, 0x87, 0xFA, 0x06, 0x3F, + 0x5E, 0xBA, 0xAE, 0x5B, 0x8A, 0x00, 0xBC, 0x9D, + 0x6D, 0xC1, 0xB1, 0x0E, 0x80, 0x5D, 0xD2, 0xD5, + 0xA0, 0x84, 0x07, 0x14, 0xB5, 0x90, 0x2C, 0xA3, + 0xB2, 0x73, 0x4C, 0x54, 0x92, 0x74, 0x36, 0x51, + 0x38, 0xB0, 0xBD, 0x5A, 0xFC, 0x60, 0x62, 0x96, + 0x6C, 0x42, 0xF7, 0x10, 0x7C, 0x28, 0x27, 0x8C, + 0x13, 0x95, 0x9C, 0xC7, 0x24, 0x46, 0x3B, 0x70, + 0xCA, 0xE3, 0x85, 0xCB, 0x11, 0xD0, 0x93, 0xB8, + 0xA6, 0x83, 0x20, 0xFF, 0x9F, 0x77, 0xC3, 0xCC, + 0x03, 0x6F, 0x08, 0xBF, 0x40, 0xE7, 0x2B, 0xE2, + 0x79, 0x0C, 0xAA, 0x82, 0x41, 0x3A, 0xEA, 0xB9, + 0xE4, 0x9A, 0xA4, 0x97, 0x7E, 0xDA, 0x7A, 0x17, + 0x66, 0x94, 0xA1, 0x1D, 0x3D, 0xF0, 0xDE, 0xB3, + 0x0B, 0x72, 0xA7, 0x1C, 0xEF, 0xD1, 0x53, 0x3E, + 0x8F, 0x33, 0x26, 0x5F, 0xEC, 0x76, 0x2A, 0x49, + 0x81, 0x88, 0xEE, 0x21, 0xC4, 0x1A, 0xEB, 0xD9, + 0xC5, 0x39, 0x99, 0xCD, 0xAD, 0x31, 0x8B, 0x01, + 0x18, 0x23, 0xDD, 0x1F, 0x4E, 0x2D, 0xF9, 0x48, + 0x4F, 0xF2, 0x65, 0x8E, 0x78, 0x5C, 0x58, 0x19, + 0x8D, 0xE5, 0x98, 0x57, 0x67, 0x7F, 0x05, 0x64, + 0xAF, 0x63, 0xB6, 0xFE, 0xF5, 0xB7, 0x3C, 0xA5, + 0xCE, 0xE9, 0x68, 0x44, 0xE0, 0x4D, 0x43, 0x69, + 0x29, 0x2E, 0xAC, 0x15, 0x59, 0xA8, 0x0A, 0x9E, + 0x6E, 0x47, 0xDF, 0x34, 0x35, 0x6A, 0xCF, 0xDC, + 0x22, 0xC9, 0xC0, 0x9B, 0x89, 0xD4, 0xED, 0xAB, + 0x12, 0xA2, 0x0D, 0x52, 0xBB, 0x02, 0x2F, 0xA9, + 0xD7, 0x61, 0x1E, 0xB4, 0x50, 0x04, 0xF6, 0xC2, + 0x16, 0x25, 0x86, 0x56, 0x55, 0x09, 0xBE, 0x91 + ); + + /** + * M-Table + * + * @var Array + * @access private + */ + var $m0 = array ( + 0xBCBC3275, 0xECEC21F3, 0x202043C6, 0xB3B3C9F4, 0xDADA03DB, 0x02028B7B, 0xE2E22BFB, 0x9E9EFAC8, + 0xC9C9EC4A, 0xD4D409D3, 0x18186BE6, 0x1E1E9F6B, 0x98980E45, 0xB2B2387D, 0xA6A6D2E8, 0x2626B74B, + 0x3C3C57D6, 0x93938A32, 0x8282EED8, 0x525298FD, 0x7B7BD437, 0xBBBB3771, 0x5B5B97F1, 0x474783E1, + 0x24243C30, 0x5151E20F, 0xBABAC6F8, 0x4A4AF31B, 0xBFBF4887, 0x0D0D70FA, 0xB0B0B306, 0x7575DE3F, + 0xD2D2FD5E, 0x7D7D20BA, 0x666631AE, 0x3A3AA35B, 0x59591C8A, 0x00000000, 0xCDCD93BC, 0x1A1AE09D, + 0xAEAE2C6D, 0x7F7FABC1, 0x2B2BC7B1, 0xBEBEB90E, 0xE0E0A080, 0x8A8A105D, 0x3B3B52D2, 0x6464BAD5, + 0xD8D888A0, 0xE7E7A584, 0x5F5FE807, 0x1B1B1114, 0x2C2CC2B5, 0xFCFCB490, 0x3131272C, 0x808065A3, + 0x73732AB2, 0x0C0C8173, 0x79795F4C, 0x6B6B4154, 0x4B4B0292, 0x53536974, 0x94948F36, 0x83831F51, + 0x2A2A3638, 0xC4C49CB0, 0x2222C8BD, 0xD5D5F85A, 0xBDBDC3FC, 0x48487860, 0xFFFFCE62, 0x4C4C0796, + 0x4141776C, 0xC7C7E642, 0xEBEB24F7, 0x1C1C1410, 0x5D5D637C, 0x36362228, 0x6767C027, 0xE9E9AF8C, + 0x4444F913, 0x1414EA95, 0xF5F5BB9C, 0xCFCF18C7, 0x3F3F2D24, 0xC0C0E346, 0x7272DB3B, 0x54546C70, + 0x29294CCA, 0xF0F035E3, 0x0808FE85, 0xC6C617CB, 0xF3F34F11, 0x8C8CE4D0, 0xA4A45993, 0xCACA96B8, + 0x68683BA6, 0xB8B84D83, 0x38382820, 0xE5E52EFF, 0xADAD569F, 0x0B0B8477, 0xC8C81DC3, 0x9999FFCC, + 0x5858ED03, 0x19199A6F, 0x0E0E0A08, 0x95957EBF, 0x70705040, 0xF7F730E7, 0x6E6ECF2B, 0x1F1F6EE2, + 0xB5B53D79, 0x09090F0C, 0x616134AA, 0x57571682, 0x9F9F0B41, 0x9D9D803A, 0x111164EA, 0x2525CDB9, + 0xAFAFDDE4, 0x4545089A, 0xDFDF8DA4, 0xA3A35C97, 0xEAEAD57E, 0x353558DA, 0xEDEDD07A, 0x4343FC17, + 0xF8F8CB66, 0xFBFBB194, 0x3737D3A1, 0xFAFA401D, 0xC2C2683D, 0xB4B4CCF0, 0x32325DDE, 0x9C9C71B3, + 0x5656E70B, 0xE3E3DA72, 0x878760A7, 0x15151B1C, 0xF9F93AEF, 0x6363BFD1, 0x3434A953, 0x9A9A853E, + 0xB1B1428F, 0x7C7CD133, 0x88889B26, 0x3D3DA65F, 0xA1A1D7EC, 0xE4E4DF76, 0x8181942A, 0x91910149, + 0x0F0FFB81, 0xEEEEAA88, 0x161661EE, 0xD7D77321, 0x9797F5C4, 0xA5A5A81A, 0xFEFE3FEB, 0x6D6DB5D9, + 0x7878AEC5, 0xC5C56D39, 0x1D1DE599, 0x7676A4CD, 0x3E3EDCAD, 0xCBCB6731, 0xB6B6478B, 0xEFEF5B01, + 0x12121E18, 0x6060C523, 0x6A6AB0DD, 0x4D4DF61F, 0xCECEE94E, 0xDEDE7C2D, 0x55559DF9, 0x7E7E5A48, + 0x2121B24F, 0x03037AF2, 0xA0A02665, 0x5E5E198E, 0x5A5A6678, 0x65654B5C, 0x62624E58, 0xFDFD4519, + 0x0606F48D, 0x404086E5, 0xF2F2BE98, 0x3333AC57, 0x17179067, 0x05058E7F, 0xE8E85E05, 0x4F4F7D64, + 0x89896AAF, 0x10109563, 0x74742FB6, 0x0A0A75FE, 0x5C5C92F5, 0x9B9B74B7, 0x2D2D333C, 0x3030D6A5, + 0x2E2E49CE, 0x494989E9, 0x46467268, 0x77775544, 0xA8A8D8E0, 0x9696044D, 0x2828BD43, 0xA9A92969, + 0xD9D97929, 0x8686912E, 0xD1D187AC, 0xF4F44A15, 0x8D8D1559, 0xD6D682A8, 0xB9B9BC0A, 0x42420D9E, + 0xF6F6C16E, 0x2F2FB847, 0xDDDD06DF, 0x23233934, 0xCCCC6235, 0xF1F1C46A, 0xC1C112CF, 0x8585EBDC, + 0x8F8F9E22, 0x7171A1C9, 0x9090F0C0, 0xAAAA539B, 0x0101F189, 0x8B8BE1D4, 0x4E4E8CED, 0x8E8E6FAB, + 0xABABA212, 0x6F6F3EA2, 0xE6E6540D, 0xDBDBF252, 0x92927BBB, 0xB7B7B602, 0x6969CA2F, 0x3939D9A9, + 0xD3D30CD7, 0xA7A72361, 0xA2A2AD1E, 0xC3C399B4, 0x6C6C4450, 0x07070504, 0x04047FF6, 0x272746C2, + 0xACACA716, 0xD0D07625, 0x50501386, 0xDCDCF756, 0x84841A55, 0xE1E15109, 0x7A7A25BE, 0x1313EF91 + ); + + /** + * M-Table + * + * @var Array + * @access private + */ + var $m1 = array ( + 0xA9D93939, 0x67901717, 0xB3719C9C, 0xE8D2A6A6, 0x04050707, 0xFD985252, 0xA3658080, 0x76DFE4E4, + 0x9A084545, 0x92024B4B, 0x80A0E0E0, 0x78665A5A, 0xE4DDAFAF, 0xDDB06A6A, 0xD1BF6363, 0x38362A2A, + 0x0D54E6E6, 0xC6432020, 0x3562CCCC, 0x98BEF2F2, 0x181E1212, 0xF724EBEB, 0xECD7A1A1, 0x6C774141, + 0x43BD2828, 0x7532BCBC, 0x37D47B7B, 0x269B8888, 0xFA700D0D, 0x13F94444, 0x94B1FBFB, 0x485A7E7E, + 0xF27A0303, 0xD0E48C8C, 0x8B47B6B6, 0x303C2424, 0x84A5E7E7, 0x54416B6B, 0xDF06DDDD, 0x23C56060, + 0x1945FDFD, 0x5BA33A3A, 0x3D68C2C2, 0x59158D8D, 0xF321ECEC, 0xAE316666, 0xA23E6F6F, 0x82165757, + 0x63951010, 0x015BEFEF, 0x834DB8B8, 0x2E918686, 0xD9B56D6D, 0x511F8383, 0x9B53AAAA, 0x7C635D5D, + 0xA63B6868, 0xEB3FFEFE, 0xA5D63030, 0xBE257A7A, 0x16A7ACAC, 0x0C0F0909, 0xE335F0F0, 0x6123A7A7, + 0xC0F09090, 0x8CAFE9E9, 0x3A809D9D, 0xF5925C5C, 0x73810C0C, 0x2C273131, 0x2576D0D0, 0x0BE75656, + 0xBB7B9292, 0x4EE9CECE, 0x89F10101, 0x6B9F1E1E, 0x53A93434, 0x6AC4F1F1, 0xB499C3C3, 0xF1975B5B, + 0xE1834747, 0xE66B1818, 0xBDC82222, 0x450E9898, 0xE26E1F1F, 0xF4C9B3B3, 0xB62F7474, 0x66CBF8F8, + 0xCCFF9999, 0x95EA1414, 0x03ED5858, 0x56F7DCDC, 0xD4E18B8B, 0x1C1B1515, 0x1EADA2A2, 0xD70CD3D3, + 0xFB2BE2E2, 0xC31DC8C8, 0x8E195E5E, 0xB5C22C2C, 0xE9894949, 0xCF12C1C1, 0xBF7E9595, 0xBA207D7D, + 0xEA641111, 0x77840B0B, 0x396DC5C5, 0xAF6A8989, 0x33D17C7C, 0xC9A17171, 0x62CEFFFF, 0x7137BBBB, + 0x81FB0F0F, 0x793DB5B5, 0x0951E1E1, 0xADDC3E3E, 0x242D3F3F, 0xCDA47676, 0xF99D5555, 0xD8EE8282, + 0xE5864040, 0xC5AE7878, 0xB9CD2525, 0x4D049696, 0x44557777, 0x080A0E0E, 0x86135050, 0xE730F7F7, + 0xA1D33737, 0x1D40FAFA, 0xAA346161, 0xED8C4E4E, 0x06B3B0B0, 0x706C5454, 0xB22A7373, 0xD2523B3B, + 0x410B9F9F, 0x7B8B0202, 0xA088D8D8, 0x114FF3F3, 0x3167CBCB, 0xC2462727, 0x27C06767, 0x90B4FCFC, + 0x20283838, 0xF67F0404, 0x60784848, 0xFF2EE5E5, 0x96074C4C, 0x5C4B6565, 0xB1C72B2B, 0xAB6F8E8E, + 0x9E0D4242, 0x9CBBF5F5, 0x52F2DBDB, 0x1BF34A4A, 0x5FA63D3D, 0x9359A4A4, 0x0ABCB9B9, 0xEF3AF9F9, + 0x91EF1313, 0x85FE0808, 0x49019191, 0xEE611616, 0x2D7CDEDE, 0x4FB22121, 0x8F42B1B1, 0x3BDB7272, + 0x47B82F2F, 0x8748BFBF, 0x6D2CAEAE, 0x46E3C0C0, 0xD6573C3C, 0x3E859A9A, 0x6929A9A9, 0x647D4F4F, + 0x2A948181, 0xCE492E2E, 0xCB17C6C6, 0x2FCA6969, 0xFCC3BDBD, 0x975CA3A3, 0x055EE8E8, 0x7AD0EDED, + 0xAC87D1D1, 0x7F8E0505, 0xD5BA6464, 0x1AA8A5A5, 0x4BB72626, 0x0EB9BEBE, 0xA7608787, 0x5AF8D5D5, + 0x28223636, 0x14111B1B, 0x3FDE7575, 0x2979D9D9, 0x88AAEEEE, 0x3C332D2D, 0x4C5F7979, 0x02B6B7B7, + 0xB896CACA, 0xDA583535, 0xB09CC4C4, 0x17FC4343, 0x551A8484, 0x1FF64D4D, 0x8A1C5959, 0x7D38B2B2, + 0x57AC3333, 0xC718CFCF, 0x8DF40606, 0x74695353, 0xB7749B9B, 0xC4F59797, 0x9F56ADAD, 0x72DAE3E3, + 0x7ED5EAEA, 0x154AF4F4, 0x229E8F8F, 0x12A2ABAB, 0x584E6262, 0x07E85F5F, 0x99E51D1D, 0x34392323, + 0x6EC1F6F6, 0x50446C6C, 0xDE5D3232, 0x68724646, 0x6526A0A0, 0xBC93CDCD, 0xDB03DADA, 0xF8C6BABA, + 0xC8FA9E9E, 0xA882D6D6, 0x2BCF6E6E, 0x40507070, 0xDCEB8585, 0xFE750A0A, 0x328A9393, 0xA48DDFDF, + 0xCA4C2929, 0x10141C1C, 0x2173D7D7, 0xF0CCB4B4, 0xD309D4D4, 0x5D108A8A, 0x0FE25151, 0x00000000, + 0x6F9A1919, 0x9DE01A1A, 0x368F9494, 0x42E6C7C7, 0x4AECC9C9, 0x5EFDD2D2, 0xC1AB7F7F, 0xE0D8A8A8 + ); + + /** + * M-Table + * + * @var Array + * @access private + */ + var $m2 = array ( + 0xBC75BC32, 0xECF3EC21, 0x20C62043, 0xB3F4B3C9, 0xDADBDA03, 0x027B028B, 0xE2FBE22B, 0x9EC89EFA, + 0xC94AC9EC, 0xD4D3D409, 0x18E6186B, 0x1E6B1E9F, 0x9845980E, 0xB27DB238, 0xA6E8A6D2, 0x264B26B7, + 0x3CD63C57, 0x9332938A, 0x82D882EE, 0x52FD5298, 0x7B377BD4, 0xBB71BB37, 0x5BF15B97, 0x47E14783, + 0x2430243C, 0x510F51E2, 0xBAF8BAC6, 0x4A1B4AF3, 0xBF87BF48, 0x0DFA0D70, 0xB006B0B3, 0x753F75DE, + 0xD25ED2FD, 0x7DBA7D20, 0x66AE6631, 0x3A5B3AA3, 0x598A591C, 0x00000000, 0xCDBCCD93, 0x1A9D1AE0, + 0xAE6DAE2C, 0x7FC17FAB, 0x2BB12BC7, 0xBE0EBEB9, 0xE080E0A0, 0x8A5D8A10, 0x3BD23B52, 0x64D564BA, + 0xD8A0D888, 0xE784E7A5, 0x5F075FE8, 0x1B141B11, 0x2CB52CC2, 0xFC90FCB4, 0x312C3127, 0x80A38065, + 0x73B2732A, 0x0C730C81, 0x794C795F, 0x6B546B41, 0x4B924B02, 0x53745369, 0x9436948F, 0x8351831F, + 0x2A382A36, 0xC4B0C49C, 0x22BD22C8, 0xD55AD5F8, 0xBDFCBDC3, 0x48604878, 0xFF62FFCE, 0x4C964C07, + 0x416C4177, 0xC742C7E6, 0xEBF7EB24, 0x1C101C14, 0x5D7C5D63, 0x36283622, 0x672767C0, 0xE98CE9AF, + 0x441344F9, 0x149514EA, 0xF59CF5BB, 0xCFC7CF18, 0x3F243F2D, 0xC046C0E3, 0x723B72DB, 0x5470546C, + 0x29CA294C, 0xF0E3F035, 0x088508FE, 0xC6CBC617, 0xF311F34F, 0x8CD08CE4, 0xA493A459, 0xCAB8CA96, + 0x68A6683B, 0xB883B84D, 0x38203828, 0xE5FFE52E, 0xAD9FAD56, 0x0B770B84, 0xC8C3C81D, 0x99CC99FF, + 0x580358ED, 0x196F199A, 0x0E080E0A, 0x95BF957E, 0x70407050, 0xF7E7F730, 0x6E2B6ECF, 0x1FE21F6E, + 0xB579B53D, 0x090C090F, 0x61AA6134, 0x57825716, 0x9F419F0B, 0x9D3A9D80, 0x11EA1164, 0x25B925CD, + 0xAFE4AFDD, 0x459A4508, 0xDFA4DF8D, 0xA397A35C, 0xEA7EEAD5, 0x35DA3558, 0xED7AEDD0, 0x431743FC, + 0xF866F8CB, 0xFB94FBB1, 0x37A137D3, 0xFA1DFA40, 0xC23DC268, 0xB4F0B4CC, 0x32DE325D, 0x9CB39C71, + 0x560B56E7, 0xE372E3DA, 0x87A78760, 0x151C151B, 0xF9EFF93A, 0x63D163BF, 0x345334A9, 0x9A3E9A85, + 0xB18FB142, 0x7C337CD1, 0x8826889B, 0x3D5F3DA6, 0xA1ECA1D7, 0xE476E4DF, 0x812A8194, 0x91499101, + 0x0F810FFB, 0xEE88EEAA, 0x16EE1661, 0xD721D773, 0x97C497F5, 0xA51AA5A8, 0xFEEBFE3F, 0x6DD96DB5, + 0x78C578AE, 0xC539C56D, 0x1D991DE5, 0x76CD76A4, 0x3EAD3EDC, 0xCB31CB67, 0xB68BB647, 0xEF01EF5B, + 0x1218121E, 0x602360C5, 0x6ADD6AB0, 0x4D1F4DF6, 0xCE4ECEE9, 0xDE2DDE7C, 0x55F9559D, 0x7E487E5A, + 0x214F21B2, 0x03F2037A, 0xA065A026, 0x5E8E5E19, 0x5A785A66, 0x655C654B, 0x6258624E, 0xFD19FD45, + 0x068D06F4, 0x40E54086, 0xF298F2BE, 0x335733AC, 0x17671790, 0x057F058E, 0xE805E85E, 0x4F644F7D, + 0x89AF896A, 0x10631095, 0x74B6742F, 0x0AFE0A75, 0x5CF55C92, 0x9BB79B74, 0x2D3C2D33, 0x30A530D6, + 0x2ECE2E49, 0x49E94989, 0x46684672, 0x77447755, 0xA8E0A8D8, 0x964D9604, 0x284328BD, 0xA969A929, + 0xD929D979, 0x862E8691, 0xD1ACD187, 0xF415F44A, 0x8D598D15, 0xD6A8D682, 0xB90AB9BC, 0x429E420D, + 0xF66EF6C1, 0x2F472FB8, 0xDDDFDD06, 0x23342339, 0xCC35CC62, 0xF16AF1C4, 0xC1CFC112, 0x85DC85EB, + 0x8F228F9E, 0x71C971A1, 0x90C090F0, 0xAA9BAA53, 0x018901F1, 0x8BD48BE1, 0x4EED4E8C, 0x8EAB8E6F, + 0xAB12ABA2, 0x6FA26F3E, 0xE60DE654, 0xDB52DBF2, 0x92BB927B, 0xB702B7B6, 0x692F69CA, 0x39A939D9, + 0xD3D7D30C, 0xA761A723, 0xA21EA2AD, 0xC3B4C399, 0x6C506C44, 0x07040705, 0x04F6047F, 0x27C22746, + 0xAC16ACA7, 0xD025D076, 0x50865013, 0xDC56DCF7, 0x8455841A, 0xE109E151, 0x7ABE7A25, 0x139113EF + ); + + /** + * M-Table + * + * @var Array + * @access private + */ + var $m3 = array ( + 0xD939A9D9, 0x90176790, 0x719CB371, 0xD2A6E8D2, 0x05070405, 0x9852FD98, 0x6580A365, 0xDFE476DF, + 0x08459A08, 0x024B9202, 0xA0E080A0, 0x665A7866, 0xDDAFE4DD, 0xB06ADDB0, 0xBF63D1BF, 0x362A3836, + 0x54E60D54, 0x4320C643, 0x62CC3562, 0xBEF298BE, 0x1E12181E, 0x24EBF724, 0xD7A1ECD7, 0x77416C77, + 0xBD2843BD, 0x32BC7532, 0xD47B37D4, 0x9B88269B, 0x700DFA70, 0xF94413F9, 0xB1FB94B1, 0x5A7E485A, + 0x7A03F27A, 0xE48CD0E4, 0x47B68B47, 0x3C24303C, 0xA5E784A5, 0x416B5441, 0x06DDDF06, 0xC56023C5, + 0x45FD1945, 0xA33A5BA3, 0x68C23D68, 0x158D5915, 0x21ECF321, 0x3166AE31, 0x3E6FA23E, 0x16578216, + 0x95106395, 0x5BEF015B, 0x4DB8834D, 0x91862E91, 0xB56DD9B5, 0x1F83511F, 0x53AA9B53, 0x635D7C63, + 0x3B68A63B, 0x3FFEEB3F, 0xD630A5D6, 0x257ABE25, 0xA7AC16A7, 0x0F090C0F, 0x35F0E335, 0x23A76123, + 0xF090C0F0, 0xAFE98CAF, 0x809D3A80, 0x925CF592, 0x810C7381, 0x27312C27, 0x76D02576, 0xE7560BE7, + 0x7B92BB7B, 0xE9CE4EE9, 0xF10189F1, 0x9F1E6B9F, 0xA93453A9, 0xC4F16AC4, 0x99C3B499, 0x975BF197, + 0x8347E183, 0x6B18E66B, 0xC822BDC8, 0x0E98450E, 0x6E1FE26E, 0xC9B3F4C9, 0x2F74B62F, 0xCBF866CB, + 0xFF99CCFF, 0xEA1495EA, 0xED5803ED, 0xF7DC56F7, 0xE18BD4E1, 0x1B151C1B, 0xADA21EAD, 0x0CD3D70C, + 0x2BE2FB2B, 0x1DC8C31D, 0x195E8E19, 0xC22CB5C2, 0x8949E989, 0x12C1CF12, 0x7E95BF7E, 0x207DBA20, + 0x6411EA64, 0x840B7784, 0x6DC5396D, 0x6A89AF6A, 0xD17C33D1, 0xA171C9A1, 0xCEFF62CE, 0x37BB7137, + 0xFB0F81FB, 0x3DB5793D, 0x51E10951, 0xDC3EADDC, 0x2D3F242D, 0xA476CDA4, 0x9D55F99D, 0xEE82D8EE, + 0x8640E586, 0xAE78C5AE, 0xCD25B9CD, 0x04964D04, 0x55774455, 0x0A0E080A, 0x13508613, 0x30F7E730, + 0xD337A1D3, 0x40FA1D40, 0x3461AA34, 0x8C4EED8C, 0xB3B006B3, 0x6C54706C, 0x2A73B22A, 0x523BD252, + 0x0B9F410B, 0x8B027B8B, 0x88D8A088, 0x4FF3114F, 0x67CB3167, 0x4627C246, 0xC06727C0, 0xB4FC90B4, + 0x28382028, 0x7F04F67F, 0x78486078, 0x2EE5FF2E, 0x074C9607, 0x4B655C4B, 0xC72BB1C7, 0x6F8EAB6F, + 0x0D429E0D, 0xBBF59CBB, 0xF2DB52F2, 0xF34A1BF3, 0xA63D5FA6, 0x59A49359, 0xBCB90ABC, 0x3AF9EF3A, + 0xEF1391EF, 0xFE0885FE, 0x01914901, 0x6116EE61, 0x7CDE2D7C, 0xB2214FB2, 0x42B18F42, 0xDB723BDB, + 0xB82F47B8, 0x48BF8748, 0x2CAE6D2C, 0xE3C046E3, 0x573CD657, 0x859A3E85, 0x29A96929, 0x7D4F647D, + 0x94812A94, 0x492ECE49, 0x17C6CB17, 0xCA692FCA, 0xC3BDFCC3, 0x5CA3975C, 0x5EE8055E, 0xD0ED7AD0, + 0x87D1AC87, 0x8E057F8E, 0xBA64D5BA, 0xA8A51AA8, 0xB7264BB7, 0xB9BE0EB9, 0x6087A760, 0xF8D55AF8, + 0x22362822, 0x111B1411, 0xDE753FDE, 0x79D92979, 0xAAEE88AA, 0x332D3C33, 0x5F794C5F, 0xB6B702B6, + 0x96CAB896, 0x5835DA58, 0x9CC4B09C, 0xFC4317FC, 0x1A84551A, 0xF64D1FF6, 0x1C598A1C, 0x38B27D38, + 0xAC3357AC, 0x18CFC718, 0xF4068DF4, 0x69537469, 0x749BB774, 0xF597C4F5, 0x56AD9F56, 0xDAE372DA, + 0xD5EA7ED5, 0x4AF4154A, 0x9E8F229E, 0xA2AB12A2, 0x4E62584E, 0xE85F07E8, 0xE51D99E5, 0x39233439, + 0xC1F66EC1, 0x446C5044, 0x5D32DE5D, 0x72466872, 0x26A06526, 0x93CDBC93, 0x03DADB03, 0xC6BAF8C6, + 0xFA9EC8FA, 0x82D6A882, 0xCF6E2BCF, 0x50704050, 0xEB85DCEB, 0x750AFE75, 0x8A93328A, 0x8DDFA48D, + 0x4C29CA4C, 0x141C1014, 0x73D72173, 0xCCB4F0CC, 0x09D4D309, 0x108A5D10, 0xE2510FE2, 0x00000000, + 0x9A196F9A, 0xE01A9DE0, 0x8F94368F, 0xE6C742E6, 0xECC94AEC, 0xFDD25EFD, 0xAB7FC1AB, 0xD8A8E0D8 + ); + + /** + * The Key Schedule Array + * + * @var Array + * @access private + */ + var $K = array(); + + /** + * The Key depended S-Table 0 + * + * @var Array + * @access private + */ + var $S0 = array(); + + /** + * The Key depended S-Table 1 + * + * @var Array + * @access private + */ + var $S1 = array(); + + /** + * The Key depended S-Table 2 + * + * @var Array + * @access private + */ + var $S2 = array(); + + /** + * The Key depended S-Table 3 + * + * @var Array + * @access private + */ + var $S3 = array(); + + /** + * Holds the last used key + * + * @var Array + * @access private + */ + var $kl; + + /** + * Default Constructor. + * + * Determines whether or not the mcrypt extension should be used. + * + * $mode could be: + * + * - CRYPT_TWOFISH_MODE_ECB + * + * - CRYPT_TWOFISH_MODE_CBC + * + * - CRYPT_TWOFISH_MODE_CTR + * + * - CRYPT_TWOFISH_MODE_CFB + * + * - CRYPT_TWOFISH_MODE_OFB + * + * If not explictly set, CRYPT_TWOFISH_MODE_CBC will be used. + * + * @see Crypt_Base::Crypt_Base() + * @param optional Integer $mode + * @access public + */ + function Crypt_Twofish($mode = CRYPT_TWOFISH_MODE_CBC) + { + parent::Crypt_Base($mode); + } + + /** + * Sets the key. + * + * Keys can be of any length. Twofish, itself, requires the use of a key that's 128, 192 or 256-bits long. + * If the key is less than 256-bits we round the length up to the closest valid key length, + * padding $key with null bytes. If the key is more than 256-bits, we trim the excess bits. + * + * If the key is not explicitly set, it'll be assumed a 128 bits key to be all null bytes. + * + * @access public + * @see Crypt_Base::setKey() + * @param String $key + */ + function setKey($key) + { + $keylength = strlen($key); + switch (true) { + case $keylength <= 16: + $key = str_pad($key, 16, "\0"); + break; + case $keylength <= 24: + $key = str_pad($key, 24, "\0"); + break; + case $keylength < 32: + $key = str_pad($key, 32, "\0"); + break; + case $keylength > 32: + $key = substr($key, 0, 32); + } + parent::setKey($key); + } + + /** + * Setup the key (expansion) + * + * @see Crypt_Base::_setupKey() + * @access private + */ + function _setupKey() + { + if (isset($this->kl['key']) && $this->key === $this->kl['key']) { + // already expanded + return; + } + $this->kl = array('key' => $this->key); + + /* Key expanding and generating the key-depended s-boxes */ + $le_longs = unpack('V*', $this->key); + $key = unpack('C*', $this->key); + $m0 = $this->m0; + $m1 = $this->m1; + $m2 = $this->m2; + $m3 = $this->m3; + $q0 = $this->q0; + $q1 = $this->q1; + + $K = $S0 = $S1 = $S2 = $S3 = array(); + + switch (strlen($this->key)) { + case 16: + list ($s7, $s6, $s5, $s4) = $this->_mdsrem($le_longs[1], $le_longs[2]); + list ($s3, $s2, $s1, $s0) = $this->_mdsrem($le_longs[3], $le_longs[4]); + for ($i = 0, $j = 1; $i < 40; $i+= 2,$j+= 2) { + $A = $m0[$q0[$q0[$i] ^ $key[ 9]] ^ $key[1]] ^ + $m1[$q0[$q1[$i] ^ $key[10]] ^ $key[2]] ^ + $m2[$q1[$q0[$i] ^ $key[11]] ^ $key[3]] ^ + $m3[$q1[$q1[$i] ^ $key[12]] ^ $key[4]]; + $B = $m0[$q0[$q0[$j] ^ $key[13]] ^ $key[5]] ^ + $m1[$q0[$q1[$j] ^ $key[14]] ^ $key[6]] ^ + $m2[$q1[$q0[$j] ^ $key[15]] ^ $key[7]] ^ + $m3[$q1[$q1[$j] ^ $key[16]] ^ $key[8]]; + $B = ($B << 8) | ($B >> 24 & 0xff); + $K[] = $A+= $B; + $K[] = (($A+= $B) << 9 | $A >> 23 & 0x1ff); + } + for ($i = 0; $i < 256; ++$i) { + $S0[$i] = $m0[$q0[$q0[$i] ^ $s4] ^ $s0]; + $S1[$i] = $m1[$q0[$q1[$i] ^ $s5] ^ $s1]; + $S2[$i] = $m2[$q1[$q0[$i] ^ $s6] ^ $s2]; + $S3[$i] = $m3[$q1[$q1[$i] ^ $s7] ^ $s3]; + } + break; + case 24: + list ($sb, $sa, $s9, $s8) = $this->_mdsrem($le_longs[1], $le_longs[2]); + list ($s7, $s6, $s5, $s4) = $this->_mdsrem($le_longs[3], $le_longs[4]); + list ($s3, $s2, $s1, $s0) = $this->_mdsrem($le_longs[5], $le_longs[6]); + for ($i = 0, $j = 1; $i < 40; $i+= 2, $j+= 2) { + $A = $m0[$q0[$q0[$q1[$i] ^ $key[17]] ^ $key[ 9]] ^ $key[1]] ^ + $m1[$q0[$q1[$q1[$i] ^ $key[18]] ^ $key[10]] ^ $key[2]] ^ + $m2[$q1[$q0[$q0[$i] ^ $key[19]] ^ $key[11]] ^ $key[3]] ^ + $m3[$q1[$q1[$q0[$i] ^ $key[20]] ^ $key[12]] ^ $key[4]]; + $B = $m0[$q0[$q0[$q1[$j] ^ $key[21]] ^ $key[13]] ^ $key[5]] ^ + $m1[$q0[$q1[$q1[$j] ^ $key[22]] ^ $key[14]] ^ $key[6]] ^ + $m2[$q1[$q0[$q0[$j] ^ $key[23]] ^ $key[15]] ^ $key[7]] ^ + $m3[$q1[$q1[$q0[$j] ^ $key[24]] ^ $key[16]] ^ $key[8]]; + $B = ($B << 8) | ($B >> 24 & 0xff); + $K[] = $A+= $B; + $K[] = (($A+= $B) << 9 | $A >> 23 & 0x1ff); + } + for ($i = 0; $i < 256; ++$i) { + $S0[$i] = $m0[$q0[$q0[$q1[$i] ^ $s8] ^ $s4] ^ $s0]; + $S1[$i] = $m1[$q0[$q1[$q1[$i] ^ $s9] ^ $s5] ^ $s1]; + $S2[$i] = $m2[$q1[$q0[$q0[$i] ^ $sa] ^ $s6] ^ $s2]; + $S3[$i] = $m3[$q1[$q1[$q0[$i] ^ $sb] ^ $s7] ^ $s3]; + } + break; + default: // 32 + list ($sf, $se, $sd, $sc) = $this->_mdsrem($le_longs[1], $le_longs[2]); + list ($sb, $sa, $s9, $s8) = $this->_mdsrem($le_longs[3], $le_longs[4]); + list ($s7, $s6, $s5, $s4) = $this->_mdsrem($le_longs[5], $le_longs[6]); + list ($s3, $s2, $s1, $s0) = $this->_mdsrem($le_longs[7], $le_longs[8]); + for ($i = 0, $j = 1; $i < 40; $i+= 2, $j+= 2) { + $A = $m0[$q0[$q0[$q1[$q1[$i] ^ $key[25]] ^ $key[17]] ^ $key[ 9]] ^ $key[1]] ^ + $m1[$q0[$q1[$q1[$q0[$i] ^ $key[26]] ^ $key[18]] ^ $key[10]] ^ $key[2]] ^ + $m2[$q1[$q0[$q0[$q0[$i] ^ $key[27]] ^ $key[19]] ^ $key[11]] ^ $key[3]] ^ + $m3[$q1[$q1[$q0[$q1[$i] ^ $key[28]] ^ $key[20]] ^ $key[12]] ^ $key[4]]; + $B = $m0[$q0[$q0[$q1[$q1[$j] ^ $key[29]] ^ $key[21]] ^ $key[13]] ^ $key[5]] ^ + $m1[$q0[$q1[$q1[$q0[$j] ^ $key[30]] ^ $key[22]] ^ $key[14]] ^ $key[6]] ^ + $m2[$q1[$q0[$q0[$q0[$j] ^ $key[31]] ^ $key[23]] ^ $key[15]] ^ $key[7]] ^ + $m3[$q1[$q1[$q0[$q1[$j] ^ $key[32]] ^ $key[24]] ^ $key[16]] ^ $key[8]]; + $B = ($B << 8) | ($B >> 24 & 0xff); + $K[] = $A+= $B; + $K[] = (($A+= $B) << 9 | $A >> 23 & 0x1ff); + } + for ($i = 0; $i < 256; ++$i) { + $S0[$i] = $m0[$q0[$q0[$q1[$q1[$i] ^ $sc] ^ $s8] ^ $s4] ^ $s0]; + $S1[$i] = $m1[$q0[$q1[$q1[$q0[$i] ^ $sd] ^ $s9] ^ $s5] ^ $s1]; + $S2[$i] = $m2[$q1[$q0[$q0[$q0[$i] ^ $se] ^ $sa] ^ $s6] ^ $s2]; + $S3[$i] = $m3[$q1[$q1[$q0[$q1[$i] ^ $sf] ^ $sb] ^ $s7] ^ $s3]; + } + } + + $this->K = $K; + $this->S0 = $S0; + $this->S1 = $S1; + $this->S2 = $S2; + $this->S3 = $S3; + } + + /** + * _mdsrem function using by the twofish cipher algorithm + * + * @access private + * @param String $A + * @param String $B + * @return Array + */ + function _mdsrem($A, $B) + { + // No gain by unrolling this loop. + for ($i = 0; $i < 8; ++$i) { + // Get most significant coefficient. + $t = 0xff & ($B >> 24); + + // Shift the others up. + $B = ($B << 8) | (0xff & ($A >> 24)); + $A<<= 8; + + $u = $t << 1; + + // Subtract the modular polynomial on overflow. + if ($t & 0x80) { + $u^= 0x14d; + } + + // Remove t * (a * x^2 + 1). + $B ^= $t ^ ($u << 16); + + // Form u = a*t + t/a = t*(a + 1/a). + $u^= 0x7fffffff & ($t >> 1); + + // Add the modular polynomial on underflow. + if ($t & 0x01) $u^= 0xa6 ; + + // Remove t * (a + 1/a) * (x^3 + x). + $B^= ($u << 24) | ($u << 8); + } + + return array( + 0xff & $B >> 24, + 0xff & $B >> 16, + 0xff & $B >> 8, + 0xff & $B); + } + + /** + * Encrypts a block + * + * @access private + * @param String $in + * @return String + */ + function _encryptBlock($in) + { + $S0 = $this->S0; + $S1 = $this->S1; + $S2 = $this->S2; + $S3 = $this->S3; + $K = $this->K; + + $in = unpack("V4", $in); + $R0 = $K[0] ^ $in[1]; + $R1 = $K[1] ^ $in[2]; + $R2 = $K[2] ^ $in[3]; + $R3 = $K[3] ^ $in[4]; + + $ki = 7; + while ($ki < 39) { + $t0 = $S0[ $R0 & 0xff] ^ + $S1[($R0 >> 8) & 0xff] ^ + $S2[($R0 >> 16) & 0xff] ^ + $S3[($R0 >> 24) & 0xff]; + $t1 = $S0[($R1 >> 24) & 0xff] ^ + $S1[ $R1 & 0xff] ^ + $S2[($R1 >> 8) & 0xff] ^ + $S3[($R1 >> 16) & 0xff]; + $R2^= $t0 + $t1 + $K[++$ki]; + $R2 = ($R2 >> 1 & 0x7fffffff) | ($R2 << 31); + $R3 = ((($R3 >> 31) & 1) | ($R3 << 1)) ^ ($t0 + ($t1 << 1) + $K[++$ki]); + + $t0 = $S0[ $R2 & 0xff] ^ + $S1[($R2 >> 8) & 0xff] ^ + $S2[($R2 >> 16) & 0xff] ^ + $S3[($R2 >> 24) & 0xff]; + $t1 = $S0[($R3 >> 24) & 0xff] ^ + $S1[ $R3 & 0xff] ^ + $S2[($R3 >> 8) & 0xff] ^ + $S3[($R3 >> 16) & 0xff]; + $R0^= ($t0 + $t1 + $K[++$ki]); + $R0 = ($R0 >> 1 & 0x7fffffff) | ($R0 << 31); + $R1 = ((($R1 >> 31) & 1) | ($R1 << 1)) ^ ($t0 + ($t1 << 1) + $K[++$ki]); + } + + return pack("V4", $K[4] ^ $R2, + $K[5] ^ $R3, + $K[6] ^ $R0, + $K[7] ^ $R1); + } + + /** + * Decrypts a block + * + * @access private + * @param String $in + * @return String + */ + function _decryptBlock($in) + { + $S0 = $this->S0; + $S1 = $this->S1; + $S2 = $this->S2; + $S3 = $this->S3; + $K = $this->K; + + $in = unpack("V4", $in); + $R0 = $K[4] ^ $in[1]; + $R1 = $K[5] ^ $in[2]; + $R2 = $K[6] ^ $in[3]; + $R3 = $K[7] ^ $in[4]; + + $ki = 40; + while ($ki > 8) { + $t0 = $S0[$R0 & 0xff] ^ + $S1[$R0 >> 8 & 0xff] ^ + $S2[$R0 >> 16 & 0xff] ^ + $S3[$R0 >> 24 & 0xff]; + $t1 = $S0[$R1 >> 24 & 0xff] ^ + $S1[$R1 & 0xff] ^ + $S2[$R1 >> 8 & 0xff] ^ + $S3[$R1 >> 16 & 0xff]; + $R3^= $t0 + ($t1 << 1) + $K[--$ki]; + $R3 = $R3 >> 1 & 0x7fffffff | $R3 << 31; + $R2 = ($R2 >> 31 & 0x1 | $R2 << 1) ^ ($t0 + $t1 + $K[--$ki]); + + $t0 = $S0[$R2 & 0xff] ^ + $S1[$R2 >> 8 & 0xff] ^ + $S2[$R2 >> 16 & 0xff] ^ + $S3[$R2 >> 24 & 0xff]; + $t1 = $S0[$R3 >> 24 & 0xff] ^ + $S1[$R3 & 0xff] ^ + $S2[$R3 >> 8 & 0xff] ^ + $S3[$R3 >> 16 & 0xff]; + $R1^= $t0 + ($t1 << 1) + $K[--$ki]; + $R1 = $R1 >> 1 & 0x7fffffff | $R1 << 31; + $R0 = ($R0 >> 31 & 0x1 | $R0 << 1) ^ ($t0 + $t1 + $K[--$ki]); + } + + return pack("V4", $K[0] ^ $R2, + $K[1] ^ $R3, + $K[2] ^ $R0, + $K[3] ^ $R1); + } + + /** + * Setup the performance-optimized function for de/encrypt() + * + * @see Crypt_Base::_setupInlineCrypt() + * @access private + */ + function _setupInlineCrypt() + { + $lambda_functions =& Crypt_Twofish::_getLambdaFunctions(); + + // Max. 10 Ultra-Hi-optimized inline-crypt functions. After that, we'll (still) create very fast code, but not the ultimate fast one. + $gen_hi_opt_code = (bool)( count($lambda_functions) < 10 ); + + switch (true) { + case $gen_hi_opt_code: + $code_hash = md5(str_pad("Crypt_Twofish, {$this->mode}, ", 32, "\0") . $this->key); + break; + default: + $code_hash = "Crypt_Twofish, {$this->mode}"; + } + + if (!isset($lambda_functions[$code_hash])) { + switch (true) { + case $gen_hi_opt_code: + $K = $this->K; + + $init_crypt = ' + static $S0, $S1, $S2, $S3; + if (!$S0) { + for ($i = 0; $i < 256; ++$i) { + $S0[] = (int)$self->S0[$i]; + $S1[] = (int)$self->S1[$i]; + $S2[] = (int)$self->S2[$i]; + $S3[] = (int)$self->S3[$i]; + } + } + '; + break; + default: + $K = array(); + for ($i = 0; $i < 40; ++$i) { + $K[] = '$K_' . $i; + } + + $init_crypt = ' + $S0 = $self->S0; + $S1 = $self->S1; + $S2 = $self->S2; + $S3 = $self->S3; + list(' . implode(',', $K) . ') = $self->K; + '; + } + + // Generating encrypt code: + $encrypt_block = ' + $in = unpack("V4", $in); + $R0 = '.$K[0].' ^ $in[1]; + $R1 = '.$K[1].' ^ $in[2]; + $R2 = '.$K[2].' ^ $in[3]; + $R3 = '.$K[3].' ^ $in[4]; + '; + for ($ki = 7, $i = 0; $i < 8; ++$i) { + $encrypt_block.= ' + $t0 = $S0[ $R0 & 0xff] ^ + $S1[($R0 >> 8) & 0xff] ^ + $S2[($R0 >> 16) & 0xff] ^ + $S3[($R0 >> 24) & 0xff]; + $t1 = $S0[($R1 >> 24) & 0xff] ^ + $S1[ $R1 & 0xff] ^ + $S2[($R1 >> 8) & 0xff] ^ + $S3[($R1 >> 16) & 0xff]; + $R2^= ($t0 + $t1 + '.$K[++$ki].'); + $R2 = ($R2 >> 1 & 0x7fffffff) | ($R2 << 31); + $R3 = ((($R3 >> 31) & 1) | ($R3 << 1)) ^ ($t0 + ($t1 << 1) + '.$K[++$ki].'); + + $t0 = $S0[ $R2 & 0xff] ^ + $S1[($R2 >> 8) & 0xff] ^ + $S2[($R2 >> 16) & 0xff] ^ + $S3[($R2 >> 24) & 0xff]; + $t1 = $S0[($R3 >> 24) & 0xff] ^ + $S1[ $R3 & 0xff] ^ + $S2[($R3 >> 8) & 0xff] ^ + $S3[($R3 >> 16) & 0xff]; + $R0^= ($t0 + $t1 + '.$K[++$ki].'); + $R0 = ($R0 >> 1 & 0x7fffffff) | ($R0 << 31); + $R1 = ((($R1 >> 31) & 1) | ($R1 << 1)) ^ ($t0 + ($t1 << 1) + '.$K[++$ki].'); + '; + } + $encrypt_block.= ' + $in = pack("V4", '.$K[4].' ^ $R2, + '.$K[5].' ^ $R3, + '.$K[6].' ^ $R0, + '.$K[7].' ^ $R1); + '; + + // Generating decrypt code: + $decrypt_block = ' + $in = unpack("V4", $in); + $R0 = '.$K[4].' ^ $in[1]; + $R1 = '.$K[5].' ^ $in[2]; + $R2 = '.$K[6].' ^ $in[3]; + $R3 = '.$K[7].' ^ $in[4]; + '; + for ($ki = 40, $i = 0; $i < 8; ++$i) { + $decrypt_block.= ' + $t0 = $S0[$R0 & 0xff] ^ + $S1[$R0 >> 8 & 0xff] ^ + $S2[$R0 >> 16 & 0xff] ^ + $S3[$R0 >> 24 & 0xff]; + $t1 = $S0[$R1 >> 24 & 0xff] ^ + $S1[$R1 & 0xff] ^ + $S2[$R1 >> 8 & 0xff] ^ + $S3[$R1 >> 16 & 0xff]; + $R3^= $t0 + ($t1 << 1) + '.$K[--$ki].'; + $R3 = $R3 >> 1 & 0x7fffffff | $R3 << 31; + $R2 = ($R2 >> 31 & 0x1 | $R2 << 1) ^ ($t0 + $t1 + '.$K[--$ki].'); + + $t0 = $S0[$R2 & 0xff] ^ + $S1[$R2 >> 8 & 0xff] ^ + $S2[$R2 >> 16 & 0xff] ^ + $S3[$R2 >> 24 & 0xff]; + $t1 = $S0[$R3 >> 24 & 0xff] ^ + $S1[$R3 & 0xff] ^ + $S2[$R3 >> 8 & 0xff] ^ + $S3[$R3 >> 16 & 0xff]; + $R1^= $t0 + ($t1 << 1) + '.$K[--$ki].'; + $R1 = $R1 >> 1 & 0x7fffffff | $R1 << 31; + $R0 = ($R0 >> 31 & 0x1 | $R0 << 1) ^ ($t0 + $t1 + '.$K[--$ki].'); + '; + } + $decrypt_block.= ' + $in = pack("V4", '.$K[0].' ^ $R2, + '.$K[1].' ^ $R3, + '.$K[2].' ^ $R0, + '.$K[3].' ^ $R1); + '; + + $lambda_functions[$code_hash] = $this->_createInlineCryptFunction( + array( + 'init_crypt' => $init_crypt, + 'init_encrypt' => '', + 'init_decrypt' => '', + 'encrypt_block' => $encrypt_block, + 'decrypt_block' => $decrypt_block + ) + ); + } + $this->inline_crypt = $lambda_functions[$code_hash]; + } +} + +// vim: ts=4:sw=4:et: +// vim6: fdl=1: diff --git a/apps/files_external/3rdparty/phpseclib/phpseclib/File/ANSI.php b/apps/files_external/3rdparty/phpseclib/phpseclib/File/ANSI.php index 29ad949e10..f7ac85536f 100644 --- a/apps/files_external/3rdparty/phpseclib/phpseclib/File/ANSI.php +++ b/apps/files_external/3rdparty/phpseclib/phpseclib/File/ANSI.php @@ -34,8 +34,7 @@ * @author Jim Wigginton * @copyright MMXII Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @version $Id$ - * @link htp://phpseclib.sourceforge.net + * @link http://phpseclib.sourceforge.net */ /** @@ -298,12 +297,12 @@ class File_ANSI { } // http://ascii-table.com/ansi-escape-sequences-vt-100.php switch ($this->ansi) { - case "\x1B[H": + case "\x1B[H": // Move cursor to upper left corner $this->old_x = $this->x; $this->old_y = $this->y; $this->x = $this->y = 0; break; - case "\x1B[J": + case "\x1B[J": // Clear screen from cursor down $this->history = array_merge($this->history, array_slice(array_splice($this->screen, $this->y + 1), 0, $this->old_y)); $this->screen = array_merge($this->screen, array_fill($this->y, $this->max_y, '')); @@ -314,36 +313,45 @@ class File_ANSI { array_shift($this->history); array_shift($this->history_attrs); } - case "\x1B[K": + case "\x1B[K": // Clear screen from cursor right $this->screen[$this->y] = substr($this->screen[$this->y], 0, $this->x); array_splice($this->attrs[$this->y], $this->x + 1); break; + case "\x1B[2K": // Clear entire line + $this->screen[$this->y] = str_repeat(' ', $this->x); + $this->attrs[$this->y] = $this->attr_row; + break; case "\x1B[?1h": // set cursor key to application + case "\x1B[?25h": // show the cursor + break; + case "\x1BE": // Move to next line + $this->_newLine(); + $this->x = 0; break; default: switch (true) { - case preg_match('#\x1B\[(\d+);(\d+)H#', $this->ansi, $match): + case preg_match('#\x1B\[(\d+);(\d+)H#', $this->ansi, $match): // Move cursor to screen location v,h $this->old_x = $this->x; $this->old_y = $this->y; $this->x = $match[2] - 1; $this->y = $match[1] - 1; break; - case preg_match('#\x1B\[(\d+)C#', $this->ansi, $match): + case preg_match('#\x1B\[(\d+)C#', $this->ansi, $match): // Move cursor right n lines $this->old_x = $this->x; $x = $match[1] - 1; break; case preg_match('#\x1B\[(\d+);(\d+)r#', $this->ansi, $match): // Set top and bottom lines of a window break; - case preg_match('#\x1B\[(\d*(?:;\d*)*)m#', $this->ansi, $match): + case preg_match('#\x1B\[(\d*(?:;\d*)*)m#', $this->ansi, $match): // character attributes $mods = explode(';', $match[1]); foreach ($mods as $mod) { switch ($mod) { - case 0: + case 0: // Turn off character attributes $this->attrs[$this->y][$this->x] = ''; if ($this->bold) $this->attrs[$this->y][$this->x].= ''; - if ($this->underline) $this->attrs[$this->y][$this->x].= ''; + if ($this->underline) $this->attrs[$this->y][$this->x].= ''; if ($this->blink) $this->attrs[$this->y][$this->x].= ''; if ($this->color) $this->attrs[$this->y][$this->x].= ''; @@ -355,25 +363,25 @@ class File_ANSI { $this->bold = $this->underline = $this->blink = $this->color = $this->reverse = false; break; - case 1: + case 1: // Turn bold mode on if (!$this->bold) { $this->attrs[$this->y][$this->x] = ''; $this->bold = true; } break; - case 4: + case 4: // Turn underline mode on if (!$this->underline) { $this->attrs[$this->y][$this->x] = ''; $this->underline = true; } break; - case 5: + case 5: // Turn blinking mode on if (!$this->blink) { $this->attrs[$this->y][$this->x] = ''; $this->blink = true; } break; - case 7: + case 7: // Turn reverse video on $this->reverse = !$this->reverse; $temp = $this->background; $this->background = $this->foreground; @@ -384,7 +392,7 @@ class File_ANSI { } $this->color = true; break; - default: + default: // set colors //$front = $this->reverse ? &$this->background : &$this->foreground; $front = &$this->{ $this->reverse ? 'background' : 'foreground' }; //$back = $this->reverse ? &$this->foreground : &$this->background; @@ -424,7 +432,7 @@ class File_ANSI { } break; default: - echo "{$this->ansi} unsupported\r\n"; + user_error("{$this->ansi} unsupported\r\n"); } } $this->ansi = ''; @@ -436,25 +444,7 @@ class File_ANSI { $this->x = 0; break; case "\n": - //if ($this->y < $this->max_y) { - // $this->y++; - //} - - while ($this->y >= $this->max_y) { - $this->history = array_merge($this->history, array(array_shift($this->screen))); - $this->screen[] = ''; - - $this->history_attrs = array_merge($this->history_attrs, array(array_shift($this->attrs))); - $this->attrs[] = $this->attr_row; - - if (count($this->history) >= $this->max_history) { - array_shift($this->history); - array_shift($this->history_attrs); - } - - $this->y--; - } - $this->y++; + $this->_newLine(); break; case "\x0F": // shift break; @@ -479,6 +469,36 @@ class File_ANSI { } } + /** + * Add a new line + * + * Also update the $this->screen and $this->history buffers + * + * @access private + */ + function _newLine() + { + //if ($this->y < $this->max_y) { + // $this->y++; + //} + + while ($this->y >= $this->max_y) { + $this->history = array_merge($this->history, array(array_shift($this->screen))); + $this->screen[] = ''; + + $this->history_attrs = array_merge($this->history_attrs, array(array_shift($this->attrs))); + $this->attrs[] = $this->attr_row; + + if (count($this->history) >= $this->max_history) { + array_shift($this->history); + array_shift($this->history_attrs); + } + + $this->y--; + } + $this->y++; + } + /** * Returns the current screen without preformating * @@ -537,4 +557,4 @@ class File_ANSI { return '
    ' . $scrollback . '
    '; } -} +} \ No newline at end of file diff --git a/apps/files_external/3rdparty/phpseclib/phpseclib/File/ASN1.php b/apps/files_external/3rdparty/phpseclib/phpseclib/File/ASN1.php index 766c6e7ebf..9f481fc3cc 100644 --- a/apps/files_external/3rdparty/phpseclib/phpseclib/File/ASN1.php +++ b/apps/files_external/3rdparty/phpseclib/phpseclib/File/ASN1.php @@ -37,17 +37,9 @@ * @author Jim Wigginton * @copyright MMXII Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @version $Id$ * @link http://phpseclib.sourceforge.net */ -/** - * Include Math_BigInteger - */ -if (!class_exists('Math_BigInteger')) { - require_once('Math/BigInteger.php'); -} - /**#@+ * Tag Classes * @@ -249,6 +241,22 @@ class File_ASN1 { FILE_ASN1_TYPE_VISIBLE_STRING => 1, ); + /** + * Default Constructor. + * + * @access public + */ + function File_ASN1() + { + static $static_init = null; + if (!$static_init) { + $static_init = true; + if (!class_exists('Math_BigInteger')) { + require_once('Math/BigInteger.php'); + } + } + } + /** * Parse BER-encoding * @@ -304,12 +312,12 @@ class File_ASN1 { } while ( $loop ); } - // Length, as discussed in § 8.1.3 of X.690-0207.pdf#page=13 + // Length, as discussed in paragraph 8.1.3 of X.690-0207.pdf#page=13 $length = ord($this->_string_shift($encoded)); $start++; if ( $length == 0x80 ) { // indefinite length // "[A sender shall] use the indefinite form (see 8.1.3.6) if the encoding is constructed and is not all - // immediately available." -- § 8.1.3.2.c + // immediately available." -- paragraph 8.1.3.2.c //if ( !$constructed ) { // return false; //} @@ -319,11 +327,15 @@ class File_ASN1 { // support it up to four. $length&= 0x7F; $temp = $this->_string_shift($encoded, $length); + // tags of indefinite length don't really have a header length; this length includes the tag + $current+= array('headerlength' => $length + 2); $start+= $length; extract(unpack('Nlength', substr(str_pad($temp, 4, chr(0), STR_PAD_LEFT), -4))); + } else { + $current+= array('headerlength' => 2); } - // End-of-content, see §§ 8.1.1.3, 8.1.3.2, 8.1.3.6, 8.1.5, and (for an example) 8.6.4.2 + // End-of-content, see paragraphs 8.1.1.3, 8.1.3.2, 8.1.3.6, 8.1.5, and (for an example) 8.6.4.2 if (!$type && !$length) { return $decoded; } @@ -349,6 +361,7 @@ class File_ASN1 { 'content' => $constructed ? $this->_decode_ber($content, $start) : $content, 'length' => $length + $start - $current['start'] ) + $current; + $start+= $length; continue 2; } @@ -357,7 +370,7 @@ class File_ASN1 { // decode UNIVERSAL tags switch ($tag) { case FILE_ASN1_TYPE_BOOLEAN: - // "The contents octets shall consist of a single octet." -- § 8.2.1 + // "The contents octets shall consist of a single octet." -- paragraph 8.2.1 //if (strlen($content) != 1) { // return false; //} @@ -410,7 +423,7 @@ class File_ASN1 { } break; case FILE_ASN1_TYPE_NULL: - // "The contents octets shall not contain any octets." -- § 8.8.2 + // "The contents octets shall not contain any octets." -- paragraph 8.8.2 //if (strlen($content)) { // return false; //} @@ -441,7 +454,7 @@ class File_ASN1 { /* Each character string type shall be encoded as if it had been declared: [UNIVERSAL x] IMPLICIT OCTET STRING - -- X.690-0207.pdf#page=23 (§ 8.21.3) + -- X.690-0207.pdf#page=23 (paragraph 8.21.3) Per that, we're not going to do any validation. If there are any illegal characters in the string, we don't really care */ @@ -487,12 +500,15 @@ class File_ASN1 { * * Provides an ASN.1 semantic mapping ($mapping) from a parsed BER-encoding to a human readable format. * + * "Special" mappings may be applied on a per tag-name basis via $special. + * * @param Array $decoded * @param Array $mapping + * @param Array $special * @return Array * @access public */ - function asn1map($decoded, $mapping) + function asn1map($decoded, $mapping, $special = array()) { if (isset($mapping['explicit'])) { $decoded = $decoded['content'][0]; @@ -506,7 +522,7 @@ class File_ASN1 { } $inmap = $this->ANYmap[$intype]; if (is_string($inmap)) { - return array($inmap => $this->asn1map($decoded, array('type' => $intype) + $mapping)); + return array($inmap => $this->asn1map($decoded, array('type' => $intype) + $mapping, $special)); } break; case $mapping['type'] == FILE_ASN1_TYPE_CHOICE: @@ -514,15 +530,18 @@ class File_ASN1 { switch (true) { case isset($option['constant']) && $option['constant'] == $decoded['constant']: case !isset($option['constant']) && $option['type'] == $decoded['type']: - $value = $this->asn1map($decoded, $option); + $value = $this->asn1map($decoded, $option, $special); break; case !isset($option['constant']) && $option['type'] == FILE_ASN1_TYPE_CHOICE: - $v = $this->asn1map($decoded, $option); + $v = $this->asn1map($decoded, $option, $special); if (isset($v)) { $value = $v; } } if (isset($value)) { + if (isset($special[$key])) { + $value = call_user_func($special[$key], $value); + } return array($key => $value); } } @@ -547,7 +566,7 @@ class File_ASN1 { if (isset($mapping['min']) && isset($mapping['max'])) { $child = $mapping['children']; foreach ($decoded['content'] as $content) { - if (($map[] = $this->asn1map($content, $child)) === NULL) { + if (($map[] = $this->asn1map($content, $child, $special)) === NULL) { return NULL; } } @@ -591,12 +610,15 @@ class File_ASN1 { if ($maymatch) { // Attempt submapping. - $candidate = $this->asn1map($temp, $child); + $candidate = $this->asn1map($temp, $child, $special); $maymatch = $candidate !== NULL; } if ($maymatch) { // Got the match: use it. + if (isset($special[$key])) { + $candidate = call_user_func($special[$key], $candidate); + } $map[$key] = $candidate; $i++; } elseif (isset($child['default'])) { @@ -617,7 +639,7 @@ class File_ASN1 { if (isset($mapping['min']) && isset($mapping['max'])) { $child = $mapping['children']; foreach ($decoded['content'] as $content) { - if (($map[] = $this->asn1map($content, $child)) === NULL) { + if (($map[] = $this->asn1map($content, $child, $special)) === NULL) { return NULL; } } @@ -660,7 +682,7 @@ class File_ASN1 { if ($maymatch) { // Attempt submapping. - $candidate = $this->asn1map($temp, $child); + $candidate = $this->asn1map($temp, $child, $special); $maymatch = $candidate !== NULL; } @@ -669,6 +691,9 @@ class File_ASN1 { } // Got the match: use it. + if (isset($special[$key])) { + $candidate = call_user_func($special[$key], $candidate); + } $map[$key] = $candidate; break; } @@ -761,18 +786,30 @@ class File_ASN1 { * DER-encodes an ASN.1 semantic mapping ($mapping). Some libraries would probably call this function * an ASN.1 compiler. * + * "Special" mappings can be applied via $special. + * * @param String $source * @param String $mapping * @param Integer $idx * @return String * @access public */ - function encodeDER($source, $mapping) + function encodeDER($source, $mapping, $special = array()) { $this->location = array(); - return $this->_encode_der($source, $mapping); + return $this->_encode_der($source, $mapping, NULL, $special); } + /** + * ASN.1 Encode (Helper function) + * + * @param String $source + * @param Array $mapping + * @param Integer $idx + * @param Array $special + * @return String + * @access private + */ /** * ASN.1 Encode (Helper function) * @@ -782,7 +819,7 @@ class File_ASN1 { * @return String * @access private */ - function _encode_der($source, $mapping, $idx = NULL) + function _encode_der($source, $mapping, $idx = NULL, $special = array()) { if (is_object($source) && strtolower(get_class($source)) == 'file_asn1_element') { return $source->element; @@ -794,6 +831,9 @@ class File_ASN1 { } if (isset($idx)) { + if (isset($special[$idx])) { + $source = call_user_func($special[$idx], $source); + } $this->location[] = $idx; } @@ -810,7 +850,7 @@ class File_ASN1 { $child = $mapping['children']; foreach ($source as $content) { - $temp = $this->_encode_der($content, $child); + $temp = $this->_encode_der($content, $child, NULL, $special); if ($temp === false) { return false; } @@ -827,7 +867,7 @@ class File_ASN1 { continue; } - $temp = $this->_encode_der($source[$key], $child, $key); + $temp = $this->_encode_der($source[$key], $child, $key, $special); if ($temp === false) { return false; } @@ -868,7 +908,7 @@ class File_ASN1 { continue; } - $temp = $this->_encode_der($source[$key], $child, $key); + $temp = $this->_encode_der($source[$key], $child, $key, $special); if ($temp === false) { return false; } @@ -914,6 +954,9 @@ class File_ASN1 { $value = new Math_BigInteger($value); $value = $value->toBytes(true); } + if (!strlen($value)) { + $value = chr(0); + } break; case FILE_ASN1_TYPE_UTC_TIME: case FILE_ASN1_TYPE_GENERALIZED_TIME: @@ -987,19 +1030,19 @@ class File_ASN1 { switch (true) { case !isset($source): - return $this->_encode_der(NULL, array('type' => FILE_ASN1_TYPE_NULL) + $mapping); + return $this->_encode_der(NULL, array('type' => FILE_ASN1_TYPE_NULL) + $mapping, NULL, $special); case is_int($source): case is_object($source) && strtolower(get_class($source)) == 'math_biginteger': - return $this->_encode_der($source, array('type' => FILE_ASN1_TYPE_INTEGER) + $mapping); + return $this->_encode_der($source, array('type' => FILE_ASN1_TYPE_INTEGER) + $mapping, NULL, $special); case is_float($source): - return $this->_encode_der($source, array('type' => FILE_ASN1_TYPE_REAL) + $mapping); + return $this->_encode_der($source, array('type' => FILE_ASN1_TYPE_REAL) + $mapping, NULL, $special); case is_bool($source): - return $this->_encode_der($source, array('type' => FILE_ASN1_TYPE_BOOLEAN) + $mapping); + return $this->_encode_der($source, array('type' => FILE_ASN1_TYPE_BOOLEAN) + $mapping, NULL, $special); case is_array($source) && count($source) == 1: $typename = implode('', array_keys($source)); $outtype = array_search($typename, $this->ANYmap, true); if ($outtype !== false) { - return $this->_encode_der($source[$typename], array('type' => $outtype) + $mapping); + return $this->_encode_der($source[$typename], array('type' => $outtype) + $mapping, NULL, $special); } } @@ -1015,7 +1058,7 @@ class File_ASN1 { user_error('No filters defined for ' . implode('/', $loc)); return false; } - return $this->_encode_der($source, $filters + $mapping); + return $this->_encode_der($source, $filters + $mapping, NULL, $special); case FILE_ASN1_TYPE_NULL: $value = ''; break; @@ -1055,7 +1098,7 @@ class File_ASN1 { * DER-encode the length * * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See - * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 § 8.1.3} for more information. + * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information. * * @access private * @param Integer $length diff --git a/apps/files_external/3rdparty/phpseclib/phpseclib/File/X509.php b/apps/files_external/3rdparty/phpseclib/phpseclib/File/X509.php index 278da62e26..0b4e291361 100644 --- a/apps/files_external/3rdparty/phpseclib/phpseclib/File/X509.php +++ b/apps/files_external/3rdparty/phpseclib/phpseclib/File/X509.php @@ -40,22 +40,22 @@ * @author Jim Wigginton * @copyright MMXII Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @version $Id$ - * @link htp://phpseclib.sourceforge.net + * @link http://phpseclib.sourceforge.net */ /** * Include File_ASN1 */ if (!class_exists('File_ASN1')) { - require_once('File/ASN1.php'); + require_once('ASN1.php'); } /** * Flag to only accept signatures signed by certificate authorities * + * Not really used anymore but retained all the same to suppress E_NOTICEs from old installs + * * @access public - * @see File_X509::validateSignature() */ define('FILE_X509_VALIDATE_SIGNATURE_BY_CA', 1); @@ -306,6 +306,10 @@ class File_X509 { */ function File_X509() { + if (!class_exists('Math_BigInteger')) { + require_once('Math/BigInteger.php'); + } + // Explicitly Tagged Module, 1988 Syntax // http://tools.ietf.org/html/rfc5280#appendix-A.1 @@ -1436,18 +1440,7 @@ class File_X509 { $asn1 = new File_ASN1(); - /* - X.509 certs are assumed to be base64 encoded but sometimes they'll have additional things in them above and beyond the ceritificate. ie. - some may have the following preceeding the -----BEGIN CERTIFICATE----- line: - - subject=/O=organization/OU=org unit/CN=common name - issuer=/O=organization/CN=common name - */ - $temp = preg_replace('#^(?:[^-].+[\r\n]+)+|-.+-|[\r\n]| #', '', $cert); - $temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? base64_decode($temp) : false; - if ($temp != false) { - $cert = $temp; - } + $cert = $this->_extractBER($cert); if ($cert === false) { $this->currentCert = false; @@ -1569,7 +1562,7 @@ class File_X509 { corresponding to the extension type identified by extnID */ $map = $this->_getMapping($id); if (!is_bool($map)) { - $mapped = $asn1->asn1map($decoded[0], $map); + $mapped = $asn1->asn1map($decoded[0], $map, array('iPAddress' => array($this, '_decodeIP'))); $value = $mapped === false ? $decoded[0] : $mapped; if ($id == 'id-ce-certificatePolicies') { @@ -1651,7 +1644,7 @@ class File_X509 { unset($extensions[$i]); } } else { - $temp = $asn1->encodeDER($value, $map); + $temp = $asn1->encodeDER($value, $map, array('iPAddress' => array($this, '_encodeIP'))); $value = base64_encode($temp); } } @@ -2001,16 +1994,19 @@ class File_X509 { * Works on X.509 certs, CSR's and CRL's. * Returns true if the signature is verified, false if it is not correct or NULL on error * + * By default returns false for self-signed certs. Call validateSignature(false) to make this support + * self-signed. + * * The behavior of this function is inspired by {@link http://php.net/openssl-verify openssl_verify}. * - * @param Integer $options optional + * @param Boolean $caonly optional * @access public * @return Mixed */ - function validateSignature($options = 0) + function validateSignature($caonly = true) { if (!is_array($this->currentCert) || !isset($this->signatureSubject)) { - return 0; + return NULL; } /* TODO: @@ -2048,10 +2044,10 @@ class File_X509 { } } } - if (count($this->CAs) == $i && ($options & FILE_X509_VALIDATE_SIGNATURE_BY_CA)) { + if (count($this->CAs) == $i && $caonly) { return false; } - } elseif (!isset($signingCert) || ($options & FILE_X509_VALIDATE_SIGNATURE_BY_CA)) { + } elseif (!isset($signingCert) || $caonly) { return false; } return $this->_validateSignature( @@ -2182,6 +2178,36 @@ class File_X509 { } } + /** + * Decodes an IP address + * + * Takes in a base64 encoded "blob" and returns a human readable IP address + * + * @param String $ip + * @access private + * @return String + */ + function _decodeIP($ip) + { + $ip = base64_decode($ip); + list(, $ip) = unpack('N', $ip); + return long2ip($ip); + } + + /** + * Encodes an IP address + * + * Takes a human readable IP address into a base64-encoded "blob" + * + * @param String $ip + * @access private + * @return String + */ + function _encodeIP($ip) + { + return base64_encode(pack('N', ip2long($ip))); + } + /** * "Normalizes" a Distinguished Name property * @@ -2207,7 +2233,7 @@ class File_X509 { case 'commonname': case 'cn': return 'id-at-commonName'; - case 'id-at-stateorprovinceName': + case 'id-at-stateorprovincename': case 'stateorprovincename': case 'state': case 'province': @@ -2630,9 +2656,9 @@ class File_X509 { case !isset($this->currentCert) || !is_array($this->currentCert): break; case isset($this->currentCert['tbsCertificate']): - return $this->getDNProp($propname, $this->currentCert['tbsCertificate']['issuer'], $withType); + return $this->getDNProp($propName, $this->currentCert['tbsCertificate']['issuer'], $withType); case isset($this->currentCert['tbsCertList']): - return $this->getDNProp($propname, $this->currentCert['tbsCertList']['issuer'], $withType); + return $this->getDNProp($propName, $this->currentCert['tbsCertList']['issuer'], $withType); } return false; @@ -2656,7 +2682,7 @@ class File_X509 { case isset($this->currentCert['tbsCertificate']): return $this->getDNProp($propName, $this->currentCert['tbsCertificate']['subject'], $withType); case isset($this->currentCert['certificationRequestInfo']): - return $this->getDNProp($propname, $this->currentCert['certificationRequestInfo']['subject'], $withType); + return $this->getDNProp($propName, $this->currentCert['certificationRequestInfo']['subject'], $withType); } return false; @@ -2718,6 +2744,7 @@ class File_X509 { */ function setPublicKey($key) { + $key->setPublicKey(); $this->publicKey = $key; } @@ -2804,11 +2831,7 @@ class File_X509 { $asn1 = new File_ASN1(); - $temp = preg_replace('#^(?:[^-].+[\r\n]+)+|-.+-|[\r\n]| #', '', $csr); - $temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? base64_decode($temp) : false; - if ($temp != false) { - $csr = $temp; - } + $csr = $this->_extractBER($csr); $orig = $csr; if ($csr === false) { @@ -2917,51 +2940,51 @@ class File_X509 { * @access public * @return Mixed */ - function loadSPKAC($csr) + function loadSPKAC($spkac) { - if (is_array($csr) && isset($csr['publicKeyAndChallenge'])) { + if (is_array($spkac) && isset($spkac['publicKeyAndChallenge'])) { unset($this->currentCert); unset($this->currentKeyIdentifier); unset($this->signatureSubject); - $this->currentCert = $csr; - return $csr; + $this->currentCert = $spkac; + return $spkac; } // see http://www.w3.org/html/wg/drafts/html/master/forms.html#signedpublickeyandchallenge $asn1 = new File_ASN1(); - $temp = preg_replace('#(?:^[^=]+=)|[\r\n\\\]#', '', $csr); + $temp = preg_replace('#(?:^[^=]+=)|[\r\n\\\]#', '', $spkac); $temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? base64_decode($temp) : false; if ($temp != false) { - $csr = $temp; + $spkac = $temp; } - $orig = $csr; + $orig = $spkac; - if ($csr === false) { + if ($spkac === false) { $this->currentCert = false; return false; } $asn1->loadOIDs($this->oids); - $decoded = $asn1->decodeBER($csr); + $decoded = $asn1->decodeBER($spkac); if (empty($decoded)) { $this->currentCert = false; return false; } - $csr = $asn1->asn1map($decoded[0], $this->SignedPublicKeyAndChallenge); + $spkac = $asn1->asn1map($decoded[0], $this->SignedPublicKeyAndChallenge); - if (!isset($csr) || $csr === false) { + if (!isset($spkac) || $spkac === false) { $this->currentCert = false; return false; } $this->signatureSubject = substr($orig, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']); - $algorithm = &$csr['publicKeyAndChallenge']['spki']['algorithm']['algorithm']; - $key = &$csr['publicKeyAndChallenge']['spki']['subjectPublicKey']; + $algorithm = &$spkac['publicKeyAndChallenge']['spki']['algorithm']['algorithm']; + $key = &$spkac['publicKeyAndChallenge']['spki']['subjectPublicKey']; $key = $this->_reformatKey($algorithm, $key); switch ($algorithm) { @@ -2978,9 +3001,9 @@ class File_X509 { } $this->currentKeyIdentifier = NULL; - $this->currentCert = $csr; + $this->currentCert = $spkac; - return $csr; + return $spkac; } /** @@ -3000,11 +3023,7 @@ class File_X509 { $asn1 = new File_ASN1(); - $temp = preg_replace('#^(?:[^-].+[\r\n]+)+|-.+-|[\r\n]| #', '', $crl); - $temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? base64_decode($temp) : false; - if ($temp != false) { - $crl = $temp; - } + $crl = $this->_extractBER($crl); $orig = $crl; if ($crl === false) { @@ -3209,9 +3228,29 @@ class File_X509 { $this->setExtension('id-ce-subjectKeyIdentifier', $subject->currentKeyIdentifier); } + $altName = array(); + if (isset($subject->domains) && count($subject->domains) > 1) { - $this->setExtension('id-ce-subjectAltName', - array_map(array('File_X509', '_dnsName'), $subject->domains)); + $altName = array_map(array('File_X509', '_dnsName'), $subject->domains); + } + + if (isset($subject->ipAddresses) && count($subject->ipAddresses)) { + // should an IP address appear as the CN if no domain name is specified? idk + //$ips = count($subject->domains) ? $subject->ipAddresses : array_slice($subject->ipAddresses, 1); + $ipAddresses = array(); + foreach ($subject->ipAddresses as $ipAddress) { + $encoded = $subject->_ipAddress($ipAddress); + if ($encoded !== false) { + $ipAddresses[] = $encoded; + } + } + if (count($ipAddresses)) { + $altName = array_merge($altName, $ipAddresses); + } + } + + if (!empty($altName)) { + $this->setExtension('id-ce-subjectAltName', $altName); } if ($this->caFlag) { @@ -4012,12 +4051,29 @@ class File_X509 { case !is_object($key): return false; case strtolower(get_class($key)) == 'file_asn1_element': + // Assume the element is a bitstring-packed key. $asn1 = new File_ASN1(); - $decoded = $asn1->decodeBER($cert); + $decoded = $asn1->decodeBER($key->element); if (empty($decoded)) { return false; } - $key = $asn1->asn1map($decoded[0], array('type' => FILE_ASN1_TYPE_BIT_STRING)); + $raw = $asn1->asn1map($decoded[0], array('type' => FILE_ASN1_TYPE_BIT_STRING)); + if (empty($raw)) { + return false; + } + $raw = base64_decode($raw); + // If the key is private, compute identifier from its corresponding public key. + if (!class_exists('Crypt_RSA')) { + require_once('Crypt/RSA.php'); + } + $key = new Crypt_RSA(); + if (!$key->loadKey($raw)) { + return false; // Not an unencrypted RSA key. + } + if ($key->getPrivateKey() !== false) { // If private. + return $this->computeKeyIdentifier($key, $method); + } + $key = $raw; // Is a public key. break; case strtolower(get_class($key)) == 'file_x509': if (isset($key->publicKey)) { @@ -4036,9 +4092,7 @@ class File_X509 { } // If in PEM format, convert to binary. - if (preg_match('#^-----BEGIN #', $key)) { - $key = base64_decode(preg_replace('#-.+-|[\r\n]#', '', $key)); - } + $key = $this->_extractBER($key); // Now we have the key string: compute its sha-1 sum. if (!class_exists('Crypt_Hash')) { @@ -4094,6 +4148,23 @@ class File_X509 { $this->setDNProp('id-at-commonName', $this->domains[0]); } + /** + * Set the IP Addresses's which the cert is to be valid for + * + * @access public + * @param String $ipAddress optional + */ + function setIPAddress() + { + $this->ipAddresses = func_get_args(); + /* + if (!isset($this->domains)) { + $this->removeDNProp('id-at-commonName'); + $this->setDNProp('id-at-commonName', $this->ipAddresses[0]); + } + */ + } + /** * Helper function to build domain array * @@ -4106,6 +4177,20 @@ class File_X509 { return array('dNSName' => $domain); } + /** + * Helper function to build IP Address array + * + * (IPv6 is not currently supported) + * + * @access private + * @param String $address + * @return Array + */ + function _iPAddress($address) + { + return array('iPAddress' => $address); + } + /** * Get the index of a revoked certificate. * @@ -4320,4 +4405,31 @@ class File_X509 { return false; } + + /** + * Extract raw BER from Base64 encoding + * + * @access private + * @param String $str + * @return String + */ + function _extractBER($str) + { + /* + X.509 certs are assumed to be base64 encoded but sometimes they'll have additional things in them above and beyond the ceritificate. ie. + some may have the following preceding the -----BEGIN CERTIFICATE----- line: + + Bag Attributes + localKeyID: 01 00 00 00 + subject=/O=organization/OU=org unit/CN=common name + issuer=/O=organization/CN=common name + */ + $temp = preg_replace('#.*?^-+[^-]+-+#ms', '', $str, 1); + // remove the -----BEGIN CERTIFICATE----- and -----END CERTIFICATE----- stuff + $temp = preg_replace('#-+[^-]+-+#', '', $temp); + // remove new lines + $temp = str_replace(array("\r", "\n", ' '), '', $temp); + $temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? base64_decode($temp) : false; + return $temp != false ? $temp : $str; + } } diff --git a/apps/files_external/3rdparty/phpseclib/phpseclib/Math/BigInteger.php b/apps/files_external/3rdparty/phpseclib/phpseclib/Math/BigInteger.php index d048cb032c..e40433de5b 100644 --- a/apps/files_external/3rdparty/phpseclib/phpseclib/Math/BigInteger.php +++ b/apps/files_external/3rdparty/phpseclib/phpseclib/Math/BigInteger.php @@ -70,7 +70,6 @@ * @author Jim Wigginton * @copyright MMVI Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @version $Id: BigInteger.php,v 1.33 2010/03/22 22:32:03 terrafrost Exp $ * @link http://pear.php.net/package/Math_BigInteger */ @@ -162,16 +161,6 @@ define('MATH_BIGINTEGER_MODE_BCMATH', 2); define('MATH_BIGINTEGER_MODE_GMP', 3); /**#@-*/ -/** - * The largest digit that may be used in addition / subtraction - * - * (we do pow(2, 52) instead of using 4503599627370496, directly, because some PHP installations - * will truncate 4503599627370496) - * - * @access private - */ -define('MATH_BIGINTEGER_MAX_DIGIT52', pow(2, 52)); - /** * Karatsuba Cutoff * @@ -232,7 +221,7 @@ class Math_BigInteger { var $bitmask = false; /** - * Mode independant value used for serialization. + * Mode independent value used for serialization. * * If the bcmath or gmp extensions are installed $this->value will be a non-serializable resource, hence the need for * a variable that'll be serializable regardless of whether or not extensions are being used. Unlike $this->value, @@ -246,20 +235,20 @@ class Math_BigInteger { var $hex; /** - * Converts base-2, base-10, base-16, and binary strings (eg. base-256) to BigIntegers. + * Converts base-2, base-10, base-16, and binary strings (base-256) to BigIntegers. * * If the second parameter - $base - is negative, then it will be assumed that the number's are encoded using * two's compliment. The sole exception to this is -10, which is treated the same as 10 is. * * Here's an example: * - * toString(); // outputs 50 - * ?> + * ?> * * * @param optional $x base-10 number or base-$base number if $base set. @@ -283,7 +272,64 @@ class Math_BigInteger { } if (function_exists('openssl_public_encrypt') && !defined('MATH_BIGINTEGER_OPENSSL_DISABLE') && !defined('MATH_BIGINTEGER_OPENSSL_ENABLED')) { - define('MATH_BIGINTEGER_OPENSSL_ENABLED', true); + // some versions of XAMPP have mismatched versions of OpenSSL which causes it not to work + ob_start(); + phpinfo(); + $content = ob_get_contents(); + ob_end_clean(); + + preg_match_all('#OpenSSL (Header|Library) Version(.*)#im', $content, $matches); + + $versions = array(); + if (!empty($matches[1])) { + for ($i = 0; $i < count($matches[1]); $i++) { + $versions[$matches[1][$i]] = trim(str_replace('=>', '', strip_tags($matches[2][$i]))); + } + } + + // it doesn't appear that OpenSSL versions were reported upon until PHP 5.3+ + switch (true) { + case !isset($versions['Header']): + case !isset($versions['Library']): + case $versions['Header'] == $versions['Library']: + define('MATH_BIGINTEGER_OPENSSL_ENABLED', true); + break; + default: + define('MATH_BIGINTEGER_OPENSSL_DISABLE', true); + } + } + + if (!defined('PHP_INT_SIZE')) { + define('PHP_INT_SIZE', 4); + } + + if (!defined('MATH_BIGINTEGER_BASE') && MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_INTERNAL) { + switch (PHP_INT_SIZE) { + case 8: // use 64-bit integers if int size is 8 bytes + define('MATH_BIGINTEGER_BASE', 31); + define('MATH_BIGINTEGER_BASE_FULL', 0x80000000); + define('MATH_BIGINTEGER_MAX_DIGIT', 0x7FFFFFFF); + define('MATH_BIGINTEGER_MSB', 0x40000000); + // 10**9 is the closest we can get to 2**31 without passing it + define('MATH_BIGINTEGER_MAX10', 1000000000); + define('MATH_BIGINTEGER_MAX10_LEN', 9); + // the largest digit that may be used in addition / subtraction + define('MATH_BIGINTEGER_MAX_DIGIT2', pow(2, 62)); + break; + //case 4: // use 64-bit floats if int size is 4 bytes + default: + define('MATH_BIGINTEGER_BASE', 26); + define('MATH_BIGINTEGER_BASE_FULL', 0x4000000); + define('MATH_BIGINTEGER_MAX_DIGIT', 0x3FFFFFF); + define('MATH_BIGINTEGER_MSB', 0x2000000); + // 10**7 is the closest to 2**26 without passing it + define('MATH_BIGINTEGER_MAX10', 10000000); + define('MATH_BIGINTEGER_MAX10_LEN', 7); + // the largest digit that may be used in addition / subtraction + // we do pow(2, 52) instead of using 4503599627370496 directly because some + // PHP installations will truncate 4503599627370496. + define('MATH_BIGINTEGER_MAX_DIGIT2', pow(2, 52)); + } } switch ( MATH_BIGINTEGER_MODE ) { @@ -338,7 +384,7 @@ class Math_BigInteger { // converts a base-2**8 (big endian / msb) number to base-2**26 (little endian / lsb) default: while (strlen($x)) { - $this->value[] = $this->_bytes2int($this->_base256_rshift($x, 26)); + $this->value[] = $this->_bytes2int($this->_base256_rshift($x, MATH_BIGINTEGER_BASE)); } } @@ -390,7 +436,10 @@ class Math_BigInteger { break; case 10: case -10: - $x = preg_replace('#^(-?[0-9]*).*#', '$1', $x); + // (?value = (string) $x; + $this->value = $x === '-' ? '0' : (string) $x; break; default: $temp = new Math_BigInteger(); - // array(10000000) is 10**7 in base-2**26. 10**7 is the closest to 2**26 we can get without passing it. $multiplier = new Math_BigInteger(); - $multiplier->value = array(10000000); + $multiplier->value = array(MATH_BIGINTEGER_MAX10); if ($x[0] == '-') { $this->is_negative = true; $x = substr($x, 1); } - $x = str_pad($x, strlen($x) + (6 * strlen($x)) % 7, 0, STR_PAD_LEFT); - + $x = str_pad($x, strlen($x) + ((MATH_BIGINTEGER_MAX10_LEN - 1) * strlen($x)) % MATH_BIGINTEGER_MAX10_LEN, 0, STR_PAD_LEFT); while (strlen($x)) { $temp = $temp->multiply($multiplier); - $temp = $temp->add(new Math_BigInteger($this->_int2bytes(substr($x, 0, 7)), 256)); - $x = substr($x, 7); + $temp = $temp->add(new Math_BigInteger($this->_int2bytes(substr($x, 0, MATH_BIGINTEGER_MAX10_LEN)), 256)); + $x = substr($x, MATH_BIGINTEGER_MAX10_LEN); } $this->value = $temp->value; @@ -543,7 +590,7 @@ class Math_BigInteger { $temp = $this->copy(); for ($i = count($temp->value) - 2; $i >= 0; --$i) { - $temp->_base256_lshift($result, 26); + $temp->_base256_lshift($result, MATH_BIGINTEGER_BASE); $result = $result | str_pad($temp->_int2bytes($temp->value[$i]), strlen($result), chr(0), STR_PAD_LEFT); } @@ -659,11 +706,11 @@ class Math_BigInteger { $temp->is_negative = false; $divisor = new Math_BigInteger(); - $divisor->value = array(10000000); // eg. 10**7 + $divisor->value = array(MATH_BIGINTEGER_MAX10); $result = ''; while (count($temp->value)) { list($temp, $mod) = $temp->divide($divisor); - $result = str_pad(isset($mod->value[0]) ? $mod->value[0] : '', 7, '0', STR_PAD_LEFT) . $result; + $result = str_pad(isset($mod->value[0]) ? $mod->value[0] : '', MATH_BIGINTEGER_MAX10_LEN, '0', STR_PAD_LEFT) . $result; } $result = ltrim($result, '0'); if (empty($result)) { @@ -874,25 +921,25 @@ class Math_BigInteger { $carry = 0; for ($i = 0, $j = 1; $j < $size; $i+=2, $j+=2) { - $sum = $x_value[$j] * 0x4000000 + $x_value[$i] + $y_value[$j] * 0x4000000 + $y_value[$i] + $carry; - $carry = $sum >= MATH_BIGINTEGER_MAX_DIGIT52; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1 - $sum = $carry ? $sum - MATH_BIGINTEGER_MAX_DIGIT52 : $sum; + $sum = $x_value[$j] * MATH_BIGINTEGER_BASE_FULL + $x_value[$i] + $y_value[$j] * MATH_BIGINTEGER_BASE_FULL + $y_value[$i] + $carry; + $carry = $sum >= MATH_BIGINTEGER_MAX_DIGIT2; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1 + $sum = $carry ? $sum - MATH_BIGINTEGER_MAX_DIGIT2 : $sum; - $temp = (int) ($sum / 0x4000000); + $temp = (int) ($sum / MATH_BIGINTEGER_BASE_FULL); - $value[$i] = (int) ($sum - 0x4000000 * $temp); // eg. a faster alternative to fmod($sum, 0x4000000) + $value[$i] = (int) ($sum - MATH_BIGINTEGER_BASE_FULL * $temp); // eg. a faster alternative to fmod($sum, 0x4000000) $value[$j] = $temp; } if ($j == $size) { // ie. if $y_size is odd $sum = $x_value[$i] + $y_value[$i] + $carry; - $carry = $sum >= 0x4000000; - $value[$i] = $carry ? $sum - 0x4000000 : $sum; + $carry = $sum >= MATH_BIGINTEGER_BASE_FULL; + $value[$i] = $carry ? $sum - MATH_BIGINTEGER_BASE_FULL : $sum; ++$i; // ie. let $i = $j since we've just done $value[$i] } if ($carry) { - for (; $value[$i] == 0x3FFFFFF; ++$i) { + for (; $value[$i] == MATH_BIGINTEGER_MAX_DIGIT; ++$i) { $value[$i] = 0; } ++$value[$i]; @@ -1010,26 +1057,26 @@ class Math_BigInteger { $carry = 0; for ($i = 0, $j = 1; $j < $y_size; $i+=2, $j+=2) { - $sum = $x_value[$j] * 0x4000000 + $x_value[$i] - $y_value[$j] * 0x4000000 - $y_value[$i] - $carry; + $sum = $x_value[$j] * MATH_BIGINTEGER_BASE_FULL + $x_value[$i] - $y_value[$j] * MATH_BIGINTEGER_BASE_FULL - $y_value[$i] - $carry; $carry = $sum < 0; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1 - $sum = $carry ? $sum + MATH_BIGINTEGER_MAX_DIGIT52 : $sum; + $sum = $carry ? $sum + MATH_BIGINTEGER_MAX_DIGIT2 : $sum; - $temp = (int) ($sum / 0x4000000); + $temp = (int) ($sum / MATH_BIGINTEGER_BASE_FULL); - $x_value[$i] = (int) ($sum - 0x4000000 * $temp); + $x_value[$i] = (int) ($sum - MATH_BIGINTEGER_BASE_FULL * $temp); $x_value[$j] = $temp; } if ($j == $y_size) { // ie. if $y_size is odd $sum = $x_value[$i] - $y_value[$i] - $carry; $carry = $sum < 0; - $x_value[$i] = $carry ? $sum + 0x4000000 : $sum; + $x_value[$i] = $carry ? $sum + MATH_BIGINTEGER_BASE_FULL : $sum; ++$i; } if ($carry) { for (; !$x_value[$i]; ++$i) { - $x_value[$i] = 0x3FFFFFF; + $x_value[$i] = MATH_BIGINTEGER_MAX_DIGIT; } --$x_value[$i]; } @@ -1162,8 +1209,8 @@ class Math_BigInteger { for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0 $temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0 - $carry = (int) ($temp / 0x4000000); - $product_value[$j] = (int) ($temp - 0x4000000 * $carry); + $carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL); + $product_value[$j] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry); } $product_value[$j] = $carry; @@ -1175,8 +1222,8 @@ class Math_BigInteger { for ($j = 0, $k = $i; $j < $x_length; ++$j, ++$k) { $temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry; - $carry = (int) ($temp / 0x4000000); - $product_value[$k] = (int) ($temp - 0x4000000 * $carry); + $carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL); + $product_value[$k] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry); } $product_value[$k] = $carry; @@ -1263,14 +1310,14 @@ class Math_BigInteger { $i2 = $i << 1; $temp = $square_value[$i2] + $value[$i] * $value[$i]; - $carry = (int) ($temp / 0x4000000); - $square_value[$i2] = (int) ($temp - 0x4000000 * $carry); + $carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL); + $square_value[$i2] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry); // note how we start from $i+1 instead of 0 as we do in multiplication. for ($j = $i + 1, $k = $i2 + 1; $j <= $max_index; ++$j, ++$k) { $temp = $square_value[$k] + 2 * $value[$j] * $value[$i] + $carry; - $carry = (int) ($temp / 0x4000000); - $square_value[$k] = (int) ($temp - 0x4000000 * $carry); + $carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL); + $square_value[$k] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry); } // the following line can yield values larger 2**15. at this point, PHP should switch @@ -1418,7 +1465,7 @@ class Math_BigInteger { // normalize $x and $y as described in HAC 14.23 / 14.24 $msb = $y->value[count($y->value) - 1]; - for ($shift = 0; !($msb & 0x2000000); ++$shift) { + for ($shift = 0; !($msb & MATH_BIGINTEGER_MSB); ++$shift) { $msb <<= 1; } $x->_lshift($shift); @@ -1465,10 +1512,10 @@ class Math_BigInteger { $q_index = $i - $y_max - 1; if ($x_window[0] == $y_window[0]) { - $quotient_value[$q_index] = 0x3FFFFFF; + $quotient_value[$q_index] = MATH_BIGINTEGER_MAX_DIGIT; } else { $quotient_value[$q_index] = (int) ( - ($x_window[0] * 0x4000000 + $x_window[1]) + ($x_window[0] * MATH_BIGINTEGER_BASE_FULL + $x_window[1]) / $y_window[0] ); @@ -1536,7 +1583,7 @@ class Math_BigInteger { $result = array(); for ($i = count($dividend) - 1; $i >= 0; --$i) { - $temp = 0x4000000 * $carry + $dividend[$i]; + $temp = MATH_BIGINTEGER_BASE_FULL * $carry + $dividend[$i]; $result[$i] = (int) ($temp / $divisor); $carry = (int) ($temp - $divisor * $result[$i]); } @@ -1754,7 +1801,7 @@ class Math_BigInteger { $e_length = count($e_value) - 1; $e_bits = decbin($e_value[$e_length]); for ($i = $e_length - 1; $i >= 0; --$i) { - $e_bits.= str_pad(decbin($e_value[$i]), 26, '0', STR_PAD_LEFT); + $e_bits.= str_pad(decbin($e_value[$i]), MATH_BIGINTEGER_BASE, '0', STR_PAD_LEFT); } $e_length = strlen($e_bits); @@ -2089,7 +2136,7 @@ class Math_BigInteger { if ($this->_compare($result, false, $temp[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_SIGN]) < 0) { $corrector_value = $this->_array_repeat(0, $n_length + 1); $corrector_value[] = 1; - $result = $this->_add($result, false, $corrector, false); + $result = $this->_add($result, false, $corrector_value, false); $result = $result[MATH_BIGINTEGER_VALUE]; } @@ -2112,6 +2159,7 @@ class Math_BigInteger { * @param Boolean $x_negative * @param Array $y_value * @param Boolean $y_negative + * @param Integer $stop * @return Array * @access private */ @@ -2148,8 +2196,8 @@ class Math_BigInteger { for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0, $k = $i $temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0 - $carry = (int) ($temp / 0x4000000); - $product_value[$j] = (int) ($temp - 0x4000000 * $carry); + $carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL); + $product_value[$j] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry); } if ($j < $stop) { @@ -2164,8 +2212,8 @@ class Math_BigInteger { for ($j = 0, $k = $i; $j < $x_length && $k < $stop; ++$j, ++$k) { $temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry; - $carry = (int) ($temp / 0x4000000); - $product_value[$k] = (int) ($temp - 0x4000000 * $carry); + $carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL); + $product_value[$k] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry); } if ($k < $stop) { @@ -2213,7 +2261,7 @@ class Math_BigInteger { for ($i = 0; $i < $k; ++$i) { $temp = $result[MATH_BIGINTEGER_VALUE][$i] * $cache[MATH_BIGINTEGER_DATA][$key]; - $temp = (int) ($temp - 0x4000000 * ((int) ($temp / 0x4000000))); + $temp = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * ((int) ($temp / MATH_BIGINTEGER_BASE_FULL))); $temp = $this->_regularMultiply(array($temp), $n); $temp = array_merge($this->_array_repeat(0, $i), $temp); $result = $this->_add($result[MATH_BIGINTEGER_VALUE], false, $temp, false); @@ -2265,9 +2313,9 @@ class Math_BigInteger { $a = array(MATH_BIGINTEGER_VALUE => $this->_array_repeat(0, $n + 1)); for ($i = 0; $i < $n; ++$i) { $temp = $a[MATH_BIGINTEGER_VALUE][0] + $x[$i] * $y[0]; - $temp = (int) ($temp - 0x4000000 * ((int) ($temp / 0x4000000))); + $temp = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * ((int) ($temp / MATH_BIGINTEGER_BASE_FULL))); $temp = $temp * $cache[MATH_BIGINTEGER_DATA][$key]; - $temp = (int) ($temp - 0x4000000 * ((int) ($temp / 0x4000000))); + $temp = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * ((int) ($temp / MATH_BIGINTEGER_BASE_FULL))); $temp = $this->_add($this->_regularMultiply(array($x[$i]), $y), false, $this->_regularMultiply(array($temp), $m), false); $a = $this->_add($a[MATH_BIGINTEGER_VALUE], false, $temp[MATH_BIGINTEGER_VALUE], false); $a[MATH_BIGINTEGER_VALUE] = array_slice($a[MATH_BIGINTEGER_VALUE], 1); @@ -2325,15 +2373,15 @@ class Math_BigInteger { * @param Array $x * @return Integer */ - function _modInverse67108864($x) // 2**26 == 67108864 + function _modInverse67108864($x) // 2**26 == 67,108,864 { $x = -$x[0]; $result = $x & 0x3; // x**-1 mod 2**2 $result = ($result * (2 - $x * $result)) & 0xF; // x**-1 mod 2**4 $result = ($result * (2 - ($x & 0xFF) * $result)) & 0xFF; // x**-1 mod 2**8 $result = ($result * ((2 - ($x & 0xFFFF) * $result) & 0xFFFF)) & 0xFFFF; // x**-1 mod 2**16 - $result = fmod($result * (2 - fmod($x * $result, 0x4000000)), 0x4000000); // x**-1 mod 2**26 - return $result & 0x3FFFFFF; + $result = fmod($result * (2 - fmod($x * $result, MATH_BIGINTEGER_BASE_FULL)), MATH_BIGINTEGER_BASE_FULL); // x**-1 mod 2**26 + return $result & MATH_BIGINTEGER_MAX_DIGIT; } /** @@ -2402,12 +2450,12 @@ class Math_BigInteger { } /** - * Calculates the greatest common divisor and Bézout's identity. + * Calculates the greatest common divisor and Bezout's identity. * - * Say you have 693 and 609. The GCD is 21. Bézout's identity states that there exist integers x and y such that + * Say you have 693 and 609. The GCD is 21. Bezout's identity states that there exist integers x and y such that * 693*x + 609*y == 21. In point of fact, there are actually an infinite number of x and y combinations and which * combination is returned is dependant upon which mode is in use. See - * {@link http://en.wikipedia.org/wiki/B%C3%A9zout%27s_identity Bézout's identity - Wikipedia} for more information. + * {@link http://en.wikipedia.org/wiki/B%C3%A9zout%27s_identity Bezout's identity - Wikipedia} for more information. * * Here's an example: * @@ -2604,8 +2652,8 @@ class Math_BigInteger { * * Note how the same comparison operator is used. If you want to test for equality, use $x->equals($y). * - * @param Math_BigInteger $x - * @return Integer < 0 if $this is less than $x; > 0 if $this is greater than $x, and 0 if they are equal. + * @param Math_BigInteger $y + * @return Integer < 0 if $this is less than $y; > 0 if $this is greater than $y, and 0 if they are equal. * @access public * @see equals() * @internal Could return $this->subtract($x), but that's not as fast as what we do do. @@ -2684,9 +2732,8 @@ class Math_BigInteger { * Some bitwise operations give different results depending on the precision being used. Examples include left * shift, not, and rotates. * - * @param Math_BigInteger $x + * @param Integer $bits * @access public - * @return Math_BigInteger */ function setPrecision($bits) { @@ -2736,7 +2783,7 @@ class Math_BigInteger { $result->value = array_slice($result->value, 0, $length); for ($i = 0; $i < $length; ++$i) { - $result->value[$i] = $result->value[$i] & $x->value[$i]; + $result->value[$i]&= $x->value[$i]; } return $this->_normalize($result); @@ -2772,11 +2819,11 @@ class Math_BigInteger { $length = max(count($this->value), count($x->value)); $result = $this->copy(); - $result->value = array_pad($result->value, 0, $length); - $x->value = array_pad($x->value, 0, $length); + $result->value = array_pad($result->value, $length, 0); + $x->value = array_pad($x->value, $length, 0); for ($i = 0; $i < $length; ++$i) { - $result->value[$i] = $this->value[$i] | $x->value[$i]; + $result->value[$i]|= $x->value[$i]; } return $this->_normalize($result); @@ -2812,11 +2859,11 @@ class Math_BigInteger { $length = max(count($this->value), count($x->value)); $result = $this->copy(); - $result->value = array_pad($result->value, 0, $length); - $x->value = array_pad($x->value, 0, $length); + $result->value = array_pad($result->value, $length, 0); + $x->value = array_pad($x->value, $length, 0); for ($i = 0; $i < $length; ++$i) { - $result->value[$i] = $this->value[$i] ^ $x->value[$i]; + $result->value[$i]^= $x->value[$i]; } return $this->_normalize($result); @@ -3004,6 +3051,37 @@ class Math_BigInteger { { } + /** + * Generates a random BigInteger + * + * Byte length is equal to $length. Uses crypt_random if it's loaded and mt_rand if it's not. + * + * @param Integer $length + * @return Math_BigInteger + * @access private + */ + function _random_number_helper($size) + { + $crypt_random = function_exists('crypt_random_string') || (!class_exists('Crypt_Random') && function_exists('crypt_random_string')); + if ($crypt_random) { + $random = crypt_random_string($size); + } else { + $random = ''; + + if ($size & 1) { + $random.= chr(mt_rand(0, 255)); + } + + $blocks = $size >> 1; + for ($i = 0; $i < $blocks; ++$i) { + // mt_rand(-2147483648, 0x7FFFFFFF) always produces -2147483648 on some systems + $random.= pack('n', mt_rand(0, 0xFFFF)); + } + } + + return new Math_BigInteger($random, 256); + } + /** * Generate a random number * @@ -3033,48 +3111,45 @@ class Math_BigInteger { $min = $temp; } - $generator = $this->generator; - - $max = $max->subtract($min); - $max = ltrim($max->toBytes(), chr(0)); - $size = strlen($max) - 1; - - $crypt_random = function_exists('crypt_random_string') || (!class_exists('Crypt_Random') && function_exists('crypt_random_string')); - if ($crypt_random) { - $random = crypt_random_string($size); - } else { - $random = ''; - - if ($size & 1) { - $random.= chr(mt_rand(0, 255)); - } - - $blocks = $size >> 1; - for ($i = 0; $i < $blocks; ++$i) { - // mt_rand(-2147483648, 0x7FFFFFFF) always produces -2147483648 on some systems - $random.= pack('n', mt_rand(0, 0xFFFF)); - } + static $one; + if (!isset($one)) { + $one = new Math_BigInteger(1); } - $fragment = new Math_BigInteger($random, 256); - $leading = $fragment->compare(new Math_BigInteger(substr($max, 1), 256)) > 0 ? - ord($max[0]) - 1 : ord($max[0]); + $max = $max->subtract($min->subtract($one)); + $size = strlen(ltrim($max->toBytes(), chr(0))); - if (!$crypt_random) { - $msb = chr(mt_rand(0, $leading)); - } else { - $cutoff = floor(0xFF / $leading) * $leading; - while (true) { - $msb = ord(crypt_random_string(1)); - if ($msb <= $cutoff) { - $msb%= $leading; - break; - } - } - $msb = chr($msb); + /* + doing $random % $max doesn't work because some numbers will be more likely to occur than others. + eg. if $max is 140 and $random's max is 255 then that'd mean both $random = 5 and $random = 145 + would produce 5 whereas the only value of random that could produce 139 would be 139. ie. + not all numbers would be equally likely. some would be more likely than others. + + creating a whole new random number until you find one that is within the range doesn't work + because, for sufficiently small ranges, the likelihood that you'd get a number within that range + would be pretty small. eg. with $random's max being 255 and if your $max being 1 the probability + would be pretty high that $random would be greater than $max. + + phpseclib works around this using the technique described here: + + http://crypto.stackexchange.com/questions/5708/creating-a-small-number-from-a-cryptographically-secure-random-string + */ + $random_max = new Math_BigInteger(chr(1) . str_repeat("\0", $size), 256); + $random = $this->_random_number_helper($size); + + list($max_multiple) = $random_max->divide($max); + $max_multiple = $max_multiple->multiply($max); + + while ($random->compare($max_multiple) >= 0) { + $random = $random->subtract($max_multiple); + $random_max = $random_max->subtract($max_multiple); + $random = $random->bitwise_leftShift(8); + $random = $random->add($this->_random_number_helper(1)); + $random_max = $random_max->bitwise_leftShift(8); + list($max_multiple) = $random_max->divide($max); + $max_multiple = $max_multiple->multiply($max); } - - $random = new Math_BigInteger($msb . $random, 256); + list(, $random) = $random->divide($max); return $this->_normalize($random->add($min)); } @@ -3094,10 +3169,18 @@ class Math_BigInteger { */ function randomPrime($min = false, $max = false, $timeout = false) { + if ($min === false) { + $min = new Math_BigInteger(0); + } + + if ($max === false) { + $max = new Math_BigInteger(0x7FFFFFFF); + } + $compare = $max->compare($min); if (!$compare) { - return $min; + return $min->isPrime() ? $min : false; } else if ($compare < 0) { // if $min is bigger then $max, swap $min and $max $temp = $max; @@ -3105,36 +3188,6 @@ class Math_BigInteger { $min = $temp; } - // gmp_nextprime() requires PHP 5 >= 5.2.0 per . - if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_GMP && function_exists('gmp_nextprime') ) { - // we don't rely on Math_BigInteger::random()'s min / max when gmp_nextprime() is being used since this function - // does its own checks on $max / $min when gmp_nextprime() is used. When gmp_nextprime() is not used, however, - // the same $max / $min checks are not performed. - if ($min === false) { - $min = new Math_BigInteger(0); - } - - if ($max === false) { - $max = new Math_BigInteger(0x7FFFFFFF); - } - - $x = $this->random($min, $max); - - $x->value = gmp_nextprime($x->value); - - if ($x->compare($max) <= 0) { - return $x; - } - - $x->value = gmp_nextprime($min->value); - - if ($x->compare($max) <= 0) { - return $x; - } - - return false; - } - static $one, $two; if (!isset($one)) { $one = new Math_BigInteger(1); @@ -3144,6 +3197,23 @@ class Math_BigInteger { $start = time(); $x = $this->random($min, $max); + + // gmp_nextprime() requires PHP 5 >= 5.2.0 per . + if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_GMP && function_exists('gmp_nextprime') ) { + $p = new Math_BigInteger(); + $p->value = gmp_nextprime($x->value); + + if ($p->compare($max) <= 0) { + return $p; + } + + if (!$min->equals($x)) { + $x = $x->subtract($one); + } + + return $x->randomPrime($min, $x); + } + if ($x->equals($two)) { return $x; } @@ -3375,16 +3445,16 @@ class Math_BigInteger { return; } - $num_digits = (int) ($shift / 26); - $shift %= 26; + $num_digits = (int) ($shift / MATH_BIGINTEGER_BASE); + $shift %= MATH_BIGINTEGER_BASE; $shift = 1 << $shift; $carry = 0; for ($i = 0; $i < count($this->value); ++$i) { $temp = $this->value[$i] * $shift + $carry; - $carry = (int) ($temp / 0x4000000); - $this->value[$i] = (int) ($temp - $carry * 0x4000000); + $carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL); + $this->value[$i] = (int) ($temp - $carry * MATH_BIGINTEGER_BASE_FULL); } if ( $carry ) { @@ -3410,9 +3480,9 @@ class Math_BigInteger { return; } - $num_digits = (int) ($shift / 26); - $shift %= 26; - $carry_shift = 26 - $shift; + $num_digits = (int) ($shift / MATH_BIGINTEGER_BASE); + $shift %= MATH_BIGINTEGER_BASE; + $carry_shift = MATH_BIGINTEGER_BASE - $shift; $carry_mask = (1 << $shift) - 1; if ( $num_digits ) { @@ -3485,6 +3555,7 @@ class Math_BigInteger { * * Removes leading zeros * + * @param Array $value * @return Math_BigInteger * @access private */ @@ -3630,4 +3701,4 @@ class Math_BigInteger { $temp = ltrim(pack('N', $length), chr(0)); return pack('Ca*', 0x80 | strlen($temp), $temp); } -} \ No newline at end of file +} diff --git a/apps/files_external/3rdparty/phpseclib/phpseclib/Net/SCP.php b/apps/files_external/3rdparty/phpseclib/phpseclib/Net/SCP.php new file mode 100644 index 0000000000..88180cac67 --- /dev/null +++ b/apps/files_external/3rdparty/phpseclib/phpseclib/Net/SCP.php @@ -0,0 +1,362 @@ + + * login('username', 'password')) { + * exit('bad login'); + * } + + * $scp = new Net_SCP($ssh); + * $scp->put('abcd', str_repeat('x', 1024*1024)); + * ?> + * + * + * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @category Net + * @package Net_SCP + * @author Jim Wigginton + * @copyright MMX Jim Wigginton + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @link http://phpseclib.sourceforge.net + */ + +/**#@+ + * @access public + * @see Net_SCP::put() + */ +/** + * Reads data from a local file. + */ +define('NET_SCP_LOCAL_FILE', 1); +/** + * Reads data from a string. + */ +define('NET_SCP_STRING', 2); +/**#@-*/ + +/**#@+ + * @access private + * @see Net_SCP::_send() + * @see Net_SCP::_receive() + */ +/** + * SSH1 is being used. + */ +define('NET_SCP_SSH1', 1); +/** + * SSH2 is being used. + */ +define('NET_SCP_SSH2', 2); +/**#@-*/ + +/** + * Pure-PHP implementations of SCP. + * + * @author Jim Wigginton + * @version 0.1.0 + * @access public + * @package Net_SCP + */ +class Net_SCP { + /** + * SSH Object + * + * @var Object + * @access private + */ + var $ssh; + + /** + * Packet Size + * + * @var Integer + * @access private + */ + var $packet_size; + + /** + * Mode + * + * @var Integer + * @access private + */ + var $mode; + + /** + * Default Constructor. + * + * Connects to an SSH server + * + * @param String $host + * @param optional Integer $port + * @param optional Integer $timeout + * @return Net_SCP + * @access public + */ + function Net_SCP($ssh) + { + if (!is_object($ssh)) { + return; + } + + switch (strtolower(get_class($ssh))) { + case'net_ssh2': + $this->mode = NET_SCP_SSH2; + break; + case 'net_ssh1': + $this->packet_size = 50000; + $this->mode = NET_SCP_SSH1; + break; + default: + return; + } + + $this->ssh = $ssh; + } + + /** + * Uploads a file to the SCP server. + * + * By default, Net_SCP::put() does not read from the local filesystem. $data is dumped directly into $remote_file. + * So, for example, if you set $data to 'filename.ext' and then do Net_SCP::get(), you will get a file, twelve bytes + * long, containing 'filename.ext' as its contents. + * + * Setting $mode to NET_SCP_LOCAL_FILE will change the above behavior. With NET_SCP_LOCAL_FILE, $remote_file will + * contain as many bytes as filename.ext does on your local filesystem. If your filename.ext is 1MB then that is how + * large $remote_file will be, as well. + * + * Currently, only binary mode is supported. As such, if the line endings need to be adjusted, you will need to take + * care of that, yourself. + * + * @param String $remote_file + * @param String $data + * @param optional Integer $mode + * @param optional Callable $callback + * @return Boolean + * @access public + */ + function put($remote_file, $data, $mode = NET_SCP_STRING, $callback = null) + { + if (!isset($this->ssh)) { + return false; + } + + if (!$this->ssh->exec('scp -t ' . $remote_file, false)) { // -t = to + return false; + } + + $temp = $this->_receive(); + if ($temp !== chr(0)) { + return false; + } + + if ($this->mode == NET_SCP_SSH2) { + $this->packet_size = $this->ssh->packet_size_client_to_server[NET_SSH2_CHANNEL_EXEC]; + } + + $remote_file = basename($remote_file); + + if ($mode == NET_SCP_STRING) { + $size = strlen($data); + } else { + if (!is_file($data)) { + user_error("$data is not a valid file", E_USER_NOTICE); + return false; + } + + $fp = @fopen($data, 'rb'); + if (!$fp) { + fclose($fp); + return false; + } + $size = filesize($data); + } + + $this->_send('C0644 ' . $size . ' ' . $remote_file . "\n"); + + $temp = $this->_receive(); + if ($temp !== chr(0)) { + return false; + } + + $sent = 0; + while ($sent < $size) { + $temp = $mode & NET_SCP_STRING ? substr($data, $sent, $this->packet_size) : fread($fp, $this->packet_size); + $this->_send($temp); + $sent+= strlen($temp); + + if (is_callable($callback)) { + $callback($sent); + } + } + $this->_close(); + + if ($mode != NET_SCP_STRING) { + fclose($fp); + } + + return true; + } + + /** + * Downloads a file from the SCP server. + * + * Returns a string containing the contents of $remote_file if $local_file is left undefined or a boolean false if + * the operation was unsuccessful. If $local_file is defined, returns true or false depending on the success of the + * operation + * + * @param String $remote_file + * @param optional String $local_file + * @return Mixed + * @access public + */ + function get($remote_file, $local_file = false) + { + if (!isset($this->ssh)) { + return false; + } + + if (!$this->ssh->exec('scp -f ' . $remote_file, false)) { // -f = from + return false; + } + + $this->_send("\0"); + + if (!preg_match('#(?[^ ]+) (?\d+) (?.+)#', rtrim($this->_receive()), $info)) { + return false; + } + + $this->_send("\0"); + + $size = 0; + + if ($local_file !== false) { + $fp = @fopen($local_file, 'wb'); + if (!$fp) { + return false; + } + } + + $content = ''; + while ($size < $info['size']) { + $data = $this->_receive(); + // SCP usually seems to split stuff out into 16k chunks + $size+= strlen($data); + + if ($local_file === false) { + $content.= $data; + } else { + fputs($fp, $data); + } + } + + $this->_close(); + + if ($local_file !== false) { + fclose($fp); + return true; + } + + return $content; + } + + /** + * Sends a packet to an SSH server + * + * @param String $data + * @access private + */ + function _send($data) + { + switch ($this->mode) { + case NET_SCP_SSH2: + $this->ssh->_send_channel_packet(NET_SSH2_CHANNEL_EXEC, $data); + break; + case NET_SCP_SSH1: + $data = pack('CNa*', NET_SSH1_CMSG_STDIN_DATA, strlen($data), $data); + $this->ssh->_send_binary_packet($data); + } + } + + /** + * Receives a packet from an SSH server + * + * @return String + * @access private + */ + function _receive() + { + switch ($this->mode) { + case NET_SCP_SSH2: + return $this->ssh->_get_channel_packet(NET_SSH2_CHANNEL_EXEC, true); + case NET_SCP_SSH1: + if (!$this->ssh->bitmap) { + return false; + } + while (true) { + $response = $this->ssh->_get_binary_packet(); + switch ($response[NET_SSH1_RESPONSE_TYPE]) { + case NET_SSH1_SMSG_STDOUT_DATA: + extract(unpack('Nlength', $response[NET_SSH1_RESPONSE_DATA])); + return $this->ssh->_string_shift($response[NET_SSH1_RESPONSE_DATA], $length); + case NET_SSH1_SMSG_STDERR_DATA: + break; + case NET_SSH1_SMSG_EXITSTATUS: + $this->ssh->_send_binary_packet(chr(NET_SSH1_CMSG_EXIT_CONFIRMATION)); + fclose($this->ssh->fsock); + $this->ssh->bitmap = 0; + return false; + default: + user_error('Unknown packet received', E_USER_NOTICE); + return false; + } + } + } + } + + /** + * Closes the connection to an SSH server + * + * @access private + */ + function _close() + { + switch ($this->mode) { + case NET_SCP_SSH2: + $this->ssh->_close_channel(NET_SSH2_CHANNEL_EXEC); + break; + case NET_SCP_SSH1: + $this->ssh->disconnect(); + } + } +} diff --git a/apps/files_external/3rdparty/phpseclib/phpseclib/Net/SFTP.php b/apps/files_external/3rdparty/phpseclib/phpseclib/Net/SFTP.php index 8db087d3d9..5356ffbf77 100644 --- a/apps/files_external/3rdparty/phpseclib/phpseclib/Net/SFTP.php +++ b/apps/files_external/3rdparty/phpseclib/phpseclib/Net/SFTP.php @@ -58,7 +58,7 @@ * Include Net_SSH2 */ if (!class_exists('Net_SSH2')) { - require_once('Net/SSH2.php'); + require_once('SSH2.php'); } /**#@+ @@ -88,7 +88,7 @@ define('NET_SFTP_LOG_REALTIME', 3); * @see Net_SSH2::_get_channel_packet() * @access private */ -define('NET_SFTP_CHANNEL', 2); +define('NET_SFTP_CHANNEL', 0x100); /**#@+ * @access public @@ -97,16 +97,20 @@ define('NET_SFTP_CHANNEL', 2); /** * Reads data from a local file. */ -define('NET_SFTP_LOCAL_FILE', 1); +define('NET_SFTP_LOCAL_FILE', 1); /** * Reads data from a string. */ // this value isn't really used anymore but i'm keeping it reserved for historical reasons -define('NET_SFTP_STRING', 2); +define('NET_SFTP_STRING', 2); /** * Resumes an upload */ -define('NET_SFTP_RESUME', 4); +define('NET_SFTP_RESUME', 4); +/** + * Append a local file to an already existing remote file + */ +define('NET_SFTP_RESUME_START', 8); /**#@-*/ /** @@ -225,15 +229,6 @@ class Net_SFTP extends Net_SSH2 { */ var $sftp_errors = array(); - /** - * File Type - * - * @see Net_SFTP::_parseLongname() - * @var Integer - * @access private - */ - var $fileType = 0; - /** * Directory Cache * @@ -248,6 +243,16 @@ class Net_SFTP extends Net_SSH2 { */ var $dirs = array(); + /** + * Max SFTP Packet Size + * + * @see Net_SFTP::Net_SFTP() + * @see Net_SFTP::get() + * @var Array + * @access private + */ + var $max_sftp_packet; + /** * Default Constructor. * @@ -262,6 +267,9 @@ class Net_SFTP extends Net_SSH2 { function Net_SFTP($host, $port = 22, $timeout = 10) { parent::Net_SSH2($host, $port, $timeout); + + $this->max_sftp_packet = 1 << 15; + $this->packet_types = array( 1 => 'NET_SFTP_INIT', 2 => 'NET_SFTP_VERSION', @@ -306,7 +314,30 @@ class Net_SFTP extends Net_SSH2 { 5 => 'NET_SFTP_STATUS_BAD_MESSAGE', 6 => 'NET_SFTP_STATUS_NO_CONNECTION', 7 => 'NET_SFTP_STATUS_CONNECTION_LOST', - 8 => 'NET_SFTP_STATUS_OP_UNSUPPORTED' + 8 => 'NET_SFTP_STATUS_OP_UNSUPPORTED', + 9 => 'NET_SFTP_STATUS_INVALID_HANDLE', + 10 => 'NET_SFTP_STATUS_NO_SUCH_PATH', + 11 => 'NET_SFTP_STATUS_FILE_ALREADY_EXISTS', + 12 => 'NET_SFTP_STATUS_WRITE_PROTECT', + 13 => 'NET_SFTP_STATUS_NO_MEDIA', + 14 => 'NET_SFTP_STATUS_NO_SPACE_ON_FILESYSTEM', + 15 => 'NET_SFTP_STATUS_QUOTA_EXCEEDED', + 16 => 'NET_SFTP_STATUS_UNKNOWN_PRINCIPAL', + 17 => 'NET_SFTP_STATUS_LOCK_CONFLICT', + 18 => 'NET_SFTP_STATUS_DIR_NOT_EMPTY', + 19 => 'NET_SFTP_STATUS_NOT_A_DIRECTORY', + 20 => 'NET_SFTP_STATUS_INVALID_FILENAME', + 21 => 'NET_SFTP_STATUS_LINK_LOOP', + 22 => 'NET_SFTP_STATUS_CANNOT_DELETE', + 23 => 'NET_SFTP_STATUS_INVALID_PARAMETER', + 24 => 'NET_SFTP_STATUS_FILE_IS_A_DIRECTORY', + 25 => 'NET_SFTP_STATUS_BYTE_RANGE_LOCK_CONFLICT', + 26 => 'NET_SFTP_STATUS_BYTE_RANGE_LOCK_REFUSED', + 27 => 'NET_SFTP_STATUS_DELETE_PENDING', + 28 => 'NET_SFTP_STATUS_FILE_CORRUPT', + 29 => 'NET_SFTP_STATUS_OWNER_INVALID', + 30 => 'NET_SFTP_STATUS_GROUP_INVALID', + 31 => 'NET_SFTP_STATUS_NO_MATCHING_BYTE_RANGE_LOCK' ); // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-7.1 // the order, in this case, matters quite a lot - see Net_SFTP::_parseAttributes() to understand why @@ -329,7 +360,8 @@ class Net_SFTP extends Net_SSH2 { 0x00000002 => 'NET_SFTP_OPEN_WRITE', 0x00000004 => 'NET_SFTP_OPEN_APPEND', 0x00000008 => 'NET_SFTP_OPEN_CREATE', - 0x00000010 => 'NET_SFTP_OPEN_TRUNCATE' + 0x00000010 => 'NET_SFTP_OPEN_TRUNCATE', + 0x00000020 => 'NET_SFTP_OPEN_EXCL' ); // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-5.2 // see Net_SFTP::_parseLongname() for an explanation @@ -337,7 +369,14 @@ class Net_SFTP extends Net_SSH2 { 1 => 'NET_SFTP_TYPE_REGULAR', 2 => 'NET_SFTP_TYPE_DIRECTORY', 3 => 'NET_SFTP_TYPE_SYMLINK', - 4 => 'NET_SFTP_TYPE_SPECIAL' + 4 => 'NET_SFTP_TYPE_SPECIAL', + 5 => 'NET_SFTP_TYPE_UNKNOWN', + // the followin types were first defined for use in SFTPv5+ + // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-05#section-5.2 + 6 => 'NET_SFTP_TYPE_SOCKET', + 7 => 'NET_SFTP_TYPE_CHAR_DEVICE', + 8 => 'NET_SFTP_TYPE_BLOCK_DEVICE', + 9 => 'NET_SFTP_TYPE_FIFO' ); $this->_define_array( $this->packet_types, @@ -346,6 +385,10 @@ class Net_SFTP extends Net_SSH2 { $this->open_flags, $this->file_types ); + + if (!defined('NET_SFTP_QUEUE_SIZE')) { + define('NET_SFTP_QUEUE_SIZE', 50); + } } /** @@ -356,13 +399,14 @@ class Net_SFTP extends Net_SSH2 { * @return Boolean * @access public */ - function login($username, $password = '') + function login($username) { - if (!parent::login($username, $password)) { + $args = func_get_args(); + if (!call_user_func_array(array('Net_SSH2', 'login'), $args)) { return false; } - $this->window_size_client_to_server[NET_SFTP_CHANNEL] = $this->window_size; + $this->window_size_server_to_client[NET_SFTP_CHANNEL] = $this->window_size; $packet = pack('CNa*N3', NET_SSH2_MSG_CHANNEL_OPEN, strlen('session'), 'session', NET_SFTP_CHANNEL, $this->window_size, 0x4000); @@ -388,7 +432,24 @@ class Net_SFTP extends Net_SSH2 { $response = $this->_get_channel_packet(NET_SFTP_CHANNEL); if ($response === false) { - return false; + // from PuTTY's psftp.exe + $command = "test -x /usr/lib/sftp-server && exec /usr/lib/sftp-server\n" . + "test -x /usr/local/lib/sftp-server && exec /usr/local/lib/sftp-server\n" . + "exec sftp-server"; + // we don't do $this->exec($command, false) because exec() operates on a different channel and plus the SSH_MSG_CHANNEL_OPEN that exec() does + // is redundant + $packet = pack('CNNa*CNa*', + NET_SSH2_MSG_CHANNEL_REQUEST, $this->server_channels[NET_SFTP_CHANNEL], strlen('exec'), 'exec', 1, strlen($command), $command); + if (!$this->_send_binary_packet($packet)) { + return false; + } + + $this->channel_status[NET_SFTP_CHANNEL] = NET_SSH2_MSG_CHANNEL_REQUEST; + + $response = $this->_get_channel_packet(NET_SFTP_CHANNEL); + if ($response === false) { + return false; + } } $this->channel_status[NET_SFTP_CHANNEL] = NET_SSH2_MSG_CHANNEL_DATA; @@ -460,7 +521,7 @@ class Net_SFTP extends Net_SSH2 { return false; } - $this->pwd = $this->_realpath('.', false); + $this->pwd = $this->_realpath('.'); $this->_save_dir($this->pwd); @@ -485,7 +546,8 @@ class Net_SFTP extends Net_SSH2 { * @param optional Integer $status * @access public */ - function _logError($response, $status = -1) { + function _logError($response, $status = -1) + { if ($status == -1) { extract(unpack('Nstatus', $this->_string_shift($response, 4))); } @@ -507,98 +569,57 @@ class Net_SFTP extends Net_SSH2 { * the absolute (canonicalized) path. * * @see Net_SFTP::chdir() - * @param String $dir + * @param String $path * @return Mixed * @access private */ - function _realpath($dir, $check_dir = true) + function _realpath($path) { - if ($check_dir && $this->_is_dir($dir)) { - return true; - } - - /* - "This protocol represents file names as strings. File names are - assumed to use the slash ('/') character as a directory separator. - - File names starting with a slash are "absolute", and are relative to - the root of the file system. Names starting with any other character - are relative to the user's default directory (home directory). Note - that identifying the user is assumed to take place outside of this - protocol." - - -- http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-6 - */ - $file = ''; - if ($this->pwd !== false) { - // if the SFTP server returned the canonicalized path even for non-existant files this wouldn't be necessary - // on OpenSSH it isn't necessary but on other SFTP servers it is. that and since the specs say nothing on - // the subject, we'll go ahead and work around it with the following. - if (empty($dir) || $dir[strlen($dir) - 1] != '/') { - $file = basename($dir); - $dir = dirname($dir); - } - - $dir = $dir[0] == '/' ? '/' . rtrim(substr($dir, 1), '/') : rtrim($dir, '/'); - - if ($dir == '.' || $dir == $this->pwd) { - $temp = $this->pwd; - if (!empty($file)) { - $temp.= '/' . $file; - } - return $temp; - } - - if ($dir[0] != '/') { - $dir = $this->pwd . '/' . $dir; - } - // on the surface it seems like maybe resolving a path beginning with / is unnecessary, but such paths - // can contain .'s and ..'s just like any other. we could parse those out as appropriate or we can let - // the server do it. we'll do the latter. - } - - /* - that SSH_FXP_REALPATH returns SSH_FXP_NAME does not necessarily mean that anything actually exists at the - specified path. generally speaking, no attributes are returned with this particular SSH_FXP_NAME packet - regardless of whether or not a file actually exists. and in SFTPv3, the longname field and the filename - field match for this particular SSH_FXP_NAME packet. for other SSH_FXP_NAME packets, this will likely - not be the case, but for this one, it is. - */ - // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.9 - if (!$this->_send_sftp_packet(NET_SFTP_REALPATH, pack('Na*', strlen($dir), $dir))) { - return false; - } - - $response = $this->_get_sftp_packet(); - switch ($this->packet_type) { - case NET_SFTP_NAME: - // although SSH_FXP_NAME is implemented differently in SFTPv3 than it is in SFTPv4+, the following - // should work on all SFTP versions since the only part of the SSH_FXP_NAME packet the following looks - // at is the first part and that part is defined the same in SFTP versions 3 through 6. - $this->_string_shift($response, 4); // skip over the count - it should be 1, anyway - extract(unpack('Nlength', $this->_string_shift($response, 4))); - $realpath = $this->_string_shift($response, $length); - // the following is SFTPv3 only code. see Net_SFTP::_parseLongname() for more information. - // per the above comment, this is a shot in the dark that, on most servers, won't help us in determining - // the file type for Net_SFTP::stat() and Net_SFTP::lstat() but it's worth a shot. - extract(unpack('Nlength', $this->_string_shift($response, 4))); - $this->fileType = $this->_parseLongname($this->_string_shift($response, $length)); - break; - case NET_SFTP_STATUS: - $this->_logError($response); - return false; - default: - user_error('Expected SSH_FXP_NAME or SSH_FXP_STATUS'); + if ($this->pwd === false) { + // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.9 + if (!$this->_send_sftp_packet(NET_SFTP_REALPATH, pack('Na*', strlen($path), $path))) { return false; + } + + $response = $this->_get_sftp_packet(); + switch ($this->packet_type) { + case NET_SFTP_NAME: + // although SSH_FXP_NAME is implemented differently in SFTPv3 than it is in SFTPv4+, the following + // should work on all SFTP versions since the only part of the SSH_FXP_NAME packet the following looks + // at is the first part and that part is defined the same in SFTP versions 3 through 6. + $this->_string_shift($response, 4); // skip over the count - it should be 1, anyway + extract(unpack('Nlength', $this->_string_shift($response, 4))); + return $this->_string_shift($response, $length); + case NET_SFTP_STATUS: + $this->_logError($response); + return false; + default: + user_error('Expected SSH_FXP_NAME or SSH_FXP_STATUS'); + return false; + } } - // if $this->pwd isn't set than the only thing $realpath could be is for '.', which is pretty much guaranteed to - // be a bonafide directory - if (!empty($file)) { - $realpath.= '/' . $file; + if ($path[0] != '/') { + $path = $this->pwd . '/' . $path; } - return $realpath; + $path = explode('/', $path); + $new = array(); + foreach ($path as $dir) { + if (!strlen($dir)) { + continue; + } + switch ($dir) { + case '..': + array_pop($new); + case '.': + break; + default: + $new[] = $dir; + } + } + + return '/' . implode('/', $new); } /** @@ -618,18 +639,18 @@ class Net_SFTP extends Net_SSH2 { $dir.= '/'; } + $dir = $this->_realpath($dir); + // confirm that $dir is, in fact, a valid directory if ($this->_is_dir($dir)) { $this->pwd = $dir; return true; } - $dir = $this->_realpath($dir, false); - - if ($this->_is_dir($dir)) { - $this->pwd = $dir; - return true; - } + // we could do a stat on the alleged $dir to see if it's a directory but that doesn't tell us + // the currently logged in user has the appropriate permissions or not. maybe you could see if + // the file's uid / gid match the currently logged in user's uid / gid but how there's no easy + // way to get those with SFTP if (!$this->_send_sftp_packet(NET_SFTP_OPENDIR, pack('Na*', strlen($dir), $dir))) { return false; @@ -649,19 +670,7 @@ class Net_SFTP extends Net_SSH2 { return false; } - if (!$this->_send_sftp_packet(NET_SFTP_CLOSE, pack('Na*', strlen($handle), $handle))) { - return false; - } - - $response = $this->_get_sftp_packet(); - if ($this->packet_type != NET_SFTP_STATUS) { - user_error('Expected SSH_FXP_STATUS'); - return false; - } - - extract(unpack('Nstatus', $this->_string_shift($response, 4))); - if ($status != NET_SFTP_STATUS_OK) { - $this->_logError($response, $status); + if (!$this->_close_handle($handle)) { return false; } @@ -760,18 +769,21 @@ class Net_SFTP extends Net_SSH2 { $shortname = $this->_string_shift($response, $length); extract(unpack('Nlength', $this->_string_shift($response, 4))); $longname = $this->_string_shift($response, $length); - $attributes = $this->_parseAttributes($response); // we also don't care about the attributes + $attributes = $this->_parseAttributes($response); + if (!isset($attributes['type'])) { + $fileType = $this->_parseLongname($longname); + if ($fileType) { + $attributes['type'] = $fileType; + } + } if (!$raw) { $contents[] = $shortname; } else { $contents[$shortname] = $attributes; - $fileType = $this->_parseLongname($longname); - if ($fileType) { - if ($fileType == NET_SFTP_TYPE_DIRECTORY && ($shortname != '.' && $shortname != '..')) { - $this->_save_dir($dir . '/' . $shortname); - } - $contents[$shortname]['type'] = $fileType; - } + } + + if (isset($attributes['type']) && $attributes['type'] == NET_SFTP_TYPE_DIRECTORY && ($shortname != '.' && $shortname != '..')) { + $this->_save_dir($dir . '/' . $shortname); } // SFTPv6 has an optional boolean end-of-list field, but we'll ignore that, since the // final SSH_FXP_STATUS packet should tell us that, already. @@ -790,21 +802,7 @@ class Net_SFTP extends Net_SSH2 { } } - if (!$this->_send_sftp_packet(NET_SFTP_CLOSE, pack('Na*', strlen($handle), $handle))) { - return false; - } - - // "The client MUST release all resources associated with the handle regardless of the status." - // -- http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.1.3 - $response = $this->_get_sftp_packet(); - if ($this->packet_type != NET_SFTP_STATUS) { - user_error('Expected SSH_FXP_STATUS'); - return false; - } - - extract(unpack('Nstatus', $this->_string_shift($response, 4))); - if ($status != NET_SFTP_STATUS_OK) { - $this->_logError($response, $status); + if (!$this->_close_handle($handle)) { return false; } @@ -880,6 +878,9 @@ class Net_SFTP extends Net_SSH2 { /** * Checks cache for directory * + * Mainly used by chdir, which is, in turn, also used for determining whether or not an individual + * file is a directory or not by stat() and lstat() + * * @param String $dir * @access private */ @@ -894,6 +895,7 @@ class Net_SFTP extends Net_SSH2 { } $temp = &$temp[$dir]; } + return true; } /** @@ -920,6 +922,9 @@ class Net_SFTP extends Net_SSH2 { if ($stat === false) { return false; } + if (isset($stat['type'])) { + return $stat; + } $pwd = $this->pwd; $stat['type'] = $this->chdir($filename) ? @@ -951,10 +956,14 @@ class Net_SFTP extends Net_SSH2 { } $lstat = $this->_stat($filename, NET_SFTP_LSTAT); - $stat = $this->_stat($filename, NET_SFTP_STAT); - if ($stat === false) { + if ($lstat === false) { return false; } + if (isset($lstat['type'])) { + return $lstat; + } + + $stat = $this->_stat($filename, NET_SFTP_STAT); if ($lstat != $stat) { return array_merge($lstat, array('type' => NET_SFTP_TYPE_SYMLINK)); @@ -991,11 +1000,7 @@ class Net_SFTP extends Net_SSH2 { $response = $this->_get_sftp_packet(); switch ($this->packet_type) { case NET_SFTP_ATTRS: - $attributes = $this->_parseAttributes($response); - if ($this->fileType) { - $attributes['type'] = $this->fileType; - } - return $attributes; + return $this->_parseAttributes($response); case NET_SFTP_STATUS: $this->_logError($response); return false; @@ -1005,33 +1010,6 @@ class Net_SFTP extends Net_SSH2 { return false; } - /** - * Attempt to identify the file type - * - * @param String $path - * @param Array $stat - * @param Array $lstat - * @return Integer - * @access private - */ - function _identify_type($path, $stat1, $stat2) - { - $stat1 = $this->_stat($path, $stat1); - $stat2 = $this->_stat($path, $stat2); - - if ($stat1 != $stat2) { - return array_merge($stat1, array('type' => NET_SFTP_TYPE_SYMLINK)); - } - - $pwd = $this->pwd; - $stat1['type'] = $this->chdir($path) ? - NET_SFTP_TYPE_DIRECTORY : - NET_SFTP_TYPE_REGULAR; - $this->pwd = $pwd; - - return $stat1; - } - /** * Returns the file size, in bytes, or false, on failure * @@ -1043,7 +1021,7 @@ class Net_SFTP extends Net_SSH2 { */ function _size($filename) { - $result = $this->_stat($filename, NET_SFTP_LSTAT); + $result = $this->_stat($filename, NET_SFTP_STAT); if ($result === false) { return false; } @@ -1051,16 +1029,32 @@ class Net_SFTP extends Net_SSH2 { } /** - * Set permissions on a file. + * Truncates a file to a given length * - * Returns the new file permissions on success or FALSE on error. - * - * @param Integer $mode * @param String $filename - * @return Mixed + * @param Integer $new_size + * @return Boolean * @access public */ - function chmod($mode, $filename, $recursive = false) + function truncate($filename, $new_size) + { + $attr = pack('N3', NET_SFTP_ATTR_SIZE, $new_size / 0x100000000, $new_size); + + return $this->_setstat($filename, $attr, false); + } + + /** + * Sets access and modification time of file. + * + * If the file does not exist, it will be created. + * + * @param String $filename + * @param optional Integer $time + * @param optional Integer $atime + * @return Boolean + * @access public + */ + function touch($filename, $time = NULL, $atime = NULL) { if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { return false; @@ -1071,36 +1065,99 @@ class Net_SFTP extends Net_SSH2 { return false; } - if ($recursive) { - $i = 0; - $result = $this->_chmod_recursive($mode, $filename, $i); - $this->_read_put_responses($i); - return $result; + if (!isset($time)) { + $time = time(); + } + if (!isset($atime)) { + $atime = $time; } - // SFTPv4+ has an additional byte field - type - that would need to be sent, as well. setting it to - // SSH_FILEXFER_TYPE_UNKNOWN might work. if not, we'd have to do an SSH_FXP_STAT before doing an SSH_FXP_SETSTAT. - $attr = pack('N2', NET_SFTP_ATTR_PERMISSIONS, $mode & 07777); - if (!$this->_send_sftp_packet(NET_SFTP_SETSTAT, pack('Na*a*', strlen($filename), $filename, $attr))) { + $flags = NET_SFTP_OPEN_WRITE | NET_SFTP_OPEN_CREATE | NET_SFTP_OPEN_EXCL; + $attr = pack('N3', NET_SFTP_ATTR_ACCESSTIME, $time, $atime); + $packet = pack('Na*Na*', strlen($filename), $filename, $flags, $attr); + if (!$this->_send_sftp_packet(NET_SFTP_OPEN, $packet)) { return false; } - /* - "Because some systems must use separate system calls to set various attributes, it is possible that a failure - response will be returned, but yet some of the attributes may be have been successfully modified. If possible, - servers SHOULD avoid this situation; however, clients MUST be aware that this is possible." - - -- http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.6 - */ $response = $this->_get_sftp_packet(); - if ($this->packet_type != NET_SFTP_STATUS) { - user_error('Expected SSH_FXP_STATUS'); - return false; + switch ($this->packet_type) { + case NET_SFTP_HANDLE: + return $this->_close_handle(substr($response, 4)); + case NET_SFTP_STATUS: + $this->_logError($response); + break; + default: + user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS'); + return false; } - extract(unpack('Nstatus', $this->_string_shift($response, 4))); - if ($status != NET_SFTP_STATUS_OK) { - $this->_logError($response, $status); + return $this->_setstat($filename, $attr, false); + } + + /** + * Changes file or directory owner + * + * Returns TRUE on success or FALSE on error. + * + * @param String $filename + * @param Integer $uid + * @param optional Boolean $recursive + * @return Boolean + * @access public + */ + function chown($filename, $uid, $recursive = false) + { + // quoting from , + // "if the owner or group is specified as -1, then that ID is not changed" + $attr = pack('N3', NET_SFTP_ATTR_UIDGID, $uid, -1); + + return $this->_setstat($filename, $attr, $recursive); + } + + /** + * Changes file or directory group + * + * Returns TRUE on success or FALSE on error. + * + * @param String $filename + * @param Integer $gid + * @param optional Boolean $recursive + * @return Boolean + * @access public + */ + function chgrp($filename, $gid, $recursive = false) + { + $attr = pack('N3', NET_SFTP_ATTR_UIDGID, -1, $gid); + + return $this->_setstat($filename, $attr, $recursive); + } + + /** + * Set permissions on a file. + * + * Returns the new file permissions on success or FALSE on error. + * If $recursive is true than this just returns TRUE or FALSE. + * + * @param Integer $mode + * @param String $filename + * @param optional Boolean $recursive + * @return Mixed + * @access public + */ + function chmod($mode, $filename, $recursive = false) + { + if (is_string($mode) && is_int($filename)) { + $temp = $mode; + $mode = $filename; + $filename = $temp; + } + + $attr = pack('N2', NET_SFTP_ATTR_PERMISSIONS, $mode & 07777); + if (!$this->_setstat($filename, $attr, $recursive)) { + return false; + } + if ($recursive) { + return true; } // rather than return what the permissions *should* be, we'll return what they actually are. this will also @@ -1126,16 +1183,72 @@ class Net_SFTP extends Net_SSH2 { } /** - * Recursively chmods directories on the SFTP server + * Sets information about a file * - * Minimizes directory lookups and SSH_FXP_STATUS requests for speed. - * - * @param Integer $mode * @param String $filename + * @param String $attr + * @param Boolean $recursive * @return Boolean * @access private */ - function _chmod_recursive($mode, $path, &$i) + function _setstat($filename, $attr, $recursive) + { + if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { + return false; + } + + $filename = $this->_realpath($filename); + if ($filename === false) { + return false; + } + + if ($recursive) { + $i = 0; + $result = $this->_setstat_recursive($filename, $attr, $i); + $this->_read_put_responses($i); + return $result; + } + + // SFTPv4+ has an additional byte field - type - that would need to be sent, as well. setting it to + // SSH_FILEXFER_TYPE_UNKNOWN might work. if not, we'd have to do an SSH_FXP_STAT before doing an SSH_FXP_SETSTAT. + if (!$this->_send_sftp_packet(NET_SFTP_SETSTAT, pack('Na*a*', strlen($filename), $filename, $attr))) { + return false; + } + + /* + "Because some systems must use separate system calls to set various attributes, it is possible that a failure + response will be returned, but yet some of the attributes may be have been successfully modified. If possible, + servers SHOULD avoid this situation; however, clients MUST be aware that this is possible." + + -- http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.6 + */ + $response = $this->_get_sftp_packet(); + if ($this->packet_type != NET_SFTP_STATUS) { + user_error('Expected SSH_FXP_STATUS'); + return false; + } + + extract(unpack('Nstatus', $this->_string_shift($response, 4))); + if ($status != NET_SFTP_STATUS_OK) { + $this->_logError($response, $status); + return false; + } + + return true; + } + + /** + * Recursively sets information on directories on the SFTP server + * + * Minimizes directory lookups and SSH_FXP_STATUS requests for speed. + * + * @param String $path + * @param String $attr + * @param Integer $i + * @return Boolean + * @access private + */ + function _setstat_recursive($path, $attr, &$i) { if (!$this->_read_put_responses($i)) { return false; @@ -1144,7 +1257,7 @@ class Net_SFTP extends Net_SSH2 { $entries = $this->_list($path, true, false); if ($entries === false) { - return $this->chmod($mode, $path); + return $this->_setstat($path, $attr, false); } // normally $entries would have at least . and .. but it might not if the directories @@ -1164,18 +1277,17 @@ class Net_SFTP extends Net_SSH2 { $temp = $path . '/' . $filename; if ($props['type'] == NET_SFTP_TYPE_DIRECTORY) { - if (!$this->_chmod_recursive($mode, $temp, $i)) { + if (!$this->_setstat_recursive($temp, $attr, $i)) { return false; } } else { - $attr = pack('N2', NET_SFTP_ATTR_PERMISSIONS, $mode & 07777); if (!$this->_send_sftp_packet(NET_SFTP_SETSTAT, pack('Na*a*', strlen($temp), $temp, $attr))) { return false; } $i++; - if ($i >= 50) { + if ($i >= NET_SFTP_QUEUE_SIZE) { if (!$this->_read_put_responses($i)) { return false; } @@ -1184,14 +1296,13 @@ class Net_SFTP extends Net_SSH2 { } } - $attr = pack('N2', NET_SFTP_ATTR_PERMISSIONS, $mode & 07777); if (!$this->_send_sftp_packet(NET_SFTP_SETSTAT, pack('Na*a*', strlen($path), $path, $attr))) { return false; } $i++; - if ($i >= 50) { + if ($i >= NET_SFTP_QUEUE_SIZE) { if (!$this->_read_put_responses($i)) { return false; } @@ -1208,33 +1319,32 @@ class Net_SFTP extends Net_SSH2 { * @return Boolean * @access public */ - function mkdir($dir) + function mkdir($dir, $mode = -1, $recursive = false) { if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { return false; } - if ($dir[0] != '/') { - $dir = $this->_realpath(rtrim($dir, '/')); - if ($dir === false) { - return false; + $dir = $this->_realpath($dir); + // by not providing any permissions, hopefully the server will use the logged in users umask - their + // default permissions. + $attr = $mode == -1 ? "\0\0\0\0" : pack('N2', NET_SFTP_ATTR_PERMISSIONS, $mode & 07777); + + if ($recursive) { + $dirs = explode('/', preg_replace('#/(?=/)|/$#', '', $dir)); + if (empty($dirs[0])) { + array_shift($dirs); + $dirs[0] = '/' . $dirs[0]; } - if (!$this->_mkdir_helper($dir)) { - return false; - } - } else { - $dirs = explode('/', preg_replace('#^/|/(?=/)|/$#', '', $dir)); - $temp = ''; - foreach ($dirs as $dir) { - $temp.= '/' . $dir; - $result = $this->_mkdir_helper($temp); - } - if (!$result) { - return false; + for ($i = 0; $i < count($dirs); $i++) { + $temp = array_slice($dirs, 0, $i + 1); + $temp = implode('/', $temp); + $result = $this->_mkdir_helper($temp, $attr); } + return $result; } - return true; + return $this->_mkdir_helper($dir, $attr); } /** @@ -1244,11 +1354,9 @@ class Net_SFTP extends Net_SSH2 { * @return Boolean * @access private */ - function _mkdir_helper($dir) + function _mkdir_helper($dir, $attr) { - // by not providing any permissions, hopefully the server will use the logged in users umask - their - // default permissions. - if (!$this->_send_sftp_packet(NET_SFTP_MKDIR, pack('Na*N', strlen($dir), $dir, 0))) { + if (!$this->_send_sftp_packet(NET_SFTP_MKDIR, pack('Na*a*', strlen($dir), $dir, $attr))) { return false; } @@ -1323,14 +1431,33 @@ class Net_SFTP extends Net_SSH2 { * Currently, only binary mode is supported. As such, if the line endings need to be adjusted, you will need to take * care of that, yourself. * + * $mode can take an additional two parameters - NET_SFTP_RESUME and NET_SFTP_RESUME_START. These are bitwise AND'd with + * $mode. So if you want to resume upload of a 300mb file on the local file system you'd set $mode to the following: + * + * NET_SFTP_LOCAL_FILE | NET_SFTP_RESUME + * + * If you wanted to simply append the full contents of a local file to the full contents of a remote file you'd replace + * NET_SFTP_RESUME with NET_SFTP_RESUME_START. + * + * If $mode & (NET_SFTP_RESUME | NET_SFTP_RESUME_START) then NET_SFTP_RESUME_START will be assumed. + * + * $start and $local_start give you more fine grained control over this process and take precident over NET_SFTP_RESUME + * when they're non-negative. ie. $start could let you write at the end of a file (like NET_SFTP_RESUME) or in the middle + * of one. $local_start could let you start your reading from the end of a file (like NET_SFTP_RESUME_START) or in the + * middle of one. + * + * Setting $local_start to > 0 or $mode | NET_SFTP_RESUME_START doesn't do anything unless $mode | NET_SFTP_LOCAL_FILE. + * * @param String $remote_file * @param String $data * @param optional Integer $mode + * @param optional Integer $start + * @param optional Integer $local_start * @return Boolean * @access public * @internal ASCII mode for SFTPv4/5/6 can be supported by adding a new function - Net_SFTP::setMode(). */ - function put($remote_file, $data, $mode = NET_SFTP_STRING) + function put($remote_file, $data, $mode = NET_SFTP_STRING, $start = -1, $local_start = -1) { if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { return false; @@ -1346,15 +1473,16 @@ class Net_SFTP extends Net_SSH2 { // in practice, it doesn't seem to do that. //$flags|= ($mode & NET_SFTP_RESUME) ? NET_SFTP_OPEN_APPEND : NET_SFTP_OPEN_TRUNCATE; - // if NET_SFTP_OPEN_APPEND worked as it should the following (up until the -----------) wouldn't be necessary - $offset = 0; - if ($mode & NET_SFTP_RESUME) { + if ($start >= 0) { + $offset = $start; + } elseif ($mode & NET_SFTP_RESUME) { + // if NET_SFTP_OPEN_APPEND worked as it should _size() wouldn't need to be called $size = $this->_size($remote_file); $offset = $size !== false ? $size : 0; } else { + $offset = 0; $flags|= NET_SFTP_OPEN_TRUNCATE; } - // -------------- $packet = pack('Na*N2', strlen($remote_file), $remote_file, $flags, 0); if (!$this->_send_sftp_packet(NET_SFTP_OPEN, $packet)) { @@ -1387,6 +1515,14 @@ class Net_SFTP extends Net_SSH2 { return false; } $size = filesize($data); + + if ($local_start >= 0) { + fseek($fp, $local_start); + } elseif ($mode & NET_SFTP_RESUME_START) { + // do nothing + } else { + fseek($fp, $offset); + } } else { $size = strlen($data); } @@ -1395,10 +1531,13 @@ class Net_SFTP extends Net_SSH2 { $size = $size < 0 ? ($size & 0x7FFFFFFF) + 0x80000000 : $size; $sftp_packet_size = 4096; // PuTTY uses 4096 + // make the SFTP packet be exactly 4096 bytes by including the bytes in the NET_SFTP_WRITE packets "header" + $sftp_packet_size-= strlen($handle) + 25; $i = 0; while ($sent < $size) { - $temp = $mode & NET_SFTP_LOCAL_FILE ? fread($fp, $sftp_packet_size) : $this->_string_shift($data, $sftp_packet_size); - $packet = pack('Na*N3a*', strlen($handle), $handle, 0, $offset + $sent, strlen($temp), $temp); + $temp = $mode & NET_SFTP_LOCAL_FILE ? fread($fp, $sftp_packet_size) : substr($data, $sent, $sftp_packet_size); + $subtemp = $offset + $sent; + $packet = pack('Na*N3a*', strlen($handle), $handle, $subtemp / 0x100000000, $subtemp, strlen($temp), $temp); if (!$this->_send_sftp_packet(NET_SFTP_WRITE, $packet)) { fclose($fp); return false; @@ -1407,7 +1546,7 @@ class Net_SFTP extends Net_SSH2 { $i++; - if ($i == 50) { + if ($i == NET_SFTP_QUEUE_SIZE) { if (!$this->_read_put_responses($i)) { $i = 0; break; @@ -1417,6 +1556,10 @@ class Net_SFTP extends Net_SSH2 { } if (!$this->_read_put_responses($i)) { + if ($mode & NET_SFTP_LOCAL_FILE) { + fclose($fp); + } + $this->_close_handle($handle); return false; } @@ -1424,23 +1567,7 @@ class Net_SFTP extends Net_SSH2 { fclose($fp); } - if (!$this->_send_sftp_packet(NET_SFTP_CLOSE, pack('Na*', strlen($handle), $handle))) { - return false; - } - - $response = $this->_get_sftp_packet(); - if ($this->packet_type != NET_SFTP_STATUS) { - user_error('Expected SSH_FXP_STATUS'); - return false; - } - - extract(unpack('Nstatus', $this->_string_shift($response, 4))); - if ($status != NET_SFTP_STATUS_OK) { - $this->_logError($response, $status); - return false; - } - - return true; + return $this->_close_handle($handle); } /** @@ -1472,15 +1599,49 @@ class Net_SFTP extends Net_SSH2 { return $i < 0; } + /** + * Close handle + * + * @param String $handle + * @return Boolean + * @access private + */ + function _close_handle($handle) + { + if (!$this->_send_sftp_packet(NET_SFTP_CLOSE, pack('Na*', strlen($handle), $handle))) { + return false; + } + + // "The client MUST release all resources associated with the handle regardless of the status." + // -- http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.1.3 + $response = $this->_get_sftp_packet(); + if ($this->packet_type != NET_SFTP_STATUS) { + user_error('Expected SSH_FXP_STATUS'); + return false; + } + + extract(unpack('Nstatus', $this->_string_shift($response, 4))); + if ($status != NET_SFTP_STATUS_OK) { + $this->_logError($response, $status); + return false; + } + + return true; + } + /** * Downloads a file from the SFTP server. * * Returns a string containing the contents of $remote_file if $local_file is left undefined or a boolean false if * the operation was unsuccessful. If $local_file is defined, returns true or false depending on the success of the - * operation + * operation. + * + * $offset and $length can be used to download files in chunks. * * @param String $remote_file * @param optional String $local_file + * @param optional Integer $offset + * @param optional Integer $length * @return Mixed * @access public */ @@ -1522,10 +1683,9 @@ class Net_SFTP extends Net_SSH2 { $content = ''; } - $size = (1 << 20) < $length || $length < 0 ? 1 << 20 : $length; - $start = $offset; + $size = $this->max_sftp_packet < $length || $length < 0 ? $this->max_sftp_packet : $length; while (true) { - $packet = pack('Na*N3', strlen($handle), $handle, 0, $offset, $size); + $packet = pack('Na*N3', strlen($handle), $handle, $offset / 0x100000000, $offset, $size); if (!$this->_send_sftp_packet(NET_SFTP_READ, $packet)) { if ($local_file !== false) { fclose($fp); @@ -1545,6 +1705,7 @@ class Net_SFTP extends Net_SSH2 { } break; case NET_SFTP_STATUS: + // could, in theory, return false if !strlen($content) but we'll hold off for the time being $this->_logError($response); break 2; default: @@ -1556,40 +1717,28 @@ class Net_SFTP extends Net_SSH2 { } if ($length > 0 && $length <= $offset - $size) { - if ($local_file === false) { - $content = substr($content, 0, $length); - } else { - ftruncate($fp, $length); - } break; } } + if ($length > 0 && $length <= $offset - $size) { + if ($local_file === false) { + $content = substr($content, 0, $length); + } else { + ftruncate($fp, $length); + } + } + if ($local_file !== false) { fclose($fp); } - if (!$this->_send_sftp_packet(NET_SFTP_CLOSE, pack('Na*', strlen($handle), $handle))) { + if (!$this->_close_handle($handle)) { return false; } - $response = $this->_get_sftp_packet(); - if ($this->packet_type != NET_SFTP_STATUS) { - user_error('Expected SSH_FXP_STATUS'); - return false; - } - - extract(unpack('Nstatus', $this->_string_shift($response, 4))); - if ($status != NET_SFTP_STATUS_OK) { - $this->_logError($response, $status); - return false; - } - - if (isset($content)) { - return $content; - } - - return true; + // if $content isn't set that means a file was written to + return isset($content) ? $content : true; } /** @@ -1683,7 +1832,7 @@ class Net_SFTP extends Net_SSH2 { $i++; - if ($i >= 50) { + if ($i >= NET_SFTP_QUEUE_SIZE) { if (!$this->_read_put_responses($i)) { return false; } @@ -1699,7 +1848,7 @@ class Net_SFTP extends Net_SSH2 { $i++; - if ($i >= 50) { + if ($i >= NET_SFTP_QUEUE_SIZE) { if (!$this->_read_put_responses($i)) { return false; } @@ -1774,17 +1923,21 @@ class Net_SFTP extends Net_SSH2 { // (0xFFFFFFFF bytes), anyway. as such, we'll just represent all file sizes that are bigger than // 4GB as being 4GB. extract(unpack('Nupper/Nsize', $this->_string_shift($response, 8))); - if ($upper) { - $attr['size'] = 0xFFFFFFFF; - } else { - $attr['size'] = $size < 0 ? ($size & 0x7FFFFFFF) + 0x80000000 : $size; - } + $attr['size'] = $upper ? 0x100000000 * $upper : 0; + $attr['size']+= $size < 0 ? ($size & 0x7FFFFFFF) + 0x80000000 : $size; break; case NET_SFTP_ATTR_UIDGID: // 0x00000002 (SFTPv3 only) $attr+= unpack('Nuid/Ngid', $this->_string_shift($response, 8)); break; case NET_SFTP_ATTR_PERMISSIONS: // 0x00000004 $attr+= unpack('Npermissions', $this->_string_shift($response, 4)); + // mode == permissions; permissions was the original array key and is retained for bc purposes. + // mode was added because that's the more industry standard terminology + $attr+= array('mode' => $attr['permissions']); + $fileType = $this->_parseMode($attr['permissions']); + if ($fileType !== false) { + $attr+= array('type' => $fileType); + } break; case NET_SFTP_ATTR_ACCESSTIME: // 0x00000008 $attr+= unpack('Natime/Nmtime', $this->_string_shift($response, 8)); @@ -1802,6 +1955,47 @@ class Net_SFTP extends Net_SSH2 { return $attr; } + /** + * Attempt to identify the file type + * + * Quoting the SFTP RFC, "Implementations MUST NOT send bits that are not defined" but they seem to anyway + * + * @param Integer $mode + * @return Integer + * @access private + */ + function _parseMode($mode) + { + // values come from http://lxr.free-electrons.com/source/include/uapi/linux/stat.h#L12 + // see, also, http://linux.die.net/man/2/stat + switch ($mode & 0170000) {// ie. 1111 0000 0000 0000 + case 0000000: // no file type specified - figure out the file type using alternative means + return false; + case 0040000: + return NET_SFTP_TYPE_DIRECTORY; + case 0100000: + return NET_SFTP_TYPE_REGULAR; + case 0120000: + return NET_SFTP_TYPE_SYMLINK; + // new types introduced in SFTPv5+ + // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-05#section-5.2 + case 0010000: // named pipe (fifo) + return NET_SFTP_TYPE_FIFO; + case 0020000: // character special + return NET_SFTP_TYPE_CHAR_DEVICE; + case 0060000: // block special + return NET_SFTP_BLOCK_DEVICE; + case 0140000: // socket + return NET_SFTP_TYPE_SOCKET; + case 0160000: // whiteout + // "SPECIAL should be used for files that are of + // a known type which cannot be expressed in the protocol" + return NET_SFTP_TYPE_SPECIAL; + default: + return NET_SFTP_TYPE_UNKNOWN; + } + } + /** * Parse Longname * @@ -2026,4 +2220,4 @@ class Net_SFTP extends Net_SSH2 { $this->pwd = false; parent::_disconnect($reason); } -} \ No newline at end of file +} diff --git a/apps/files_external/3rdparty/phpseclib/phpseclib/Net/SFTP/Stream.php b/apps/files_external/3rdparty/phpseclib/phpseclib/Net/SFTP/Stream.php new file mode 100644 index 0000000000..0572c5c402 --- /dev/null +++ b/apps/files_external/3rdparty/phpseclib/phpseclib/Net/SFTP/Stream.php @@ -0,0 +1,771 @@ + + * @copyright MMXIII Jim Wigginton + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @link http://phpseclib.sourceforge.net + */ + +/** + * SFTP Stream Wrapper + * + * @author Jim Wigginton + * @version 0.3.2 + * @access public + * @package Net_SFTP_Stream + */ +class Net_SFTP_Stream { + /** + * SFTP instances + * + * Rather than re-create the connection we re-use instances if possible + * + * @var Array + * @access static + */ + static $instances; + + /** + * SFTP instance + * + * @var Object + * @access private + */ + var $sftp; + + /** + * Path + * + * @var String + * @access private + */ + var $path; + + /** + * Mode + * + * @var String + * @access private + */ + var $mode; + + /** + * Position + * + * @var Integer + * @access private + */ + var $pos; + + /** + * Size + * + * @var Integer + * @access private + */ + var $size; + + /** + * Directory entries + * + * @var Array + * @access private + */ + var $entries; + + /** + * EOF flag + * + * @var Boolean + * @access private + */ + var $eof; + + /** + * Context resource + * + * Technically this needs to be publically accessible so PHP can set it directly + * + * @var Resource + * @access public + */ + var $context; + + /** + * Notification callback function + * + * @var Callable + * @access public + */ + var $notification; + + /** + * The Constructor + * + * @access public + */ + function Net_SFTP_Stream() + { + if (!class_exists('Net_SFTP')) { + require_once('Net/SFTP.php'); + } + } + + /** + * Path Parser + * + * Extract a path from a URI and actually connect to an SSH server if appropriate + * + * If "notification" is set as a context parameter the message code for successful login is + * NET_SSH2_MSG_USERAUTH_SUCCESS. For a failed login it's NET_SSH2_MSG_USERAUTH_FAILURE. + * + * @param String $path + * @return String + * @access private + */ + function _parse_path($path) + { + extract(parse_url($path) + array('port' => 22)); + + if (!isset($host)) { + return false; + } + + if (isset($this->context)) { + $context = stream_context_get_params($this->context); + if (isset($context['notification'])) { + $this->notification = $context['notification']; + } + } + + if ($host[0] == '$') { + $host = substr($host, 1); + global $$host; + if (!is_object($$host) || get_class($$host) != 'Net_SFTP') { + return false; + } + $this->sftp = $$host; + } else { + if (isset($this->context)) { + $context = stream_context_get_options($this->context); + } + if (isset($context['sftp']['session'])) { + $sftp = $context['sftp']['session']; + } + if (isset($context['sftp']['sftp'])) { + $sftp = $context['sftp']['sftp']; + } + if (isset($sftp) && is_object($sftp) && get_class($sftp) == 'Net_SFTP') { + $this->sftp = $sftp; + return $path; + } + if (isset($context['sftp']['username'])) { + $user = $context['sftp']['username']; + } + if (isset($context['sftp']['password'])) { + $pass = $context['sftp']['password']; + } + if (isset($context['sftp']['privkey']) && is_object($context['sftp']['privkey']) && get_Class($context['sftp']['privkey']) == 'Crypt_RSA') { + $pass = $context['sftp']['privkey']; + } + + if (!isset($user) || !isset($pass)) { + return false; + } + + // casting $pass to a string is necessary in the event that it's a Crypt_RSA object + if (isset(self::$instances[$host][$port][$user][(string) $pass])) { + $this->sftp = self::$instances[$host][$port][$user][(string) $pass]; + } else { + $this->sftp = new Net_SFTP($host, $port); + if (isset($this->notification) && is_callable($this->notification)) { + /* if !is_callable($this->notification) we could do this: + + user_error('fopen(): failed to call user notifier', E_USER_WARNING); + + the ftp wrapper gives errors like that when the notifier isn't callable. + i've opted not to do that, however, since the ftp wrapper gives the line + on which the fopen occurred as the line number - not the line that the + user_error is on. + */ + call_user_func($this->notification, STREAM_NOTIFY_CONNECT, STREAM_NOTIFY_SEVERITY_INFO, '', 0, 0, 0); + call_user_func($this->notification, STREAM_NOTIFY_AUTH_REQUIRED, STREAM_NOTIFY_SEVERITY_INFO, '', 0, 0, 0); + if (!$this->sftp->login($user, $pass)) { + call_user_func($this->notification, STREAM_NOTIFY_AUTH_RESULT, STREAM_NOTIFY_SEVERITY_ERR, 'Login Failure', NET_SSH2_MSG_USERAUTH_FAILURE, 0, 0); + return false; + } + call_user_func($this->notification, STREAM_NOTIFY_AUTH_RESULT, STREAM_NOTIFY_SEVERITY_INFO, 'Login Success', NET_SSH2_MSG_USERAUTH_SUCCESS, 0, 0); + } else { + if (!$this->sftp->login($user, $pass)) { + return false; + } + } + self::$instances[$host][$port][$user][(string) $pass] = $this->sftp; + } + } + + return $path; + } + + /** + * Opens file or URL + * + * @param String $path + * @param String $mode + * @param Integer $options + * @param String $opened_path + * @return Boolean + * @access public + */ + function _stream_open($path, $mode, $options, &$opened_path) + { + $path = $this->_parse_path($path); + + if ($path === false) { + return false; + } + $this->path = $path; + + $this->size = $this->sftp->size($path); + $this->mode = preg_replace('#[bt]$#', '', $mode); + $this->eof = false; + + if ($this->size === false) { + if ($this->mode[0] == 'r') { + return false; + } + } else { + switch ($this->mode[0]) { + case 'x': + return false; + case 'w': + case 'c': + $this->sftp->truncate($path, 0); + } + } + + $this->pos = $this->mode[0] != 'a' ? 0 : $this->size; + + return true; + } + + /** + * Read from stream + * + * @param Integer $count + * @return Mixed + * @access public + */ + function _stream_read($count) + { + switch ($this->mode) { + case 'w': + case 'a': + case 'x': + case 'c': + return false; + } + + // commented out because some files - eg. /dev/urandom - will say their size is 0 when in fact it's kinda infinite + //if ($this->pos >= $this->size) { + // $this->eof = true; + // return false; + //} + + $result = $this->sftp->get($this->path, false, $this->pos, $count); + if (isset($this->notification) && is_callable($this->notification)) { + if ($result === false) { + call_user_func($this->notification, STREAM_NOTIFY_FAILURE, STREAM_NOTIFY_SEVERITY_ERR, $this->sftp->getLastSFTPError(), NET_SFTP_OPEN, 0, 0); + return 0; + } + // seems that PHP calls stream_read in 8k chunks + call_user_func($this->notification, STREAM_NOTIFY_PROGRESS, STREAM_NOTIFY_SEVERITY_INFO, '', 0, strlen($result), $this->size); + } + + if (empty($result)) { // ie. false or empty string + $this->eof = true; + return false; + } + $this->pos+= strlen($result); + + return $result; + } + + /** + * Write to stream + * + * @param String $data + * @return Mixed + * @access public + */ + function _stream_write($data) + { + switch ($this->mode) { + case 'r': + return false; + } + + $result = $this->sftp->put($this->path, $data, NET_SFTP_STRING, $this->pos); + if (isset($this->notification) && is_callable($this->notification)) { + if (!$result) { + call_user_func($this->notification, STREAM_NOTIFY_FAILURE, STREAM_NOTIFY_SEVERITY_ERR, $this->sftp->getLastSFTPError(), NET_SFTP_OPEN, 0, 0); + return 0; + } + // seems that PHP splits up strings into 8k blocks before calling stream_write + call_user_func($this->notification, STREAM_NOTIFY_PROGRESS, STREAM_NOTIFY_SEVERITY_INFO, '', 0, strlen($data), strlen($data)); + } + + if ($result === false) { + return false; + } + $this->pos+= strlen($data); + if ($this->pos > $this->size) { + $this->size = $this->pos; + } + $this->eof = false; + return strlen($data); + } + + /** + * Retrieve the current position of a stream + * + * @return Integer + * @access public + */ + function _stream_tell() + { + return $this->pos; + } + + /** + * Tests for end-of-file on a file pointer + * + * In my testing there are four classes functions that normally effect the pointer: + * fseek, fputs / fwrite, fgets / fread and ftruncate. + * + * Only fgets / fread, however, results in feof() returning true. do fputs($fp, 'aaa') on a blank file and feof() + * will return false. do fread($fp, 1) and feof() will then return true. do fseek($fp, 10) on ablank file and feof() + * will return false. do fread($fp, 1) and feof() will then return true. + * + * @return Boolean + * @access public + */ + function _stream_eof() + { + return $this->eof; + } + + /** + * Seeks to specific location in a stream + * + * @param Integer $offset + * @param Integer $whence + * @return Boolean + * @access public + */ + function _stream_seek($offset, $whence) + { + switch ($whence) { + case SEEK_SET: + if ($offset >= $this->size || $offset < 0) { + return false; + } + break; + case SEEK_CUR: + $offset+= $this->pos; + break; + case SEEK_END: + $offset+= $this->size; + } + + $this->pos = $offset; + $this->eof = false; + return true; + } + + /** + * Change stream options + * + * @param String $path + * @param Integer $option + * @param Mixed $var + * @return Boolean + * @access public + */ + function _stream_metadata($path, $option, $var) + { + $path = $this->_parse_path($path); + if ($path === false) { + return false; + } + + // stream_metadata was introduced in PHP 5.4.0 but as of 5.4.11 the constants haven't been defined + // see http://www.php.net/streamwrapper.stream-metadata and https://bugs.php.net/64246 + // and https://github.com/php/php-src/blob/master/main/php_streams.h#L592 + switch ($option) { + case 1: // PHP_STREAM_META_TOUCH + return $this->sftp->touch($path, $var[0], $var[1]); + case 2: // PHP_STREAM_OWNER_NAME + case 3: // PHP_STREAM_GROUP_NAME + return false; + case 4: // PHP_STREAM_META_OWNER + return $this->sftp->chown($path, $var); + case 5: // PHP_STREAM_META_GROUP + return $this->sftp->chgrp($path, $var); + case 6: // PHP_STREAM_META_ACCESS + return $this->sftp->chmod($path, $var) !== false; + } + } + + /** + * Retrieve the underlaying resource + * + * @param Integer $cast_as + * @return Resource + * @access public + */ + function _stream_cast($cast_as) + { + return $this->sftp->fsock; + } + + /** + * Advisory file locking + * + * @param Integer $operation + * @return Boolean + * @access public + */ + function _stream_lock($operation) + { + return false; + } + + /** + * Renames a file or directory + * + * Attempts to rename oldname to newname, moving it between directories if necessary. + * If newname exists, it will be overwritten. This is a departure from what Net_SFTP + * does. + * + * @param String $path_from + * @param String $path_to + * @return Boolean + * @access public + */ + function _rename($path_from, $path_to) + { + $path1 = parse_url($path_from); + $path2 = parse_url($path_to); + unset($path1['path'], $path2['path']); + if ($path1 != $path2) { + return false; + } + + $path_from = $this->_parse_path($path_from); + $path_to = parse_url($path_to); + if ($path_from == false) { + return false; + } + + $path_to = $path_to['path']; // the $component part of parse_url() was added in PHP 5.1.2 + // "It is an error if there already exists a file with the name specified by newpath." + // -- http://tools.ietf.org/html/draft-ietf-secsh-filexfer-02#section-6.5 + if (!$this->sftp->rename($path_from, $path_to)) { + if ($this->sftp->stat($path_to)) { + return $this->sftp->delete($path_to, true) && $this->sftp->rename($path_from, $path_to); + } + return false; + } + + return true; + } + + /** + * Open directory handle + * + * The only $options is "whether or not to enforce safe_mode (0x04)". Since safe mode was deprecated in 5.3 and + * removed in 5.4 I'm just going to ignore it + * + * @param String $path + * @param Integer $options + * @return Boolean + * @access public + */ + function _dir_opendir($path, $options) + { + $path = $this->_parse_path($path); + if ($path === false) { + return false; + } + $this->pos = 0; + $this->entries = $this->sftp->nlist($path); + return $this->entries !== false; + } + + /** + * Read entry from directory handle + * + * @return Mixed + * @access public + */ + function _dir_readdir() + { + if (isset($this->entries[$this->pos])) { + return $this->entries[$this->pos++]; + } + return false; + } + + /** + * Rewind directory handle + * + * @return Boolean + * @access public + */ + function _dir_rewinddir() + { + $this->pos = 0; + return true; + } + + /** + * Close directory handle + * + * @return Boolean + * @access public + */ + function _dir_closedir() + { + return true; + } + + /** + * Create a directory + * + * Only valid $options is STREAM_MKDIR_RECURSIVE + * + * @param String $path + * @param Integer $mode + * @param Integer $options + * @return Boolean + * @access public + */ + function _mkdir($path, $mode, $options) + { + $path = $this->_parse_path($path); + if ($path === false) { + return false; + } + + return $this->sftp->mkdir($path, $mode, $options & STREAM_MKDIR_RECURSIVE); + } + + /** + * Removes a directory + * + * Only valid $options is STREAM_MKDIR_RECURSIVE per , however, + * does not have a $recursive parameter as mkdir() does so I don't know how + * STREAM_MKDIR_RECURSIVE is supposed to be set. Also, when I try it out with rmdir() I get 8 as + * $options. What does 8 correspond to? + * + * @param String $path + * @param Integer $mode + * @param Integer $options + * @return Boolean + * @access public + */ + function _rmdir($path, $options) + { + $path = $this->_parse_path($path); + if ($path === false) { + return false; + } + + return $this->sftp->rmdir($path); + } + + /** + * Flushes the output + * + * See . Always returns true because Net_SFTP doesn't cache stuff before writing + * + * @return Boolean + * @access public + */ + function _stream_flush() + { + return true; + } + + /** + * Retrieve information about a file resource + * + * @return Mixed + * @access public + */ + function _stream_stat() + { + $results = $this->sftp->stat($this->path); + if ($results === false) { + return false; + } + return $results; + } + + /** + * Delete a file + * + * @param String $path + * @return Boolean + * @access public + */ + function _unlink($path) + { + $path = $this->_parse_path($path); + if ($path === false) { + return false; + } + + return $this->sftp->delete($path, false); + } + + /** + * Retrieve information about a file + * + * Ignores the STREAM_URL_STAT_QUIET flag because the entirety of Net_SFTP_Stream is quiet by default + * might be worthwhile to reconstruct bits 12-16 (ie. the file type) if mode doesn't have them but we'll + * cross that bridge when and if it's reached + * + * @param String $path + * @param Integer $flags + * @return Mixed + * @access public + */ + function _url_stat($path, $flags) + { + $path = $this->_parse_path($path); + if ($path === false) { + return false; + } + + $results = $flags & STREAM_URL_STAT_LINK ? $this->sftp->lstat($path) : $this->sftp->stat($path); + if ($results === false) { + return false; + } + + return $results; + } + + /** + * Truncate stream + * + * @param Integer $new_size + * @return Boolean + * @access public + */ + function _stream_truncate($new_size) + { + if (!$this->sftp->truncate($this->path, $new_size)) { + return false; + } + + $this->eof = false; + $this->size = $new_size; + + return true; + } + + /** + * Change stream options + * + * STREAM_OPTION_WRITE_BUFFER isn't supported for the same reason stream_flush isn't. + * The other two aren't supported because of limitations in Net_SFTP. + * + * @param Integer $option + * @param Integer $arg1 + * @param Integer $arg2 + * @return Boolean + * @access public + */ + function _stream_set_option($option, $arg1, $arg2) + { + return false; + } + + /** + * Close an resource + * + * @access public + */ + function _stream_close() + { + } + + /** + * __call Magic Method + * + * When you're utilizing an SFTP stream you're not calling the methods in this class directly - PHP is calling them for you. + * Which kinda begs the question... what methods is PHP calling and what parameters is it passing to them? This function + * lets you figure that out. + * + * If NET_SFTP_STREAM_LOGGING is defined all calls will be output on the screen and then (regardless of whether or not + * NET_SFTP_STREAM_LOGGING is enabled) the parameters will be passed through to the appropriate method. + * + * @param String + * @param Array + * @return Mixed + * @access public + */ + function __call($name, $arguments) + { + if (defined('NET_SFTP_STREAM_LOGGING')) { + echo $name . '('; + $last = count($arguments) - 1; + foreach ($arguments as $i => $argument) { + var_export($argument); + if ($i != $last) { + echo ','; + } + } + echo ")\r\n"; + } + $name = '_' . $name; + if (!method_exists($this, $name)) { + return false; + } + return call_user_func_array(array($this, $name), $arguments); + } +} + +if (function_exists('stream_wrapper_register')) { + stream_wrapper_register('sftp', 'Net_SFTP_Stream'); +} diff --git a/apps/files_external/3rdparty/phpseclib/phpseclib/Net/SSH1.php b/apps/files_external/3rdparty/phpseclib/phpseclib/Net/SSH1.php index 8f5c79938e..83d5980d00 100644 --- a/apps/files_external/3rdparty/phpseclib/phpseclib/Net/SSH1.php +++ b/apps/files_external/3rdparty/phpseclib/phpseclib/Net/SSH1.php @@ -62,56 +62,9 @@ * @author Jim Wigginton * @copyright MMVII Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @version $Id: SSH1.php,v 1.15 2010/03/22 22:01:38 terrafrost Exp $ * @link http://phpseclib.sourceforge.net */ -/** - * Include Math_BigInteger - * - * Used to do RSA encryption. - */ -if (!class_exists('Math_BigInteger')) { - require_once('Math/BigInteger.php'); -} - -/** - * Include Crypt_Null - */ -//require_once('Crypt/Null.php'); - -/** - * Include Crypt_DES - */ -if (!class_exists('Crypt_DES')) { - require_once('Crypt/DES.php'); -} - -/** - * Include Crypt_TripleDES - */ -if (!class_exists('Crypt_TripleDES')) { - require_once('Crypt/TripleDES.php'); -} - -/** - * Include Crypt_RC4 - */ -if (!class_exists('Crypt_RC4')) { - require_once('Crypt/RC4.php'); -} - -/** - * Include Crypt_Random - */ -// the class_exists() will only be called if the crypt_random_string function hasn't been defined and -// will trigger a call to __autoload() if you're wanting to auto-load classes -// call function_exists() a second time to stop the require_once from being called outside -// of the auto loader -if (!function_exists('crypt_random_string') && !class_exists('Crypt_Random') && !function_exists('crypt_random_string')) { - require_once('Crypt/Random.php'); -} - /**#@+ * Encryption Methods * @@ -495,6 +448,19 @@ class Net_SSH1 { */ function Net_SSH1($host, $port = 22, $timeout = 10, $cipher = NET_SSH1_CIPHER_3DES) { + if (!class_exists('Math_BigInteger')) { + require_once('Math/BigInteger.php'); + } + + // Include Crypt_Random + // the class_exists() will only be called if the crypt_random_string function hasn't been defined and + // will trigger a call to __autoload() if you're wanting to auto-load classes + // call function_exists() a second time to stop the require_once from being called outside + // of the auto loader + if (!function_exists('crypt_random_string') && !class_exists('Crypt_Random') && !function_exists('crypt_random_string')) { + require_once('Crypt/Random.php'); + } + $this->protocol_flags = array( 1 => 'NET_SSH1_MSG_DISCONNECT', 2 => 'NET_SSH1_SMSG_PUBLIC_KEY', @@ -636,18 +602,27 @@ class Net_SSH1 { // $this->crypto = new Crypt_Null(); // break; case NET_SSH1_CIPHER_DES: + if (!class_exists('Crypt_DES')) { + require_once('Crypt/DES.php'); + } $this->crypto = new Crypt_DES(); $this->crypto->disablePadding(); $this->crypto->enableContinuousBuffer(); $this->crypto->setKey(substr($session_key, 0, 8)); break; case NET_SSH1_CIPHER_3DES: + if (!class_exists('Crypt_TripleDES')) { + require_once('Crypt/TripleDES.php'); + } $this->crypto = new Crypt_TripleDES(CRYPT_DES_MODE_3CBC); $this->crypto->disablePadding(); $this->crypto->enableContinuousBuffer(); $this->crypto->setKey(substr($session_key, 0, 24)); break; //case NET_SSH1_CIPHER_RC4: + // if (!class_exists('Crypt_RC4')) { + // require_once('Crypt/RC4.php'); + // } // $this->crypto = new Crypt_RC4(); // $this->crypto->enableContinuousBuffer(); // $this->crypto->setKey(substr($session_key, 0, 16)); @@ -935,7 +910,7 @@ class Net_SSH1 { * Returns the output of an interactive shell when no more output is available. * * Requires PHP 4.3.0 or later due to the use of the stream_select() function. If you see stuff like - * "", you're seeing ANSI escape codes. According to + * "^[[00m", you're seeing ANSI escape codes. According to * {@link http://support.microsoft.com/kb/101875 How to Enable ANSI.SYS in a Command Window}, "Windows NT * does not support ANSI escape sequences in Win32 Console applications", so if you're a Windows user, * there's not going to be much recourse. @@ -1574,4 +1549,4 @@ class Net_SSH1 { fputs($this->realtime_log_file, $entry); } } -} \ No newline at end of file +} diff --git a/apps/files_external/3rdparty/phpseclib/phpseclib/Net/SSH2.php b/apps/files_external/3rdparty/phpseclib/phpseclib/Net/SSH2.php index 43bfbca2db..dad0369723 100644 --- a/apps/files_external/3rdparty/phpseclib/phpseclib/Net/SSH2.php +++ b/apps/files_external/3rdparty/phpseclib/phpseclib/Net/SSH2.php @@ -64,67 +64,20 @@ * @author Jim Wigginton * @copyright MMVII Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @version $Id: SSH2.php,v 1.53 2010-10-24 01:24:30 terrafrost Exp $ * @link http://phpseclib.sourceforge.net */ -/** - * Include Math_BigInteger - * - * Used to do Diffie-Hellman key exchange and DSA/RSA signature verification. - */ -if (!class_exists('Math_BigInteger')) { - require_once('Math/BigInteger.php'); -} - -/** - * Include Crypt_Random - */ -// the class_exists() will only be called if the crypt_random_string function hasn't been defined and -// will trigger a call to __autoload() if you're wanting to auto-load classes -// call function_exists() a second time to stop the require_once from being called outside -// of the auto loader -if (!function_exists('crypt_random_string') && !class_exists('Crypt_Random') && !function_exists('crypt_random_string')) { - require_once('Crypt/Random.php'); -} - -/** - * Include Crypt_Hash - */ -if (!class_exists('Crypt_Hash')) { - require_once('Crypt/Hash.php'); -} - -/** - * Include Crypt_TripleDES - */ -if (!class_exists('Crypt_TripleDES')) { - require_once('Crypt/TripleDES.php'); -} - -/** - * Include Crypt_RC4 - */ -if (!class_exists('Crypt_RC4')) { - require_once('Crypt/RC4.php'); -} - -/** - * Include Crypt_AES - */ -if (!class_exists('Crypt_AES')) { - require_once('Crypt/AES.php'); -} - /**#@+ * Execution Bitmap Masks * * @see Net_SSH2::bitmap * @access private */ -define('NET_SSH2_MASK_CONSTRUCTOR', 0x00000001); -define('NET_SSH2_MASK_LOGIN', 0x00000002); -define('NET_SSH2_MASK_SHELL', 0x00000004); +define('NET_SSH2_MASK_CONSTRUCTOR', 0x00000001); +define('NET_SSH2_MASK_LOGIN_REQ', 0x00000002); +define('NET_SSH2_MASK_LOGIN', 0x00000004); +define('NET_SSH2_MASK_SHELL', 0x00000008); +define('NET_SSH2_MASK_WINDOW_ADJUST', 0X00000010); /**#@-*/ /**#@+ @@ -143,8 +96,9 @@ define('NET_SSH2_MASK_SHELL', 0x00000004); * @see Net_SSH2::_get_channel_packet() * @access private */ -define('NET_SSH2_CHANNEL_EXEC', 0); // PuTTy uses 0x100 -define('NET_SSH2_CHANNEL_SHELL',1); +define('NET_SSH2_CHANNEL_EXEC', 0); // PuTTy uses 0x100 +define('NET_SSH2_CHANNEL_SHELL', 1); +define('NET_SSH2_CHANNEL_SUBSYSTEM', 2); /**#@-*/ /**#@+ @@ -580,7 +534,7 @@ class Net_SSH2 { /** * The Window Size * - * Bytes the other party can send before it must wait for the window to be adjusted (0x7FFFFFFF = 4GB) + * Bytes the other party can send before it must wait for the window to be adjusted (0x7FFFFFFF = 2GB) * * @var Integer * @see Net_SSH2::_send_channel_packet() @@ -590,7 +544,7 @@ class Net_SSH2 { var $window_size = 0x7FFFFFFF; /** - * Window size + * Window size, server to client * * Window size indexed by channel * @@ -598,6 +552,17 @@ class Net_SSH2 { * @var Array * @access private */ + var $window_size_server_to_client = array(); + + /** + * Window size, client to server + * + * Window size indexed by channel + * + * @see Net_SSH2::_get_channel_packet() + * @var Array + * @access private + */ var $window_size_client_to_server = array(); /** @@ -717,6 +682,71 @@ class Net_SSH2 { */ var $exit_status; + /** + * Flag to request a PTY when using exec() + * + * @see Net_SSH2::enablePTY() + * @access private + */ + var $request_pty = false; + + /** + * Flag set while exec() is running when using enablePTY() + * + * @access private + */ + var $in_request_pty_exec = false; + + /** + * Flag set after startSubsystem() is called + * + * @access private + */ + var $in_subsystem; + + /** + * Contents of stdError + * + * @access private + */ + var $stdErrorLog; + + /** + * The Last Interactive Response + * + * @see Net_SSH2::_keyboard_interactive_process() + * @access private + */ + var $last_interactive_response = ''; + + /** + * Keyboard Interactive Request / Responses + * + * @see Net_SSH2::_keyboard_interactive_process() + * @access private + */ + var $keyboard_requests_responses = array(); + + /** + * Banner Message + * + * Quoting from the RFC, "in some jurisdictions, sending a warning message before + * authentication may be relevant for getting legal protection." + * + * @see Net_SSH2::_filter() + * @see Net_SSH2::getBannerMessage() + * @access private + */ + var $banner_message = ''; + + /** + * Did read() timeout or return normally? + * + * @see Net_SSH2::isTimeout + * @access private + */ + var $is_timeout = false; + /** * Default Constructor. * @@ -730,6 +760,20 @@ class Net_SSH2 { */ function Net_SSH2($host, $port = 22, $timeout = 10) { + // Include Math_BigInteger + // Used to do Diffie-Hellman key exchange and DSA/RSA signature verification. + if (!class_exists('Math_BigInteger')) { + require_once('Math/BigInteger.php'); + } + + if (!function_exists('crypt_random_string')) { + require_once('Crypt/Random.php'); + } + + if (!class_exists('Crypt_Hash')) { + require_once('Crypt/Hash.php'); + } + $this->last_packet = strtok(microtime(), ' ') + strtok(''); // == microtime(true) in PHP5 $this->message_numbers = array( 1 => 'NET_SSH2_MSG_DISCONNECT', @@ -918,26 +962,76 @@ class Net_SSH2 { 'ssh-dss' // REQUIRED sign Raw DSS Key ); - static $encryption_algorithms = array( - // from : - 'arcfour256', - 'arcfour128', + static $encryption_algorithms = false; + if ($encryption_algorithms === false) { + $encryption_algorithms = array( + // from : + 'arcfour256', + 'arcfour128', - 'arcfour', // OPTIONAL the ARCFOUR stream cipher with a 128-bit key + 'arcfour', // OPTIONAL the ARCFOUR stream cipher with a 128-bit key - 'aes128-cbc', // RECOMMENDED AES with a 128-bit key - 'aes192-cbc', // OPTIONAL AES with a 192-bit key - 'aes256-cbc', // OPTIONAL AES in CBC mode, with a 256-bit key + // CTR modes from : + 'aes128-ctr', // RECOMMENDED AES (Rijndael) in SDCTR mode, with 128-bit key + 'aes192-ctr', // RECOMMENDED AES with 192-bit key + 'aes256-ctr', // RECOMMENDED AES with 256-bit key - // from : - 'aes128-ctr', // RECOMMENDED AES (Rijndael) in SDCTR mode, with 128-bit key - 'aes192-ctr', // RECOMMENDED AES with 192-bit key - 'aes256-ctr', // RECOMMENDED AES with 256-bit key - '3des-ctr', // RECOMMENDED Three-key 3DES in SDCTR mode + 'twofish128-ctr', // OPTIONAL Twofish in SDCTR mode, with 128-bit key + 'twofish192-ctr', // OPTIONAL Twofish with 192-bit key + 'twofish256-ctr', // OPTIONAL Twofish with 256-bit key - '3des-cbc', // REQUIRED three-key 3DES in CBC mode - 'none' // OPTIONAL no encryption; NOT RECOMMENDED - ); + 'aes128-cbc', // RECOMMENDED AES with a 128-bit key + 'aes192-cbc', // OPTIONAL AES with a 192-bit key + 'aes256-cbc', // OPTIONAL AES in CBC mode, with a 256-bit key + + 'twofish128-cbc', // OPTIONAL Twofish with a 128-bit key + 'twofish192-cbc', // OPTIONAL Twofish with a 192-bit key + 'twofish256-cbc', + 'twofish-cbc', // OPTIONAL alias for "twofish256-cbc" + // (this is being retained for historical reasons) + + 'blowfish-ctr', // OPTIONAL Blowfish in SDCTR mode + + 'blowfish-cbc', // OPTIONAL Blowfish in CBC mode + + '3des-ctr', // RECOMMENDED Three-key 3DES in SDCTR mode + + '3des-cbc', // REQUIRED three-key 3DES in CBC mode + 'none' // OPTIONAL no encryption; NOT RECOMMENDED + ); + + if (!$this->_is_includable('Crypt/RC4.php')) { + $encryption_algorithms = array_diff( + $encryption_algorithms, + array('arcfour256', 'arcfour128', 'arcfour') + ); + } + if (!$this->_is_includable('Crypt/Rijndael.php')) { + $encryption_algorithms = array_diff( + $encryption_algorithms, + array('aes128-ctr', 'aes192-ctr', 'aes256-ctr', 'aes128-cbc', 'aes192-cbc', 'aes256-cbc') + ); + } + if (!$this->_is_includable('Crypt/Twofish.php')) { + $encryption_algorithms = array_diff( + $encryption_algorithms, + array('twofish128-ctr', 'twofish192-ctr', 'twofish256-ctr', 'twofish128-cbc', 'twofish192-cbc', 'twofish256-cbc', 'twofish-cbc') + ); + } + if (!$this->_is_includable('Crypt/Blowfish.php')) { + $encryption_algorithms = array_diff( + $encryption_algorithms, + array('blowfish-ctr', 'blowfish-cbc') + ); + } + if (!$this->_is_includable('Crypt/TripleDES.php')) { + $encryption_algorithms = array_diff( + $encryption_algorithms, + array('3des-ctr', '3des-cbc') + ); + } + $encryption_algorithms = array_values($encryption_algorithms); + } static $mac_algorithms = array( 'hmac-sha1-96', // RECOMMENDED first 96 bits of HMAC-SHA1 (digest length = 12, key length = 20) @@ -1045,14 +1139,23 @@ class Net_SSH2 { break; case 'aes256-cbc': case 'aes256-ctr': + case 'twofish-cbc': + case 'twofish256-cbc': + case 'twofish256-ctr': $decryptKeyLength = 32; // eg. 256 / 8 break; case 'aes192-cbc': case 'aes192-ctr': + case 'twofish192-cbc': + case 'twofish192-ctr': $decryptKeyLength = 24; // eg. 192 / 8 break; case 'aes128-cbc': case 'aes128-ctr': + case 'twofish128-cbc': + case 'twofish128-ctr': + case 'blowfish-cbc': + case 'blowfish-ctr': $decryptKeyLength = 16; // eg. 128 / 8 break; case 'arcfour': @@ -1080,14 +1183,23 @@ class Net_SSH2 { break; case 'aes256-cbc': case 'aes256-ctr': + case 'twofish-cbc': + case 'twofish256-cbc': + case 'twofish256-ctr': $encryptKeyLength = 32; break; case 'aes192-cbc': case 'aes192-ctr': + case 'twofish192-cbc': + case 'twofish192-ctr': $encryptKeyLength = 24; break; case 'aes128-cbc': case 'aes128-ctr': + case 'twofish128-cbc': + case 'twofish128-ctr': + case 'blowfish-cbc': + case 'blowfish-ctr': $encryptKeyLength = 16; break; case 'arcfour': @@ -1114,28 +1226,29 @@ class Net_SSH2 { // see http://tools.ietf.org/html/rfc2409#section-6.2 and // http://tools.ietf.org/html/rfc2412, appendex E case 'diffie-hellman-group1-sha1': - $p = pack('H256', 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' . - '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' . - '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' . - 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF'); - $keyLength = $keyLength < 160 ? $keyLength : 160; - $hash = 'sha1'; + $prime = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' . + '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' . + '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' . + 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF'; break; // see http://tools.ietf.org/html/rfc3526#section-3 case 'diffie-hellman-group14-sha1': - $p = pack('H512', 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' . - '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' . - '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' . - 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF05' . - '98DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB' . - '9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B' . - 'E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718' . - '3995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF'); - $keyLength = $keyLength < 160 ? $keyLength : 160; - $hash = 'sha1'; + $prime = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' . + '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' . + '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' . + 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF05' . + '98DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB' . + '9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B' . + 'E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718' . + '3995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF'; + break; } - $p = new Math_BigInteger($p, 256); + // For both diffie-hellman-group1-sha1 and diffie-hellman-group14-sha1 + // the generator field element is 2 (decimal) and the hash function is sha1. + $g = new Math_BigInteger(2); + $prime = new Math_BigInteger($prime, 16); + $kexHash = new Crypt_Hash('sha1'); //$q = $p->bitwise_rightShift(1); /* To increase the speed of the key exchange, both client and server may @@ -1145,14 +1258,12 @@ class Net_SSH2 { [VAN-OORSCHOT]. -- http://tools.ietf.org/html/rfc4419#section-6.2 */ - $q = new Math_BigInteger(1); - $q = $q->bitwise_leftShift(2 * $keyLength); - $q = $q->subtract(new Math_BigInteger(1)); + $one = new Math_BigInteger(1); + $keyLength = min($keyLength, $kexHash->getLength()); + $max = $one->bitwise_leftShift(16 * $keyLength)->subtract($one); // 2 * 8 * $keyLength - $g = new Math_BigInteger(2); - $x = new Math_BigInteger(); - $x = $x->random(new Math_BigInteger(1), $q); - $e = $g->modPow($x, $p); + $x = $one->random($one, $max); + $e = $g->modPow($x, $prime); $eBytes = $e->toBytes(true); $data = pack('CNa*', NET_SSH2_MSG_KEXDH_INIT, strlen($eBytes), $eBytes); @@ -1190,7 +1301,7 @@ class Net_SSH2 { $temp = unpack('Nlength', $this->_string_shift($this->signature, 4)); $this->signature_format = $this->_string_shift($this->signature, $temp['length']); - $key = $f->modPow($x, $p); + $key = $f->modPow($x, $prime); $keyBytes = $key->toBytes(true); $this->exchange_hash = pack('Na*Na*Na*Na*Na*Na*Na*Na*', @@ -1200,7 +1311,7 @@ class Net_SSH2 { $eBytes, strlen($fBytes), $fBytes, strlen($keyBytes), $keyBytes ); - $this->exchange_hash = pack('H*', $hash($this->exchange_hash)); + $this->exchange_hash = $kexHash->hash($this->exchange_hash); if ($this->session_id === false) { $this->session_id = $this->exchange_hash; @@ -1213,7 +1324,7 @@ class Net_SSH2 { } if ($public_key_format != $server_host_key_algorithms[$i] || $this->signature_format != $server_host_key_algorithms[$i]) { - user_error('Sever Host Key Algorithm Mismatch'); + user_error('Server Host Key Algorithm Mismatch'); return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); } @@ -1241,28 +1352,76 @@ class Net_SSH2 { switch ($encrypt) { case '3des-cbc': + if (!class_exists('Crypt_TripleDES')) { + require_once('Crypt/TripleDES.php'); + } $this->encrypt = new Crypt_TripleDES(); // $this->encrypt_block_size = 64 / 8 == the default break; case '3des-ctr': + if (!class_exists('Crypt_TripleDES')) { + require_once('Crypt/TripleDES.php'); + } $this->encrypt = new Crypt_TripleDES(CRYPT_DES_MODE_CTR); // $this->encrypt_block_size = 64 / 8 == the default break; case 'aes256-cbc': case 'aes192-cbc': case 'aes128-cbc': - $this->encrypt = new Crypt_AES(); + if (!class_exists('Crypt_Rijndael')) { + require_once('Crypt/Rijndael.php'); + } + $this->encrypt = new Crypt_Rijndael(); $this->encrypt_block_size = 16; // eg. 128 / 8 break; case 'aes256-ctr': case 'aes192-ctr': case 'aes128-ctr': - $this->encrypt = new Crypt_AES(CRYPT_AES_MODE_CTR); + if (!class_exists('Crypt_Rijndael')) { + require_once('Crypt/Rijndael.php'); + } + $this->encrypt = new Crypt_Rijndael(CRYPT_RIJNDAEL_MODE_CTR); $this->encrypt_block_size = 16; // eg. 128 / 8 break; + case 'blowfish-cbc': + if (!class_exists('Crypt_Blowfish')) { + require_once('Crypt/Blowfish.php'); + } + $this->encrypt = new Crypt_Blowfish(); + $this->encrypt_block_size = 8; + break; + case 'blowfish-ctr': + if (!class_exists('Crypt_Blowfish')) { + require_once('Crypt/Blowfish.php'); + } + $this->encrypt = new Crypt_Blowfish(CRYPT_BLOWFISH_MODE_CTR); + $this->encrypt_block_size = 8; + break; + case 'twofish128-cbc': + case 'twofish192-cbc': + case 'twofish256-cbc': + case 'twofish-cbc': + if (!class_exists('Crypt_Twofish')) { + require_once('Crypt/Twofish.php'); + } + $this->encrypt = new Crypt_Twofish(); + $this->encrypt_block_size = 16; + break; + case 'twofish128-ctr': + case 'twofish192-ctr': + case 'twofish256-ctr': + if (!class_exists('Crypt_Twofish')) { + require_once('Crypt/Twofish.php'); + } + $this->encrypt = new Crypt_Twofish(CRYPT_TWOFISH_MODE_CTR); + $this->encrypt_block_size = 16; + break; case 'arcfour': case 'arcfour128': case 'arcfour256': + if (!class_exists('Crypt_RC4')) { + require_once('Crypt/RC4.php'); + } $this->encrypt = new Crypt_RC4(); break; case 'none'; @@ -1271,26 +1430,74 @@ class Net_SSH2 { switch ($decrypt) { case '3des-cbc': + if (!class_exists('Crypt_TripleDES')) { + require_once('Crypt/TripleDES.php'); + } $this->decrypt = new Crypt_TripleDES(); break; case '3des-ctr': + if (!class_exists('Crypt_TripleDES')) { + require_once('Crypt/TripleDES.php'); + } $this->decrypt = new Crypt_TripleDES(CRYPT_DES_MODE_CTR); break; case 'aes256-cbc': case 'aes192-cbc': case 'aes128-cbc': - $this->decrypt = new Crypt_AES(); + if (!class_exists('Crypt_Rijndael')) { + require_once('Crypt/Rijndael.php'); + } + $this->decrypt = new Crypt_Rijndael(); $this->decrypt_block_size = 16; break; case 'aes256-ctr': case 'aes192-ctr': case 'aes128-ctr': - $this->decrypt = new Crypt_AES(CRYPT_AES_MODE_CTR); + if (!class_exists('Crypt_Rijndael')) { + require_once('Crypt/Rijndael.php'); + } + $this->decrypt = new Crypt_Rijndael(CRYPT_RIJNDAEL_MODE_CTR); + $this->decrypt_block_size = 16; + break; + case 'blowfish-cbc': + if (!class_exists('Crypt_Blowfish')) { + require_once('Crypt/Blowfish.php'); + } + $this->decrypt = new Crypt_Blowfish(); + $this->decrypt_block_size = 8; + break; + case 'blowfish-ctr': + if (!class_exists('Crypt_Blowfish')) { + require_once('Crypt/Blowfish.php'); + } + $this->decrypt = new Crypt_Blowfish(CRYPT_BLOWFISH_MODE_CTR); + $this->decrypt_block_size = 8; + break; + case 'twofish128-cbc': + case 'twofish192-cbc': + case 'twofish256-cbc': + case 'twofish-cbc': + if (!class_exists('Crypt_Twofish')) { + require_once('Crypt/Twofish.php'); + } + $this->decrypt = new Crypt_Twofish(); + $this->decrypt_block_size = 16; + break; + case 'twofish128-ctr': + case 'twofish192-ctr': + case 'twofish256-ctr': + if (!class_exists('Crypt_Twofish')) { + require_once('Crypt/Twofish.php'); + } + $this->decrypt = new Crypt_Twofish(CRYPT_TWOFISH_MODE_CTR); $this->decrypt_block_size = 16; break; case 'arcfour': case 'arcfour128': case 'arcfour256': + if (!class_exists('Crypt_RC4')) { + require_once('Crypt/RC4.php'); + } $this->decrypt = new Crypt_RC4(); break; case 'none'; @@ -1303,15 +1510,15 @@ class Net_SSH2 { $this->encrypt->enableContinuousBuffer(); $this->encrypt->disablePadding(); - $iv = pack('H*', $hash($keyBytes . $this->exchange_hash . 'A' . $this->session_id)); + $iv = $kexHash->hash($keyBytes . $this->exchange_hash . 'A' . $this->session_id); while ($this->encrypt_block_size > strlen($iv)) { - $iv.= pack('H*', $hash($keyBytes . $this->exchange_hash . $iv)); + $iv.= $kexHash->hash($keyBytes . $this->exchange_hash . $iv); } $this->encrypt->setIV(substr($iv, 0, $this->encrypt_block_size)); - $key = pack('H*', $hash($keyBytes . $this->exchange_hash . 'C' . $this->session_id)); + $key = $kexHash->hash($keyBytes . $this->exchange_hash . 'C' . $this->session_id); while ($encryptKeyLength > strlen($key)) { - $key.= pack('H*', $hash($keyBytes . $this->exchange_hash . $key)); + $key.= $kexHash->hash($keyBytes . $this->exchange_hash . $key); } $this->encrypt->setKey(substr($key, 0, $encryptKeyLength)); } @@ -1320,15 +1527,15 @@ class Net_SSH2 { $this->decrypt->enableContinuousBuffer(); $this->decrypt->disablePadding(); - $iv = pack('H*', $hash($keyBytes . $this->exchange_hash . 'B' . $this->session_id)); + $iv = $kexHash->hash($keyBytes . $this->exchange_hash . 'B' . $this->session_id); while ($this->decrypt_block_size > strlen($iv)) { - $iv.= pack('H*', $hash($keyBytes . $this->exchange_hash . $iv)); + $iv.= $kexHash->hash($keyBytes . $this->exchange_hash . $iv); } $this->decrypt->setIV(substr($iv, 0, $this->decrypt_block_size)); - $key = pack('H*', $hash($keyBytes . $this->exchange_hash . 'D' . $this->session_id)); + $key = $kexHash->hash($keyBytes . $this->exchange_hash . 'D' . $this->session_id); while ($decryptKeyLength > strlen($key)) { - $key.= pack('H*', $hash($keyBytes . $this->exchange_hash . $key)); + $key.= $kexHash->hash($keyBytes . $this->exchange_hash . $key); } $this->decrypt->setKey(substr($key, 0, $decryptKeyLength)); } @@ -1402,15 +1609,15 @@ class Net_SSH2 { $this->hmac_size = 12; } - $key = pack('H*', $hash($keyBytes . $this->exchange_hash . 'E' . $this->session_id)); + $key = $kexHash->hash($keyBytes . $this->exchange_hash . 'E' . $this->session_id); while ($createKeyLength > strlen($key)) { - $key.= pack('H*', $hash($keyBytes . $this->exchange_hash . $key)); + $key.= $kexHash->hash($keyBytes . $this->exchange_hash . $key); } $this->hmac_create->setKey(substr($key, 0, $createKeyLength)); - $key = pack('H*', $hash($keyBytes . $this->exchange_hash . 'F' . $this->session_id)); + $key = $kexHash->hash($keyBytes . $this->exchange_hash . 'F' . $this->session_id); while ($checkKeyLength > strlen($key)) { - $key.= pack('H*', $hash($keyBytes . $this->exchange_hash . $key)); + $key.= $kexHash->hash($keyBytes . $this->exchange_hash . $key); } $this->hmac_check->setKey(substr($key, 0, $checkKeyLength)); @@ -1434,40 +1641,72 @@ class Net_SSH2 { /** * Login * - * The $password parameter can be a plaintext password or a Crypt_RSA object. + * The $password parameter can be a plaintext password, a Crypt_RSA object or an array + * + * @param String $username + * @param Mixed $password + * @param Mixed $... + * @return Boolean + * @see _login_helper + * @access public + */ + function login($username) + { + $args = array_slice(func_get_args(), 1); + if (empty($args)) { + return $this->_login_helper($username); + } + + foreach ($args as $arg) { + if ($this->_login_helper($username, $arg)) { + return true; + } + } + return false; + } + + /** + * Login Helper * * @param String $username * @param optional String $password * @return Boolean - * @access public + * @access private * @internal It might be worthwhile, at some point, to protect against {@link http://tools.ietf.org/html/rfc4251#section-9.3.9 traffic analysis} * by sending dummy SSH_MSG_IGNORE messages. */ - function login($username, $password = null) + function _login_helper($username, $password = null) { if (!($this->bitmap & NET_SSH2_MASK_CONSTRUCTOR)) { return false; } - $packet = pack('CNa*', - NET_SSH2_MSG_SERVICE_REQUEST, strlen('ssh-userauth'), 'ssh-userauth' - ); + if (!($this->bitmap & NET_SSH2_MASK_LOGIN_REQ)) { + $packet = pack('CNa*', + NET_SSH2_MSG_SERVICE_REQUEST, strlen('ssh-userauth'), 'ssh-userauth' + ); - if (!$this->_send_binary_packet($packet)) { - return false; + if (!$this->_send_binary_packet($packet)) { + return false; + } + + $response = $this->_get_binary_packet(); + if ($response === false) { + user_error('Connection closed by server'); + return false; + } + + extract(unpack('Ctype', $this->_string_shift($response, 1))); + + if ($type != NET_SSH2_MSG_SERVICE_ACCEPT) { + user_error('Expected SSH_MSG_SERVICE_ACCEPT'); + return false; + } + $this->bitmap |= NET_SSH2_MASK_LOGIN_REQ; } - $response = $this->_get_binary_packet(); - if ($response === false) { - user_error('Connection closed by server'); - return false; - } - - extract(unpack('Ctype', $this->_string_shift($response, 1))); - - if ($type != NET_SSH2_MSG_SERVICE_ACCEPT) { - user_error('Expected SSH_MSG_SERVICE_ACCEPT'); - return false; + if (strlen($this->last_interactive_response)) { + return !is_string($password) && !is_array($password) ? false : $this->_keyboard_interactive_process($password); } // although PHP5's get_class() preserves the case, PHP4's does not @@ -1475,6 +1714,14 @@ class Net_SSH2 { return $this->_privatekey_login($username, $password); } + if (is_array($password)) { + if ($this->_keyboard_interactive_login($username, $password)) { + $this->bitmap |= NET_SSH2_MASK_LOGIN; + return true; + } + return false; + } + if (!isset($password)) { $packet = pack('CNa*Na*Na*', NET_SSH2_MSG_USERAUTH_REQUEST, strlen($username), $username, strlen('ssh-connection'), 'ssh-connection', @@ -1508,17 +1755,18 @@ class Net_SSH2 { strlen('password'), 'password', 0, strlen($password), $password ); - if (!$this->_send_binary_packet($packet)) { - return false; - } - - // remove the username and password from the last logged packet - if (defined('NET_SSH2_LOGGING') && NET_SSH2_LOGGING == NET_SSH2_LOG_COMPLEX) { - $packet = pack('CNa*Na*Na*CNa*', + // remove the username and password from the logged packet + if (!defined('NET_SSH2_LOGGING')) { + $logged = NULL; + } else { + $logged = pack('CNa*Na*Na*CNa*', NET_SSH2_MSG_USERAUTH_REQUEST, strlen('username'), 'username', strlen('ssh-connection'), 'ssh-connection', strlen('password'), 'password', 0, strlen('password'), 'password' ); - $this->message_log[count($this->message_log) - 1] = $packet; + } + + if (!$this->_send_binary_packet($packet, $logged)) { + return false; } $response = $this->_get_binary_packet(); @@ -1542,7 +1790,10 @@ class Net_SSH2 { // multi-factor authentication extract(unpack('Nlength', $this->_string_shift($response, 4))); $auth_methods = explode(',', $this->_string_shift($response, $length)); - if (in_array('keyboard-interactive', $auth_methods)) { + extract(unpack('Cpartial_success', $this->_string_shift($response, 1))); + $partial_success = $partial_success != 0; + + if (!$partial_success && in_array('keyboard-interactive', $auth_methods)) { if ($this->_keyboard_interactive_login($username, $password)) { $this->bitmap |= NET_SSH2_MASK_LOGIN; return true; @@ -1593,25 +1844,20 @@ class Net_SSH2 { { $responses = func_get_args(); - $response = $this->_get_binary_packet(); - if ($response === false) { - user_error('Connection closed by server'); - return false; + if (strlen($this->last_interactive_response)) { + $response = $this->last_interactive_response; + } else { + $orig = $response = $this->_get_binary_packet(); + if ($response === false) { + user_error('Connection closed by server'); + return false; + } } extract(unpack('Ctype', $this->_string_shift($response, 1))); switch ($type) { case NET_SSH2_MSG_USERAUTH_INFO_REQUEST: - // see http://tools.ietf.org/html/rfc4256#section-3.2 - if (defined('NET_SSH2_LOGGING')) { - $this->message_number_log[count($this->message_number_log) - 1] = str_replace( - 'UNKNOWN', - 'NET_SSH2_MSG_USERAUTH_INFO_REQUEST', - $this->message_number_log[count($this->message_number_log) - 1] - ); - } - extract(unpack('Nlength', $this->_string_shift($response, 4))); $this->_string_shift($response, $length); // name; may be empty extract(unpack('Nlength', $this->_string_shift($response, 4))); @@ -1619,14 +1865,48 @@ class Net_SSH2 { extract(unpack('Nlength', $this->_string_shift($response, 4))); $this->_string_shift($response, $length); // language tag; may be empty extract(unpack('Nnum_prompts', $this->_string_shift($response, 4))); - /* - for ($i = 0; $i < $num_prompts; $i++) { - extract(unpack('Nlength', $this->_string_shift($response, 4))); - // prompt - ie. "Password: "; must not be empty - $this->_string_shift($response, $length); - $echo = $this->_string_shift($response) != chr(0); + + for ($i = 0; $i < count($responses); $i++) { + if (is_array($responses[$i])) { + foreach ($responses[$i] as $key => $value) { + $this->keyboard_requests_responses[$key] = $value; + } + unset($responses[$i]); + } + } + $responses = array_values($responses); + + if (isset($this->keyboard_requests_responses)) { + for ($i = 0; $i < $num_prompts; $i++) { + extract(unpack('Nlength', $this->_string_shift($response, 4))); + // prompt - ie. "Password: "; must not be empty + $prompt = $this->_string_shift($response, $length); + //$echo = $this->_string_shift($response) != chr(0); + foreach ($this->keyboard_requests_responses as $key => $value) { + if (substr($prompt, 0, strlen($key)) == $key) { + $responses[] = $value; + break; + } + } + } + } + + // see http://tools.ietf.org/html/rfc4256#section-3.2 + if (strlen($this->last_interactive_response)) { + $this->last_interactive_response = ''; + } else if (defined('NET_SSH2_LOGGING')) { + $this->message_number_log[count($this->message_number_log) - 1] = str_replace( + 'UNKNOWN', + 'NET_SSH2_MSG_USERAUTH_INFO_REQUEST', + $this->message_number_log[count($this->message_number_log) - 1] + ); + } + + if (!count($responses) && $num_prompts) { + $this->last_interactive_response = $orig; + $this->bitmap |= NET_SSH_MASK_LOGIN_INTERACTIVE; + return false; } - */ /* After obtaining the requested information from the user, the client @@ -1639,17 +1919,16 @@ class Net_SSH2 { $logged.= pack('Na*', strlen('dummy-answer'), 'dummy-answer'); } - if (!$this->_send_binary_packet($packet)) { + if (!$this->_send_binary_packet($packet, $logged)) { return false; } - if (defined('NET_SSH2_LOGGING')) { + if (defined('NET_SSH2_LOGGING') && NET_SSH2_LOGGING == NET_SSH2_LOG_COMPLEX) { $this->message_number_log[count($this->message_number_log) - 1] = str_replace( 'UNKNOWN', 'NET_SSH2_MSG_USERAUTH_INFO_RESPONSE', $this->message_number_log[count($this->message_number_log) - 1] ); - $this->message_log[count($this->message_log) - 1] = $logged; } /* @@ -1718,11 +1997,11 @@ class Net_SSH2 { case NET_SSH2_MSG_USERAUTH_FAILURE: extract(unpack('Nlength', $this->_string_shift($response, 4))); $this->errors[] = 'SSH_MSG_USERAUTH_FAILURE: ' . $this->_string_shift($response, $length); - return $this->_disconnect(NET_SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER); + return false; case NET_SSH2_MSG_USERAUTH_PK_OK: // we'll just take it on faith that the public key blob and the public key algorithm name are as // they should be - if (defined('NET_SSH2_LOGGING')) { + if (defined('NET_SSH2_LOGGING') && NET_SSH2_LOGGING == NET_SSH2_LOG_COMPLEX) { $this->message_number_log[count($this->message_number_log) - 1] = str_replace( 'UNKNOWN', 'NET_SSH2_MSG_USERAUTH_PK_OK', @@ -1768,12 +2047,23 @@ class Net_SSH2 { * Setting $timeout to false or 0 will mean there is no timeout. * * @param Mixed $timeout + * @access public */ function setTimeout($timeout) { $this->timeout = $this->curTimeout = $timeout; } + /** + * Get the output from stdError + * + * @access public + */ + function getStdError() + { + return $this->stdErrorLog; + } + /** * Execute Command * @@ -1785,25 +2075,27 @@ class Net_SSH2 { * @return String * @access public */ - function exec($command, $block = true) + function exec($command, $callback = NULL) { $this->curTimeout = $this->timeout; + $this->is_timeout = false; + $this->stdErrorLog = ''; if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { return false; } // RFC4254 defines the (client) window size as "bytes the other party can send before it must wait for the window to - // be adjusted". 0x7FFFFFFF is, at 4GB, the max size. technically, it should probably be decremented, but, - // honestly, if you're transfering more than 4GB, you probably shouldn't be using phpseclib, anyway. + // be adjusted". 0x7FFFFFFF is, at 2GB, the max size. technically, it should probably be decremented, but, + // honestly, if you're transfering more than 2GB, you probably shouldn't be using phpseclib, anyway. // see http://tools.ietf.org/html/rfc4254#section-5.2 for more info - $this->window_size_client_to_server[NET_SSH2_CHANNEL_EXEC] = 0x7FFFFFFF; + $this->window_size_server_to_client[NET_SSH2_CHANNEL_EXEC] = 0x7FFFFFFF; // 0x8000 is the maximum max packet size, per http://tools.ietf.org/html/rfc4253#section-6.1, although since PuTTy // uses 0x4000, that's what will be used here, as well. $packet_size = 0x4000; $packet = pack('CNa*N3', - NET_SSH2_MSG_CHANNEL_OPEN, strlen('session'), 'session', NET_SSH2_CHANNEL_EXEC, $this->window_size_client_to_server[NET_SSH2_CHANNEL_EXEC], $packet_size); + NET_SSH2_MSG_CHANNEL_OPEN, strlen('session'), 'session', NET_SSH2_CHANNEL_EXEC, $this->window_size_server_to_client[NET_SSH2_CHANNEL_EXEC], $packet_size); if (!$this->_send_binary_packet($packet)) { return false; @@ -1816,6 +2108,34 @@ class Net_SSH2 { return false; } + if ($this->request_pty === true) { + $terminal_modes = pack('C', NET_SSH2_TTY_OP_END); + $packet = pack('CNNa*CNa*N5a*', + NET_SSH2_MSG_CHANNEL_REQUEST, $this->server_channels[NET_SSH2_CHANNEL_EXEC], strlen('pty-req'), 'pty-req', 1, strlen('vt100'), 'vt100', + 80, 24, 0, 0, strlen($terminal_modes), $terminal_modes); + + if (!$this->_send_binary_packet($packet)) { + return false; + } + $response = $this->_get_binary_packet(); + if ($response === false) { + user_error('Connection closed by server'); + return false; + } + + list(, $type) = unpack('C', $this->_string_shift($response, 1)); + + switch ($type) { + case NET_SSH2_MSG_CHANNEL_SUCCESS: + break; + case NET_SSH2_MSG_CHANNEL_FAILURE: + default: + user_error('Unable to request pseudo-terminal'); + return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION); + } + $this->in_request_pty_exec = true; + } + // sending a pty-req SSH_MSG_CHANNEL_REQUEST message is unnecessary and, in fact, in most cases, slows things // down. the one place where it might be desirable is if you're doing something like Net_SSH2::exec('ping localhost &'). // with a pty-req SSH_MSG_CHANNEL_REQUEST, exec() will return immediately and the ping process will then @@ -1840,7 +2160,7 @@ class Net_SSH2 { $this->channel_status[NET_SSH2_CHANNEL_EXEC] = NET_SSH2_MSG_CHANNEL_DATA; - if (!$block) { + if ($callback === false || $this->in_request_pty_exec) { return true; } @@ -1849,11 +2169,15 @@ class Net_SSH2 { $temp = $this->_get_channel_packet(NET_SSH2_CHANNEL_EXEC); switch (true) { case $temp === true: - return $output; + return is_callable($callback) ? true : $output; case $temp === false: return false; default: - $output.= $temp; + if (is_callable($callback)) { + $callback($temp); + } else { + $output.= $temp; + } } } } @@ -1868,11 +2192,15 @@ class Net_SSH2 { */ function _initShell() { - $this->window_size_client_to_server[NET_SSH2_CHANNEL_SHELL] = 0x7FFFFFFF; + if ($this->in_request_pty_exec === true) { + return true; + } + + $this->window_size_server_to_client[NET_SSH2_CHANNEL_SHELL] = 0x7FFFFFFF; $packet_size = 0x4000; $packet = pack('CNa*N3', - NET_SSH2_MSG_CHANNEL_OPEN, strlen('session'), 'session', NET_SSH2_CHANNEL_SHELL, $this->window_size_client_to_server[NET_SSH2_CHANNEL_SHELL], $packet_size); + NET_SSH2_MSG_CHANNEL_OPEN, strlen('session'), 'session', NET_SSH2_CHANNEL_SHELL, $this->window_size_server_to_client[NET_SSH2_CHANNEL_SHELL], $packet_size); if (!$this->_send_binary_packet($packet)) { return false; @@ -1904,8 +2232,9 @@ class Net_SSH2 { switch ($type) { case NET_SSH2_MSG_CHANNEL_SUCCESS: - break; + // if a pty can't be opened maybe commands can still be executed case NET_SSH2_MSG_CHANNEL_FAILURE: + break; default: user_error('Unable to request pseudo-terminal'); return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION); @@ -1931,13 +2260,33 @@ class Net_SSH2 { return true; } + /** + * Return the channel to be used with read() / write() + * + * @see Net_SSH2::read() + * @see Net_SSH2::write() + * @return Integer + * @access public + */ + function _get_interactive_channel() + { + switch (true) { + case $this->in_subsystem: + return NET_SSH2_CHANNEL_SUBSYSTEM; + case $this->in_request_pty_exec: + return NET_SSH2_CHANNEL_EXEC; + default: + return NET_SSH2_CHANNEL_SHELL; + } + } + /** * Returns the output of an interactive shell * * Returns when there's a match for $expect, which can take the form of a string literal or, * if $mode == NET_SSH2_READ_REGEX, a regular expression. * - * @see Net_SSH2::read() + * @see Net_SSH2::write() * @param String $expect * @param Integer $mode * @return String @@ -1946,6 +2295,7 @@ class Net_SSH2 { function read($expect = '', $mode = NET_SSH2_READ_SIMPLE) { $this->curTimeout = $this->timeout; + $this->is_timeout = false; if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { user_error('Operation disallowed prior to login()'); @@ -1957,6 +2307,8 @@ class Net_SSH2 { return false; } + $channel = $this->_get_interactive_channel(); + $match = $expect; while (true) { if ($mode == NET_SSH2_READ_REGEX) { @@ -1967,8 +2319,9 @@ class Net_SSH2 { if ($pos !== false) { return $this->_string_shift($this->interactiveBuffer, $pos + strlen($match)); } - $response = $this->_get_channel_packet(NET_SSH2_CHANNEL_SHELL); + $response = $this->_get_channel_packet($channel); if (is_bool($response)) { + $this->in_request_pty_exec = false; return $response ? $this->_string_shift($this->interactiveBuffer, strlen($this->interactiveBuffer)) : false; } @@ -1979,7 +2332,7 @@ class Net_SSH2 { /** * Inputs a command into an interactive shell. * - * @see Net_SSH1::interactiveWrite() + * @see Net_SSH2::read() * @param String $cmd * @return Boolean * @access public @@ -1996,7 +2349,101 @@ class Net_SSH2 { return false; } - return $this->_send_channel_packet(NET_SSH2_CHANNEL_SHELL, $cmd); + $channel = $this->in_request_pty_exec ? NET_SSH2_CHANNEL_EXEC : NET_SSH2_CHANNEL_SHELL; + return $this->_send_channel_packet($this->_get_interactive_channel(), $cmd); + } + + /** + * Start a subsystem. + * + * Right now only one subsystem at a time is supported. To support multiple subsystem's stopSubsystem() could accept + * a string that contained the name of the subsystem, but at that point, only one subsystem of each type could be opened. + * To support multiple subsystem's of the same name maybe it'd be best if startSubsystem() generated a new channel id and + * returns that and then that that was passed into stopSubsystem() but that'll be saved for a future date and implemented + * if there's sufficient demand for such a feature. + * + * @see Net_SSH2::stopSubsystem() + * @param String $subsystem + * @return Boolean + * @access public + */ + function startSubsystem($subsystem) + { + $this->window_size_server_to_client[NET_SSH2_CHANNEL_SUBSYSTEM] = $this->window_size; + + $packet = pack('CNa*N3', + NET_SSH2_MSG_CHANNEL_OPEN, strlen('session'), 'session', NET_SSH2_CHANNEL_SUBSYSTEM, $this->window_size, 0x4000); + + if (!$this->_send_binary_packet($packet)) { + return false; + } + + $this->channel_status[NET_SSH2_CHANNEL_SUBSYSTEM] = NET_SSH2_MSG_CHANNEL_OPEN; + + $response = $this->_get_channel_packet(NET_SSH2_CHANNEL_SUBSYSTEM); + if ($response === false) { + return false; + } + + $packet = pack('CNNa*CNa*', + NET_SSH2_MSG_CHANNEL_REQUEST, $this->server_channels[NET_SSH2_CHANNEL_SUBSYSTEM], strlen('subsystem'), 'subsystem', 1, strlen($subsystem), $subsystem); + if (!$this->_send_binary_packet($packet)) { + return false; + } + + $this->channel_status[NET_SSH2_CHANNEL_SUBSYSTEM] = NET_SSH2_MSG_CHANNEL_REQUEST; + + $response = $this->_get_channel_packet(NET_SSH2_CHANNEL_SUBSYSTEM); + + if ($response === false) { + return false; + } + + $this->channel_status[NET_SSH2_CHANNEL_SUBSYSTEM] = NET_SSH2_MSG_CHANNEL_DATA; + + $this->bitmap |= NET_SSH2_MASK_SHELL; + $this->in_subsystem = true; + + return true; + } + + /** + * Stops a subsystem. + * + * @see Net_SSH2::startSubsystem() + * @return Boolean + * @access public + */ + function stopSubsystem() + { + $this->in_subsystem = false; + $this->_close_channel(NET_SSH2_CHANNEL_SUBSYSTEM); + return true; + } + + /** + * Closes a channel + * + * If read() timed out you might want to just close the channel and have it auto-restart on the next read() call + * + * @access public + */ + function reset() + { + $channel = $this->in_request_pty_exec ? NET_SSH2_CHANNEL_EXEC : NET_SSH2_CHANNEL_SHELL; + $this->_close_channel($channel); + } + + /** + * Is timeout? + * + * Did exec() or read() return because they timed out or because they encountered the end? + * + * @access public + */ + function isTimeout() + { + return $this->is_timeout; } /** @@ -2025,6 +2472,16 @@ class Net_SSH2 { $this->disconnect(); } + /** + * Is the connection still active? + * + * @access public + */ + function isConnected() + { + return $this->bitmap & NET_SSH2_MASK_LOGIN; + } + /** * Gets Binary Packets * @@ -2038,7 +2495,7 @@ class Net_SSH2 { { if (!is_resource($this->fsock) || feof($this->fsock)) { user_error('Connection closed prematurely'); - $this->bitmask = 0; + $this->bitmap = 0; return false; } @@ -2125,7 +2582,7 @@ class Net_SSH2 { $this->_string_shift($payload, 1); extract(unpack('Nreason_code/Nlength', $this->_string_shift($payload, 8))); $this->errors[] = 'SSH_MSG_DISCONNECT: ' . $this->disconnect_reasons[$reason_code] . "\r\n" . utf8_decode($this->_string_shift($payload, $length)); - $this->bitmask = 0; + $this->bitmap = 0; return false; case NET_SSH2_MSG_IGNORE: $payload = $this->_get_binary_packet(); @@ -2141,7 +2598,7 @@ class Net_SSH2 { case NET_SSH2_MSG_KEXINIT: if ($this->session_id !== false) { if (!$this->_key_exchange($payload)) { - $this->bitmask = 0; + $this->bitmap = 0; return false; } $payload = $this->_get_binary_packet(); @@ -2152,7 +2609,7 @@ class Net_SSH2 { if (($this->bitmap & NET_SSH2_MASK_CONSTRUCTOR) && !($this->bitmap & NET_SSH2_MASK_LOGIN) && ord($payload[0]) == NET_SSH2_MSG_USERAUTH_BANNER) { $this->_string_shift($payload, 1); extract(unpack('Nlength', $this->_string_shift($payload, 4))); - $this->errors[] = 'SSH_MSG_USERAUTH_BANNER: ' . utf8_decode($this->_string_shift($payload, $length)); + $this->banner_message = utf8_decode($this->_string_shift($payload, $length)); $payload = $this->_get_binary_packet(); } @@ -2172,7 +2629,7 @@ class Net_SSH2 { break; case NET_SSH2_MSG_CHANNEL_OPEN: // see http://tools.ietf.org/html/rfc4254#section-5.1 $this->_string_shift($payload, 1); - extract(unpack('N', $this->_string_shift($payload, 4))); + extract(unpack('Nlength', $this->_string_shift($payload, 4))); $this->errors[] = 'SSH_MSG_CHANNEL_OPEN: ' . utf8_decode($this->_string_shift($payload, $length)); $this->_string_shift($payload, 4); // skip over client channel @@ -2188,7 +2645,12 @@ class Net_SSH2 { $payload = $this->_get_binary_packet(); break; case NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST: - $payload = $this->_get_binary_packet(); + $this->_string_shift($payload, 1); + extract(unpack('Nchannel', $this->_string_shift($payload, 4))); + extract(unpack('Nwindow_size', $this->_string_shift($payload, 4))); + $this->window_size_client_to_server[$channel]+= $window_size; + + $payload = ($this->bitmap & NET_SSH2_MASK_WINDOW_ADJUST) ? true : $this->_get_binary_packet(); } } @@ -2219,6 +2681,26 @@ class Net_SSH2 { $this->quiet_mode = false; } + /** + * Enable request-pty when using exec() + * + * @access public + */ + function enablePTY() + { + $this->request_pty = true; + } + + /** + * Disable request-pty when using exec() + * + * @access public + */ + function disablePTY() + { + $this->request_pty = false; + } + /** * Gets channel data * @@ -2236,6 +2718,11 @@ class Net_SSH2 { while (true) { if ($this->curTimeout) { + if ($this->curTimeout < 0) { + $this->is_timeout = true; + return true; + } + $read = array($this->fsock); $write = $except = NULL; @@ -2244,7 +2731,7 @@ class Net_SSH2 { $usec = 1000000 * ($this->curTimeout - $sec); // on windows this returns a "Warning: Invalid CRT parameters detected" error if (!@stream_select($read, $write, $except, $sec, $usec) && !count($read)) { - $this->_close_channel($client_channel); + $this->is_timeout = true; return true; } $elapsed = strtok(microtime(), ' ') + strtok('') - $start; @@ -2256,20 +2743,34 @@ class Net_SSH2 { user_error('Connection closed by server'); return false; } - + if ($client_channel == -1 && $response === true) { + return true; + } if (!strlen($response)) { return ''; } extract(unpack('Ctype/Nchannel', $this->_string_shift($response, 5))); + $this->window_size_server_to_client[$channel]-= strlen($response) + 4; + + // resize the window, if appropriate + if ($this->window_size_server_to_client[$channel] < 0) { + $packet = pack('CNN', NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST, $this->server_channels[$channel], $this->window_size); + if (!$this->_send_binary_packet($packet)) { + return false; + } + $this->window_size_server_to_client[$channel]+= $this->window_size; + } + switch ($this->channel_status[$channel]) { case NET_SSH2_MSG_CHANNEL_OPEN: switch ($type) { case NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION: extract(unpack('Nserver_channel', $this->_string_shift($response, 4))); $this->server_channels[$channel] = $server_channel; - $this->_string_shift($response, 4); // skip over (server) window size + extract(unpack('Nwindow_size', $this->_string_shift($response, 4))); + $this->window_size_client_to_server[$channel] = $window_size; $temp = unpack('Npacket_size_client_to_server', $this->_string_shift($response, 4)); $this->packet_size_client_to_server[$channel] = $temp['packet_size_client_to_server']; return $client_channel == $channel ? true : $this->_get_channel_packet($client_channel, $skip_extended); @@ -2283,24 +2784,27 @@ class Net_SSH2 { switch ($type) { case NET_SSH2_MSG_CHANNEL_SUCCESS: return true; - //case NET_SSH2_MSG_CHANNEL_FAILURE: + case NET_SSH2_MSG_CHANNEL_FAILURE: + return false; default: - user_error('Unable to request pseudo-terminal'); + user_error('Unable to fulfill channel request'); return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION); } case NET_SSH2_MSG_CHANNEL_CLOSE: return $type == NET_SSH2_MSG_CHANNEL_CLOSE ? true : $this->_get_channel_packet($client_channel, $skip_extended); } + // ie. $this->channel_status[$channel] == NET_SSH2_MSG_CHANNEL_DATA + switch ($type) { case NET_SSH2_MSG_CHANNEL_DATA: /* - if ($client_channel == NET_SSH2_CHANNEL_EXEC) { + if ($channel == NET_SSH2_CHANNEL_EXEC) { // SCP requires null packets, such as this, be sent. further, in the case of the ssh.com SSH server // this actually seems to make things twice as fast. more to the point, the message right after // SSH_MSG_CHANNEL_DATA (usually SSH_MSG_IGNORE) won't block for as long as it would have otherwise. // in OpenSSH it slows things down but only by a couple thousandths of a second. - $this->_send_channel_packet($client_channel, chr(0)); + $this->_send_channel_packet($channel, chr(0)); } */ extract(unpack('Nlength', $this->_string_shift($response, 4))); @@ -2308,15 +2812,12 @@ class Net_SSH2 { if ($client_channel == $channel) { return $data; } - if (!isset($this->channel_buffers[$client_channel])) { - $this->channel_buffers[$client_channel] = array(); + if (!isset($this->channel_buffers[$channel])) { + $this->channel_buffers[$channel] = array(); } - $this->channel_buffers[$client_channel][] = $data; + $this->channel_buffers[$channel][] = $data; break; case NET_SSH2_MSG_CHANNEL_EXTENDED_DATA: - if ($skip_extended || $this->quiet_mode) { - break; - } /* if ($client_channel == NET_SSH2_CHANNEL_EXEC) { $this->_send_channel_packet($client_channel, chr(0)); @@ -2325,13 +2826,17 @@ class Net_SSH2 { // currently, there's only one possible value for $data_type_code: NET_SSH2_EXTENDED_DATA_STDERR extract(unpack('Ndata_type_code/Nlength', $this->_string_shift($response, 8))); $data = $this->_string_shift($response, $length); + $this->stdErrorLog .= $data; + if ($skip_extended || $this->quiet_mode) { + break; + } if ($client_channel == $channel) { return $data; } - if (!isset($this->channel_buffers[$client_channel])) { - $this->channel_buffers[$client_channel] = array(); + if (!isset($this->channel_buffers[$channel])) { + $this->channel_buffers[$channel] = array(); } - $this->channel_buffers[$client_channel][] = $data; + $this->channel_buffers[$channel][] = $data; break; case NET_SSH2_MSG_CHANNEL_REQUEST: extract(unpack('Nlength', $this->_string_shift($response, 4))); @@ -2346,6 +2851,13 @@ class Net_SSH2 { if ($length) { $this->errors[count($this->errors)].= "\r\n" . $this->_string_shift($response, $length); } + + $this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_EOF, $this->server_channels[$client_channel])); + $this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$channel])); + + $this->channel_status[$channel] = NET_SSH2_MSG_CHANNEL_EOF; + + break; case 'exit-status': extract(unpack('Cfalse/Nexit_status', $this->_string_shift($response, 5))); $this->exit_status = $exit_status; @@ -2355,6 +2867,8 @@ class Net_SSH2 { $this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$channel])); $this->channel_status[$channel] = NET_SSH2_MSG_CHANNEL_EOF; + + break; default: // "Some systems may not implement signals, in which case they SHOULD ignore this message." // -- http://tools.ietf.org/html/rfc4254#section-6.9 @@ -2388,15 +2902,16 @@ class Net_SSH2 { * See '6. Binary Packet Protocol' of rfc4253 for more info. * * @param String $data + * @param optional String $logged * @see Net_SSH2::_get_binary_packet() * @return Boolean * @access private */ - function _send_binary_packet($data) + function _send_binary_packet($data, $logged = NULL) { if (!is_resource($this->fsock) || feof($this->fsock)) { user_error('Connection closed prematurely'); - $this->bitmask = 0; + $this->bitmap = 0; return false; } @@ -2435,7 +2950,7 @@ class Net_SSH2 { $message_number = isset($this->message_numbers[ord($data[0])]) ? $this->message_numbers[ord($data[0])] : 'UNKNOWN (' . ord($data[0]) . ')'; $message_number = '-> ' . $message_number . ' (since last: ' . round($current - $this->last_packet, 4) . ', network: ' . round($stop - $start, 4) . 's)'; - $this->_append_log($message_number, $data); + $this->_append_log($message_number, isset($logged) ? $logged : $data); $this->last_packet = $current; } @@ -2452,6 +2967,11 @@ class Net_SSH2 { */ function _append_log($message_number, $message) { + // remove the byte identifying the message type from all but the first two messages (ie. the identification strings) + if (strlen($message_number) > 2) { + $this->_string_shift($message); + } + switch (NET_SSH2_LOGGING) { // useful for benchmarks case NET_SSH2_LOG_SIMPLE: @@ -2460,7 +2980,6 @@ class Net_SSH2 { // the most useful log for SSH2 case NET_SSH2_LOG_COMPLEX: $this->message_number_log[] = $message_number; - $this->_string_shift($message); $this->log_size+= strlen($message); $this->message_log[] = $message; while ($this->log_size > NET_SSH2_LOG_MAX_SIZE) { @@ -2472,7 +2991,15 @@ class Net_SSH2 { // passwords won't be filtered out and select other packets may not be correctly // identified case NET_SSH2_LOG_REALTIME: - echo "
    \r\n" . $this->_format_log(array($message), array($message_number)) . "\r\n
    \r\n"; + switch (PHP_SAPI) { + case 'cli': + $start = $stop = "\r\n"; + break; + default: + $start = '
    ';
    +                            $stop = '
    '; + } + echo $start . $this->_format_log(array($message), array($message_number)) . $stop; @flush(); @ob_flush(); break; @@ -2483,7 +3010,7 @@ class Net_SSH2 { case NET_SSH2_LOG_REALTIME_FILE: if (!isset($this->realtime_log_file)) { // PHP doesn't seem to like using constants in fopen() - $filename = NET_SSH2_LOG_REALTIME_FILE; + $filename = NET_SSH2_LOG_REALTIME_FILENAME; $fp = fopen($filename, 'w'); $this->realtime_log_file = $fp; } @@ -2518,39 +3045,49 @@ class Net_SSH2 { */ function _send_channel_packet($client_channel, $data) { - while (strlen($data) > $this->packet_size_client_to_server[$client_channel]) { - // resize the window, if appropriate - $this->window_size_client_to_server[$client_channel]-= $this->packet_size_client_to_server[$client_channel]; - if ($this->window_size_client_to_server[$client_channel] < 0) { - $packet = pack('CNN', NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST, $this->server_channels[$client_channel], $this->window_size); - if (!$this->_send_binary_packet($packet)) { - return false; - } - $this->window_size_client_to_server[$client_channel]+= $this->window_size; + /* The maximum amount of data allowed is determined by the maximum + packet size for the channel, and the current window size, whichever + is smaller. + + -- http://tools.ietf.org/html/rfc4254#section-5.2 */ + $max_size = min( + $this->packet_size_client_to_server[$client_channel], + $this->window_size_client_to_server[$client_channel] + ) - 4; + while (strlen($data) > $max_size) { + if (!$this->window_size_client_to_server[$client_channel]) { + $this->bitmap^= NET_SSH2_MASK_WINDOW_ADJUST; + // using an invalid channel will let the buffers be built up for the valid channels + $output = $this->_get_channel_packet(-1); + $this->bitmap^= NET_SSH2_MASK_WINDOW_ADJUST; + $max_size = min( + $this->packet_size_client_to_server[$client_channel], + $this->window_size_client_to_server[$client_channel] + ) - 4; } $packet = pack('CN2a*', NET_SSH2_MSG_CHANNEL_DATA, $this->server_channels[$client_channel], - $this->packet_size_client_to_server[$client_channel], - $this->_string_shift($data, $this->packet_size_client_to_server[$client_channel]) + $max_size, + $this->_string_shift($data, $max_size) ); + $this->window_size_client_to_server[$client_channel]-= $max_size + 4; + if (!$this->_send_binary_packet($packet)) { return false; } } - // resize the window, if appropriate - $this->window_size_client_to_server[$client_channel]-= strlen($data); - if ($this->window_size_client_to_server[$client_channel] < 0) { - $packet = pack('CNN', NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST, $this->server_channels[$client_channel], $this->window_size); - if (!$this->_send_binary_packet($packet)) { - return false; - } - $this->window_size_client_to_server[$client_channel]+= $this->window_size; + if (strlen($data) >= $this->window_size_client_to_server[$client_channel] - 4) { + $this->bitmap^= NET_SSH2_MASK_WINDOW_ADJUST; + $this->_get_channel_packet(-1); + $this->bitmap^= NET_SSH2_MASK_WINDOW_ADJUST; } + $this->window_size_client_to_server[$client_channel]-= strlen($data) + 4; + return $this->_send_binary_packet(pack('CN2a*', NET_SSH2_MSG_CHANNEL_DATA, $this->server_channels[$client_channel], @@ -2858,6 +3395,20 @@ class Net_SSH2 { return $this->languages_client_to_server; } + /** + * Returns the banner message. + * + * Quoting from the RFC, "in some jurisdictions, sending a warning message before + * authentication may be relevant for getting legal protection." + * + * @return String + * @access public + */ + function getBannerMessage() + { + return $this->banner_message; + } + /** * Returns the server public host key. * @@ -2885,6 +3436,8 @@ class Net_SSH2 { switch ($this->signature_format) { case 'ssh-dss': + $zero = new Math_BigInteger(); + $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4)); $p = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256); @@ -2909,9 +3462,13 @@ class Net_SSH2 { $r = new Math_BigInteger($this->_string_shift($signature, 20), 256); $s = new Math_BigInteger($this->_string_shift($signature, 20), 256); - if ($r->compare($q) >= 0 || $s->compare($q) >= 0) { - user_error('Invalid signature'); - return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); + switch (true) { + case $r->equals($zero): + case $r->compare($q) >= 0: + case $s->equals($zero): + case $s->compare($q) >= 0: + user_error('Invalid signature'); + return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); } $w = $s->modInverse($q); @@ -3006,4 +3563,24 @@ class Net_SSH2 { } return $this->exit_status; } + + /** + * Is a path includable? + * + * @return Boolean + * @access private + */ + function _is_includable($suffix) + { + foreach (explode(PATH_SEPARATOR, get_include_path()) as $prefix) { + $ds = substr($prefix, -1) == DIRECTORY_SEPARATOR ? '' : DIRECTORY_SEPARATOR; + $file = $prefix . $ds . $suffix; + + if (file_exists($file)) { + return true; + } + } + + return false; + } } diff --git a/apps/files_external/lib/sftp.php b/apps/files_external/lib/sftp.php index 95e0cefa39..e3689b751c 100644 --- a/apps/files_external/lib/sftp.php +++ b/apps/files_external/lib/sftp.php @@ -10,6 +10,7 @@ namespace OC\Files\Storage; set_include_path(get_include_path() . PATH_SEPARATOR . \OC_App::getAppPath('files_external') . '/3rdparty/phpseclib/phpseclib'); require 'Net/SFTP.php'; +require 'Net/SFTP/Stream.php'; class SFTP extends \OC\Files\Storage\Common { private $host; @@ -205,16 +206,6 @@ class SFTP extends \OC\Files\Storage\Common { if ( !$this->file_exists($path)) { return false; } - - if (strrpos($path, '.')!==false) { - $ext=substr($path, strrpos($path, '.')); - } else { - $ext=''; - } - $tmp = \OC_Helper::tmpFile($ext); - $this->getFile($absPath, $tmp); - return fopen($tmp, $mode); - case 'w': case 'wb': case 'a': @@ -227,24 +218,8 @@ class SFTP extends \OC\Files\Storage\Common { case 'x+': case 'c': case 'c+': - if (strrpos($path, '.')!==false) { - $ext=substr($path, strrpos($path, '.')); - } else { - $ext=''; - } - - $tmpFile=\OC_Helper::tmpFile($ext); - \OC\Files\Stream\Close::registerCallback( - $tmpFile, - array($this, 'writeBack') - ); - - if ($this->file_exists($path)) { - $this->getFile($absPath, $tmpFile); - } - - self::$tempFiles[$tmpFile]=$absPath; - return fopen('close://'.$tmpFile, $mode); + // FIXME: make client login lazy to prevent it when using fopen() + return fopen($this->constructUrl($path), $mode); } } catch (\Exception $e) { } @@ -309,4 +284,9 @@ class SFTP extends \OC\Files\Storage\Common { return false; } } + + public function constructUrl($path) { + $url = 'sftp://'.$this->user.':'.$this->password.'@'.$this->host.$this->root.$path; + return $url; + } } From 25e9b7a7423da5d8631d365250e7e5e5955b87b2 Mon Sep 17 00:00:00 2001 From: Jan-Christoph Borchardt Date: Tue, 21 Jan 2014 17:39:38 +0100 Subject: [PATCH 086/181] add icons.css file, first step to get rid of %webroot% --- core/css/icons.css | 240 +++++++++++++++++++++++++++++++++++++++++++++ lib/base.php | 1 + 2 files changed, 241 insertions(+) create mode 100644 core/css/icons.css diff --git a/core/css/icons.css b/core/css/icons.css new file mode 100644 index 0000000000..57c37c5c51 --- /dev/null +++ b/core/css/icons.css @@ -0,0 +1,240 @@ +.icon { + background-repeat: no-repeat; + background-position: center; +} + + + + +/* general assets */ + +.icon-breadcrumb { + background-image: url('../img/breadcrumb.svg'); +} + +.icon-loading { + background-image: url('../img/loading.gif'); +} +.icon-loading-dark { + background-image: url('../img/loading-dark.gif'); +} +.icon-loading-small { + background-image: url('../img/loading-small.gif'); +} + +.icon-noise { + background-image: url('../img/noise.png'); + background-repeat: no-repeat; +} + + + + +/* action icons */ + +.icon-add { + background-image: url('../img/actions/add.svg'); +} + +.icon-caret { + background-image: url('../img/actions/caret.svg'); +} +.icon-caret-dark { + background-image: url('../img/actions/caret-dark.svg'); +} + +.icon-checkmark { + background-image: url('../img/actions/checkmark.svg'); +} + +.icon-clock { + background-image: url('../img/actions/clock.svg'); +} + +.icon-close { + background-image: url('../img/actions/close.svg'); +} + +.icon-confirm { + background-image: url('../img/actions/confirm.svg'); +} + +.icon-delete { + background-image: url('../img/actions/delete.svg'); +} +.icon-delete-hover { + background-image: url('../img/actions/delete-hover.svg'); +} + +.icon-download { + background-image: url('../img/actions/download.svg'); +} + +.icon-history { + background-image: url('../img/actions/history.svg'); +} + +.icon-info { + background-image: url('../img/actions/info.svg'); +} + +.icon-lock { + background-image: url('../img/actions/lock.svg'); +} + +.icon-logout { + background-image: url('../img/actions/logout.svg'); +} + +.icon-mail { + background-image: url('../img/actions/mail.svg'); +} + +.icon-more { + background-image: url('../img/actions/more.svg'); +} + +.icon-password { + background-image: url('../img/actions/password.svg'); +} + +.icon-pause { + background-image: url('../img/actions/pause.svg'); +} +.icon-pause-big { + background-image: url('../img/actions/pause-big.svg'); +} + +.icon-play { + background-image: url('../img/actions/play.svg'); +} +.icon-play-add { + background-image: url('../img/actions/play-add.svg'); +} +.icon-play-big { + background-image: url('../img/actions/play-big.svg'); +} +.icon-play-next { + background-image: url('../img/actions/play-next.svg'); +} +.icon-play-previous { + background-image: url('../img/actions/play-previous.svg'); +} + +.icon-public { + background-image: url('../img/actions/public.svg'); +} + +.icon-rename { + background-image: url('../img/actions/rename.svg'); +} + +.icon-search { + background-image: url('../img/actions/search.svg'); +} + +.icon-settings { + background-image: url('../img/actions/settings.svg'); +} + +.icon-share { + background-image: url('../img/actions/share.svg'); +} +.icon-shared { + background-image: url('../img/actions/shared.svg'); +} + +.icon-sound { + background-image: url('../img/actions/sound.svg'); +} +.icon-sound-off { + background-image: url('../img/actions/sound-off.svg'); +} + +.icon-star { + background-image: url('../img/actions/star.svg'); +} + +.icon-starred { + background-image: url('../img/actions/starred.svg'); +} + +.icon-toggle { + background-image: url('../img/actions/toggle.svg'); +} + +.icon-triangle-e { + background-image: url('../img/actions/triangle-e.svg'); +} +.icon-triangle-n { + background-image: url('../img/actions/triangle-n.svg'); +} +.icon-triangle-s { + background-image: url('../img/actions/triangle-s.svg'); +} + +.icon-upload { + background-image: url('../img/actions/upload.svg'); +} +.icon-upload-white { + background-image: url('../img/actions/upload-white.svg'); +} + +.icon-user { + background-image: url('../img/actions/user.svg'); +} + +.icon-view-close { + background-image: url('../img/actions/view-close.svg'); +} +.icon-view-next { + background-image: url('../img/actions/view-next.svg'); +} +.icon-view-pause { + background-image: url('../img/actions/view-pause.svg'); +} +.icon-view-play { + background-image: url('../img/actions/view-play.svg'); +} +.icon-view-previous { + background-image: url('../img/actions/view-previous.svg'); +} + + + + +/* places icons */ + +.icon-calendar-dark { + background-image: url('../img/places/calendar-dark.svg'); +} + +.icon-contacts-dark { + background-image: url('../img/places/contacts-dark.svg'); +} + +.icon-file { + background-image: url('../img/places/file.svg'); +} +.icon-files { + background-image: url('../img/places/files.svg'); +} +.icon-folder { + background-image: url('../img/places/folder.svg'); +} + +.icon-home { + background-image: url('../img/places/home.svg'); +} + +.icon-link { + background-image: url('../img/places/link.svg'); +} + +.icon-music { + background-image: url('../img/places/music.svg'); +} + +.icon-picture { + background-image: url('../img/places/picture.svg'); +} diff --git a/lib/base.php b/lib/base.php index 0597183adc..a1c424017e 100644 --- a/lib/base.php +++ b/lib/base.php @@ -331,6 +331,7 @@ class OC { } OC_Util::addStyle("styles"); + OC_Util::addStyle("icons"); OC_Util::addStyle("apps"); OC_Util::addStyle("fixes"); OC_Util::addStyle("multiselect"); From 809fb8482dd825d43e3af1e98d902424c406ae0a Mon Sep 17 00:00:00 2001 From: Jan-Christoph Borchardt Date: Thu, 23 Jan 2014 13:11:08 +0100 Subject: [PATCH 087/181] remove %webroot% from files app --- apps/files/css/upload.css | 8 -------- apps/files/templates/index.php | 2 +- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/apps/files/css/upload.css b/apps/files/css/upload.css index ef04356909..d44967c7ae 100644 --- a/apps/files/css/upload.css +++ b/apps/files/css/upload.css @@ -18,9 +18,6 @@ margin: -5px -3px; cursor: pointer; z-index: 10; - background-image: url('%webroot%/core/img/actions/upload.svg'); - background-repeat: no-repeat; - background-position: center; opacity: .65; } .file_upload_target { display:none; } @@ -119,11 +116,6 @@ .oc-dialog .fileexists .conflict input[type='checkbox'] { float: left; } -.oc-dialog .fileexists .toggle { - background-image: url('%webroot%/core/img/actions/triangle-e.png'); - width: 16px; - height: 16px; -} .oc-dialog .fileexists #allfileslabel { float:right; } diff --git a/apps/files/templates/index.php b/apps/files/templates/index.php index 00ec109621..5ed1ee0c7a 100644 --- a/apps/files/templates/index.php +++ b/apps/files/templates/index.php @@ -23,7 +23,7 @@ - + > From 4b7dfd34f8adb5db9b7e67206da384973ebdc767 Mon Sep 17 00:00:00 2001 From: Morris Jobke Date: Thu, 23 Jan 2014 13:51:51 +0100 Subject: [PATCH 088/181] fix conflicts and add missing closing tag --- apps/files_sharing/css/public.css | 8 -------- apps/files_sharing/templates/public.php | 2 +- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/apps/files_sharing/css/public.css b/apps/files_sharing/css/public.css index 7bcafd542c..a5762799ac 100644 --- a/apps/files_sharing/css/public.css +++ b/apps/files_sharing/css/public.css @@ -105,11 +105,3 @@ thead{ margin-left: 5px; width: 300px; } - -/*.directLink label {*/ - /*font-weight: normal;*/ -/*}*/ -/*.directLink input {*/ - /*margin-left: 10px;*/ - /*width: 300px;*/ -/*}*/ diff --git a/apps/files_sharing/templates/public.php b/apps/files_sharing/templates/public.php index fd0e0ad641..f8a31005cd 100644 --- a/apps/files_sharing/templates/public.php +++ b/apps/files_sharing/templates/public.php @@ -16,7 +16,7 @@
    t('shared by %s', array($_['displayName']))) ?>
    - +
    From f0c9e8205fdf549f3324c61705896f005e9fe043 Mon Sep 17 00:00:00 2001 From: Jan-Christoph Borchardt Date: Thu, 23 Jan 2014 14:04:13 +0100 Subject: [PATCH 089/181] remove %webroot from files_sharing app --- apps/files_sharing/css/authenticate.css | 7 ++----- apps/files_sharing/css/public.css | 19 +------------------ apps/files_sharing/templates/authenticate.php | 2 +- apps/files_sharing/templates/public.php | 2 +- 4 files changed, 5 insertions(+), 25 deletions(-) diff --git a/apps/files_sharing/css/authenticate.css b/apps/files_sharing/css/authenticate.css index cebe906dd5..ef963ba7c6 100644 --- a/apps/files_sharing/css/authenticate.css +++ b/apps/files_sharing/css/authenticate.css @@ -11,16 +11,13 @@ margin: 6px; } -input[type="submit"]{ +input[type='submit'] { width: 45px; height: 45px; margin: 6px; - background-image: url('%webroot%/core/img/actions/confirm.svg'); - background-repeat: no-repeat; - background-position: center; } -#body-login input[type="submit"] { +#body-login input[type='submit'] { position: absolute; top: 0px; } diff --git a/apps/files_sharing/css/public.css b/apps/files_sharing/css/public.css index 060d4dfedc..9a653459db 100644 --- a/apps/files_sharing/css/public.css +++ b/apps/files_sharing/css/public.css @@ -3,7 +3,7 @@ body { } #header { - background: #1d2d44 url('%webroot%/core/img/noise.png') repeat; + background-color: #1d2d44; height:32px; left:0; line-height:32px; @@ -121,23 +121,6 @@ thead{ width: 100% !important; } -#publicUploadButtonMock { - position:relative; - display:block; - width:100%; - height:32px; - cursor:pointer; - z-index:10; - background-image:url('%webroot%/core/img/actions/upload.svg'); - background-repeat:no-repeat; - background-position:7px 8px; -} - -#publicUploadButtonMock span { - margin: 0 5px 0 28px; - color: #555; -} - .directLink { margin-bottom: 20px; } diff --git a/apps/files_sharing/templates/authenticate.php b/apps/files_sharing/templates/authenticate.php index 6b98e6c9f3..928be93fc9 100644 --- a/apps/files_sharing/templates/authenticate.php +++ b/apps/files_sharing/templates/authenticate.php @@ -9,7 +9,7 @@

    - +

    diff --git a/apps/files_sharing/templates/public.php b/apps/files_sharing/templates/public.php index 1d527dca8e..011963766f 100644 --- a/apps/files_sharing/templates/public.php +++ b/apps/files_sharing/templates/public.php @@ -9,7 +9,7 @@ -
    @@ -110,7 +110,7 @@ true 50 - +
    diff --git a/apps/files_trashbin/appinfo/version b/apps/files_trashbin/appinfo/version index bd73f47072..2eb3c4fe4e 100644 --- a/apps/files_trashbin/appinfo/version +++ b/apps/files_trashbin/appinfo/version @@ -1 +1 @@ -0.4 +0.5 From 5ad28f4d1ff952c17f3ca13c8ea7e2e118965846 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Wed, 27 Nov 2013 12:46:12 +0100 Subject: [PATCH 093/181] Allow getting info or renaming part files through WebDAV When mounting an ownCloud (backend OC) inside another ownCloud (frontend OC), the frontend OC will use WebDAV to upload file, which will create part files. These part files need to be accessible for the frontend OC to rename them to the actual file name. This fix leaves the file cache untouched but gives direct access to part file info when requested. This means that part file can be accessed only when their path and name are known. These won't appear in file listtings. Fixes #6068 --- lib/private/connector/sabre/objecttree.php | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/lib/private/connector/sabre/objecttree.php b/lib/private/connector/sabre/objecttree.php index cd3f081f7c..d1e179af2e 100644 --- a/lib/private/connector/sabre/objecttree.php +++ b/lib/private/connector/sabre/objecttree.php @@ -38,7 +38,20 @@ class ObjectTree extends \Sabre_DAV_ObjectTree { return $this->rootNode; } - $info = $this->getFileView()->getFileInfo($path); + if (pathinfo($path, PATHINFO_EXTENSION) === 'part') { + // read from storage + $absPath = $this->getFileView()->getAbsolutePath($path); + list($storage, $internalPath) = Filesystem::resolvePath('/' . $absPath); + if ($storage) { + $scanner = $storage->getScanner($internalPath); + // get data directly + $info = $scanner->getData($internalPath); + } + } + else { + // read from cache + $info = $this->getFileView()->getFileInfo($path); + } if (!$info) { throw new \Sabre_DAV_Exception_NotFound('File with name ' . $path . ' could not be located'); From 617aa3cf29955a23eed2ececc8e1876d77002223 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Thu, 23 Jan 2014 20:15:10 +0100 Subject: [PATCH 094/181] Instead of 'No preview available for ...' we simple display the mieme-type icon --- apps/files_sharing/js/public.js | 9 +-------- apps/files_sharing/templates/public.php | 20 ++++++++------------ 2 files changed, 9 insertions(+), 20 deletions(-) diff --git a/apps/files_sharing/js/public.js b/apps/files_sharing/js/public.js index d95f6348ac..730649c637 100644 --- a/apps/files_sharing/js/public.js +++ b/apps/files_sharing/js/public.js @@ -15,14 +15,7 @@ $(document).ready(function() { if (mimetype.substr(0, mimetype.indexOf('/')) != 'image' && $('.publicpreview').length === 0) { // Trigger default action if not download TODO var action = FileActions.getDefault(mimetype, 'file', OC.PERMISSION_READ); - if (typeof action === 'undefined') { - $('#noPreview').show(); - if (mimetype != 'httpd/unix-directory') { - // NOTE: Remove when a better file previewer solution exists - $('#content').remove(); - $('table').remove(); - } - } else { + if (typeof action !== 'undefined') { action($('#filename').val()); } } diff --git a/apps/files_sharing/templates/public.php b/apps/files_sharing/templates/public.php index f8a31005cd..652cd74eaf 100644 --- a/apps/files_sharing/templates/public.php +++ b/apps/files_sharing/templates/public.php @@ -32,16 +32,10 @@
    - +
    - -
      -
    • - t('No preview available for').' '.$_['filename']); ?>
      -
    • -
    -
    -

    - getLongFooter()); ?> -

    -
    + + +
    +

    + getLongFooter()); ?> +

    +
    From 4734146580d8175e9e6178097258b7f87e7aba86 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Thu, 23 Jan 2014 20:50:09 +0100 Subject: [PATCH 095/181] Fixed max upload size input field style Added "type=text" makes it look like nice like all other fields --- apps/files/templates/admin.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/files/templates/admin.php b/apps/files/templates/admin.php index 697fc52526..a5afd55fbc 100644 --- a/apps/files/templates/admin.php +++ b/apps/files/templates/admin.php @@ -5,7 +5,7 @@

    t('File handling')); ?>

    - '/> + '/> (t('max. possible: ')); p($_['maxPossibleUploadSize']) ?>) From 269f24cf9617397aaf501b27ec1af2c8e3154cf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Thu, 23 Jan 2014 21:28:19 +0100 Subject: [PATCH 096/181] remove css files from rewrite rule - there is no need to rewrite css any more --- .htaccess | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.htaccess b/.htaccess index fa6263c7ff..4ba5095e14 100755 --- a/.htaccess +++ b/.htaccess @@ -26,7 +26,7 @@ RewriteRule ^.well-known/carddav /remote.php/carddav/ [R] RewriteRule ^.well-known/caldav /remote.php/caldav/ [R] RewriteRule ^apps/calendar/caldav.php remote.php/caldav/ [QSA,L] RewriteRule ^apps/contacts/carddav.php remote.php/carddav/ [QSA,L] -RewriteRule ^apps/([^/]*)/(.*\.(css|php))$ index.php?app=$1&getfile=$2 [QSA,L] +RewriteRule ^apps/([^/]*)/(.*\.(php))$ index.php?app=$1&getfile=$2 [QSA,L] RewriteRule ^remote/(.*) remote.php [QSA,L] From 77de47858b6f53bfa36b84de5e316e6e804ad7ca Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Thu, 23 Jan 2014 11:18:23 +0100 Subject: [PATCH 097/181] add expire date to link share if possible --- core/ajax/share.php | 21 +++++++++++++++++++-- core/js/share.js | 6 +++++- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/core/ajax/share.php b/core/ajax/share.php index be02c05635..268cd4f53a 100644 --- a/core/ajax/share.php +++ b/core/ajax/share.php @@ -119,8 +119,12 @@ if (isset($_POST['action']) && isset($_POST['itemType']) && isset($_POST['itemSo $subject = (string)$l->t('%s shared »%s« with you', array($ownerDisplayName, $filename)); $expiration = null; if (isset($items[0]['expiration'])) { - $date = new DateTime($items[0]['expiration']); - $expiration = $date->format('Y-m-d'); + try { + $date = new DateTime($items[0]['expiration']); + $expiration = $date->format('Y-m-d'); + } catch (Exception $e) { + \OCP\Util::writeLog('sharing', "Couldn't read date: " . $e->getMessage(), \OCP\Util::ERROR); + } } if ($itemType === 'folder') { @@ -191,6 +195,17 @@ if (isset($_POST['action']) && isset($_POST['itemType']) && isset($_POST['itemSo $file = $_POST['file']; $to_address = $_POST['toaddress']; + $expiration = null; + if (isset($_POST['expiration']) && $_POST['expiration'] !== '') { + try { + $date = new DateTime($_POST['expiration']); + $expiration = $date->format('Y-m-d'); + } catch (Exception $e) { + \OCP\Util::writeLog('sharing', "Couldn't read date: " . $e->getMessage(), \OCP\Util::ERROR); + } + + } + // enable l10n support $l = OC_L10N::get('core'); @@ -202,6 +217,7 @@ if (isset($_POST['action']) && isset($_POST['itemType']) && isset($_POST['itemSo $content->assign ('type', $type); $content->assign ('user_displayname', $displayName); $content->assign ('filename', $file); + $content->assign('expiration', $expiration); $text = $content->fetchPage(); $content = new OC_Template("core", "altmail", ""); @@ -209,6 +225,7 @@ if (isset($_POST['action']) && isset($_POST['itemType']) && isset($_POST['itemSo $content->assign ('type', $type); $content->assign ('user_displayname', $displayName); $content->assign ('filename', $file); + $content->assign('expiration', $expiration); $alttext = $content->fetchPage(); $default_from = OCP\Util::getDefaultEmailAddress('sharing-noreply'); diff --git a/core/js/share.js b/core/js/share.js index 3637d2e7e7..0939259b7d 100644 --- a/core/js/share.js +++ b/core/js/share.js @@ -733,12 +733,16 @@ $(document).ready(function() { var itemSource = $('#dropdown').data('item-source'); var file = $('tr').filterAttr('data-id', String(itemSource)).data('file'); var email = $('#email').val(); + var expirationDate = ''; + if ( $('#expirationCheckbox').is(':checked') === true ) { + expirationDate = $( "#expirationDate" ).val(); + } if (email != '') { $('#email').prop('disabled', true); $('#email').val(t('core', 'Sending ...')); $('#emailButton').prop('disabled', true); - $.post(OC.filePath('core', 'ajax', 'share.php'), { action: 'email', toaddress: email, link: link, itemType: itemType, itemSource: itemSource, file: file}, + $.post(OC.filePath('core', 'ajax', 'share.php'), { action: 'email', toaddress: email, link: link, itemType: itemType, itemSource: itemSource, file: file, expiration: expirationDate}, function(result) { $('#email').prop('disabled', false); $('#emailButton').prop('disabled', false); From 2a3cb7ac5ba5a958b212de86dea62735c3f9d503 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Fri, 24 Jan 2014 11:35:52 +0100 Subject: [PATCH 098/181] remove the form, it isn't needed here --- settings/js/personal.js | 5 ++-- settings/templates/personal.php | 42 ++++++++++++++++----------------- 2 files changed, 22 insertions(+), 25 deletions(-) diff --git a/settings/js/personal.js b/settings/js/personal.js index aa55832469..57b69fd7b6 100644 --- a/settings/js/personal.js +++ b/settings/js/personal.js @@ -283,10 +283,9 @@ OC.Encryption = { } else { OC.Encryption.msg.finishedDecrypting('#decryptAll .msg', data); } - } - ); + }); } -} +}; OC.Encryption.msg={ startDecrypting:function(selector){ diff --git a/settings/templates/personal.php b/settings/templates/personal.php index 1518b48b97..a38178e63a 100644 --- a/settings/templates/personal.php +++ b/settings/templates/personal.php @@ -146,29 +146,27 @@ if($_['passwordChangeSupported']) { };?> -
    -
    -

    - t( 'Encryption' ) ); ?> -

    - t( "The encryption app is no longer enabled, please decrypt all your files" )); ?> -

    - - -
    - - -

    +
    +

    + t( 'Encryption' ) ); ?> +

    + t( "The encryption app is no longer enabled, please decrypt all your files" )); ?> +

    + +
    -

    - + + +

    +
    +
    From 6bb27ea76bc007908a1b48b7ee8441347f84296b Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Fri, 24 Jan 2014 12:05:14 +0100 Subject: [PATCH 099/181] disable button and input field during decryption --- settings/js/personal.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/settings/js/personal.js b/settings/js/personal.js index 57b69fd7b6..e6e1d538a1 100644 --- a/settings/js/personal.js +++ b/settings/js/personal.js @@ -206,6 +206,8 @@ $(document).ready(function(){ $('button:button[name="submitDecryptAll"]').click(function() { var privateKeyPassword = $('#decryptAll input:password[id="privateKeyPassword"]').val(); + $('#decryptAll button:button[name="submitDecryptAll"]').prop("disabled", true); + $('#decryptAll input:password[name="privateKeyPassword"]').prop("disabled", true); OC.Encryption.decryptAll(privateKeyPassword); }); @@ -214,6 +216,8 @@ $(document).ready(function(){ if (privateKeyPassword !== '' ) { $('#decryptAll button:button[name="submitDecryptAll"]').removeAttr("disabled"); if(event.which === 13) { + $('#decryptAll button:button[name="submitDecryptAll"]').prop("disabled", true); + $('#decryptAll input:password[name="privateKeyPassword"]').prop("disabled", true); OC.Encryption.decryptAll(privateKeyPassword); } } else { @@ -280,6 +284,7 @@ OC.Encryption = { $.post('ajax/decryptall.php', {password:password}, function(data) { if (data.status === "error") { OC.Encryption.msg.finishedDecrypting('#decryptAll .msg', data); + $('#decryptAll input:password[name="privateKeyPassword"]').removeAttr("disabled"); } else { OC.Encryption.msg.finishedDecrypting('#decryptAll .msg', data); } From 41b6d4b702e8ed32f7ea51edffd0005639f77138 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Fri, 24 Jan 2014 12:44:31 +0100 Subject: [PATCH 100/181] Added OC.buidQueryString() utility function Makes it possible to create query strings by passing a JavaScript hash map and automatically encodes the keys and values. --- core/js/js.js | 28 +++++++++++++++++++++++++ core/js/tests/specs/coreSpec.js | 37 +++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) diff --git a/core/js/js.js b/core/js/js.js index e84f482d67..976027dd06 100644 --- a/core/js/js.js +++ b/core/js/js.js @@ -364,6 +364,34 @@ var OC={ } return result; }, + + /** + * Builds a URL query from a JS map. + * @param params parameter map + * @return string containing a URL query (without question) mark + */ + buildQueryString: function(params) { + var s = ''; + var first = true; + if (!params) { + return s; + } + for (var key in params) { + var value = params[key]; + if (first) { + first = false; + } + else { + s += '&'; + } + s += encodeURIComponent(key); + if (value !== null && typeof(value) !== 'undefined') { + s += '=' + encodeURIComponent(value); + } + } + return s; + }, + /** * Opens a popup with the setting for an app. * @param appid String. The ID of the app e.g. 'calendar', 'contacts' or 'files'. diff --git a/core/js/tests/specs/coreSpec.js b/core/js/tests/specs/coreSpec.js index 827669f270..28c20a0642 100644 --- a/core/js/tests/specs/coreSpec.js +++ b/core/js/tests/specs/coreSpec.js @@ -67,4 +67,41 @@ describe('Core base tests', function() { }); }); }); + describe('Query string building', function() { + it('Returns empty string when empty params', function() { + expect(OC.buildQueryString()).toEqual(''); + expect(OC.buildQueryString({})).toEqual(''); + }); + it('Encodes regular query strings', function() { + expect(OC.buildQueryString({ + a: 'abc', + b: 'def' + })).toEqual('a=abc&b=def'); + }); + it('Encodes special characters', function() { + expect(OC.buildQueryString({ + unicode: '汉字', + })).toEqual('unicode=%E6%B1%89%E5%AD%97'); + expect(OC.buildQueryString({ + b: 'spaace value', + 'space key': 'normalvalue', + 'slash/this': 'amp&ersand' + })).toEqual('b=spaace%20value&space%20key=normalvalue&slash%2Fthis=amp%26ersand'); + }); + it('Encodes data types and empty values', function() { + expect(OC.buildQueryString({ + 'keywithemptystring': '', + 'keywithnull': null, + 'keywithundefined': null, + something: 'else' + })).toEqual('keywithemptystring=&keywithnull&keywithundefined&something=else'); + expect(OC.buildQueryString({ + 'booleanfalse': false, + 'booleantrue': true + })).toEqual('booleanfalse=false&booleantrue=true'); + expect(OC.buildQueryString({ + 'number': 123, + })).toEqual('number=123'); + }); + }); }); From 0671c58e361f2ccf2cd23d73a9712c1a31e838ce Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Fri, 24 Jan 2014 13:19:44 +0100 Subject: [PATCH 101/181] Fixed filelist unit tests hidden params Also added dummy table --- apps/files/tests/js/filelistSpec.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/apps/files/tests/js/filelistSpec.js b/apps/files/tests/js/filelistSpec.js index 6b28a02989..be848e0e0b 100644 --- a/apps/files/tests/js/filelistSpec.js +++ b/apps/files/tests/js/filelistSpec.js @@ -21,11 +21,14 @@ describe('FileList tests', function() { beforeEach(function() { // init horrible parameters - $('').append('body'); - $('').append('body'); + var $body = $('body'); + $body.append(''); + $body.append(''); + // dummy files table + $body.append('
    '); }); afterEach(function() { - $('#dir, #permissions').remove(); + $('#dir, #permissions, #filestable').remove(); }); it('generates file element with correct attributes when calling addFile', function() { var lastMod = new Date(10000); @@ -36,7 +39,7 @@ describe('FileList tests', function() { expect($tr.attr('data-type')).toEqual('file'); expect($tr.attr('data-file')).toEqual('testName.txt'); expect($tr.attr('data-size')).toEqual('1234'); - //expect($tr.attr('data-permissions')).toEqual('31'); + expect($tr.attr('data-permissions')).toEqual('31'); //expect($tr.attr('data-mime')).toEqual('plain/text'); }); it('generates dir element with correct attributes when calling addDir', function() { @@ -48,7 +51,7 @@ describe('FileList tests', function() { expect($tr.attr('data-type')).toEqual('dir'); expect($tr.attr('data-file')).toEqual('testFolder'); expect($tr.attr('data-size')).toEqual('1234'); - //expect($tr.attr('data-permissions')).toEqual('31'); + expect($tr.attr('data-permissions')).toEqual('31'); //expect($tr.attr('data-mime')).toEqual('httpd/unix-directory'); }); }); From c6695bbd764be9f43067c09894e36422c2b92b49 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Fri, 24 Jan 2014 13:32:31 +0100 Subject: [PATCH 102/181] Fixed download URL in public page - Refactored download URL building to make it overridable - Added download URL override in public page - Added JS unit tests for download URL - Added OC.redirect() method to facilitate unit testing --- apps/files/js/fileactions.js | 5 ++- apps/files/js/filelist.js | 14 ++++++ apps/files/tests/js/fileactionsSpec.js | 61 ++++++++++++++++++++++++++ apps/files/tests/js/filelistSpec.js | 6 +++ apps/files_sharing/js/public.js | 16 +++---- core/js/js.js | 6 +++ 6 files changed, 98 insertions(+), 10 deletions(-) create mode 100644 apps/files/tests/js/fileactionsSpec.js diff --git a/apps/files/js/fileactions.js b/apps/files/js/fileactions.js index 74bb711ef3..eb59e71a03 100644 --- a/apps/files/js/fileactions.js +++ b/apps/files/js/fileactions.js @@ -173,7 +173,10 @@ $(document).ready(function () { FileActions.register(downloadScope, 'Download', OC.PERMISSION_READ, function () { return OC.imagePath('core', 'actions/download'); }, function (filename) { - window.location = OC.filePath('files', 'ajax', 'download.php') + '?files=' + encodeURIComponent(filename) + '&dir=' + encodeURIComponent($('#dir').val()); + var url = FileList.getDownloadUrl(filename); + if (url) { + OC.redirect(url); + } }); } $('#fileList tr').each(function () { diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js index 66968ab54c..63fd0f4ce0 100644 --- a/apps/files/js/filelist.js +++ b/apps/files/js/filelist.js @@ -780,6 +780,20 @@ var FileList={ $('#fileList tr.searchresult').each(function(i,e) { $(e).removeClass("searchresult"); }); + }, + + /** + * Returns the download URL of the given file + * @param filename file name of the file + * @param dir optional directory in which the file name is, defaults to the current directory + */ + getDownloadUrl: function(filename, dir) { + var params = { + files: filename, + dir: dir || FileList.getCurrentDirectory(), + download: null + }; + return OC.filePath('files', 'ajax', 'download.php') + '?' + OC.buildQueryString(params); } }; diff --git a/apps/files/tests/js/fileactionsSpec.js b/apps/files/tests/js/fileactionsSpec.js new file mode 100644 index 0000000000..23f7b58dcd --- /dev/null +++ b/apps/files/tests/js/fileactionsSpec.js @@ -0,0 +1,61 @@ +/** +* ownCloud +* +* @author Vincent Petry +* @copyright 2014 Vincent Petry +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the License, or any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. If not, see . +* +*/ +describe('FileActions tests', function() { + beforeEach(function() { + // init horrible parameters + var $body = $('body'); + $body.append(''); + $body.append(''); + // dummy files table + $filesTable = $body.append('
    '); + }); + afterEach(function() { + $('#dir, #permissions, #filestable').remove(); + }); + it('calling display() sets file actions', function() { + // note: download_url is actually the link target, not the actual download URL... + var $tr = FileList.addFile('testName.txt', 1234, new Date(), false, false, {download_url: 'test/download/url'}); + + // no actions before call + expect($tr.find('.action[data-action=Download]').length).toEqual(0); + expect($tr.find('.action[data-action=Rename]').length).toEqual(0); + expect($tr.find('.action.delete').length).toEqual(0); + + FileActions.display($tr.find('td.filename'), true); + + // actions defined after cal + expect($tr.find('.action[data-action=Download]').length).toEqual(1); + expect($tr.find('.action[data-action=Rename]').length).toEqual(1); + expect($tr.find('.action.delete').length).toEqual(1); + }); + it('redirects to download URL when clicking download', function() { + var redirectStub = sinon.stub(OC, 'redirect'); + // note: download_url is actually the link target, not the actual download URL... + var $tr = FileList.addFile('test download File.txt', 1234, new Date(), false, false, {download_url: 'test/download/url'}); + FileActions.display($tr.find('td.filename'), true); + + $tr.find('.action[data-action=Download]').click(); + + expect(redirectStub.calledOnce).toEqual(true); + expect(redirectStub.getCall(0).args[0]).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?files=test%20download%20File.txt&dir=%2Fsubdir&download'); + redirectStub.restore(); + }); +}); diff --git a/apps/files/tests/js/filelistSpec.js b/apps/files/tests/js/filelistSpec.js index be848e0e0b..61e026c072 100644 --- a/apps/files/tests/js/filelistSpec.js +++ b/apps/files/tests/js/filelistSpec.js @@ -32,10 +32,12 @@ describe('FileList tests', function() { }); it('generates file element with correct attributes when calling addFile', function() { var lastMod = new Date(10000); + // note: download_url is actually the link target, not the actual download URL... var $tr = FileList.addFile('testName.txt', 1234, lastMod, false, false, {download_url: 'test/download/url'}); expect($tr).toBeDefined(); expect($tr[0].tagName.toLowerCase()).toEqual('tr'); + expect($tr.find('a:first').attr('href')).toEqual('test/download/url'); expect($tr.attr('data-type')).toEqual('file'); expect($tr.attr('data-file')).toEqual('testName.txt'); expect($tr.attr('data-size')).toEqual('1234'); @@ -54,4 +56,8 @@ describe('FileList tests', function() { expect($tr.attr('data-permissions')).toEqual('31'); //expect($tr.attr('data-mime')).toEqual('httpd/unix-directory'); }); + it('returns correct download URL', function() { + expect(FileList.getDownloadUrl('some file.txt')).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?files=some%20file.txt&dir=%2Fsubdir&download'); + expect(FileList.getDownloadUrl('some file.txt', '/anotherpath/abc')).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?files=some%20file.txt&dir=%2Fanotherpath%2Fabc&download'); + }); }); diff --git a/apps/files_sharing/js/public.js b/apps/files_sharing/js/public.js index 4c0b0ad9d4..79c15623c0 100644 --- a/apps/files_sharing/js/public.js +++ b/apps/files_sharing/js/public.js @@ -34,18 +34,16 @@ $(document).ready(function() { window.location = $(tr).find('a.name').attr('href'); } }); - FileActions.register('file', 'Download', OC.PERMISSION_READ, '', function(filename) { + + // override since the format is different + FileList.getDownloadUrl = function(filename, dir) { + // we use this because we need the service and token attributes var tr = FileList.findFileEl(filename); if (tr.length > 0) { - window.location = $(tr).find('a.name').attr('href'); + return $(tr).find('a.name').attr('href') + '&download'; } - }); - FileActions.register('dir', 'Download', OC.PERMISSION_READ, '', function(filename) { - var tr = FileList.findFileEl(filename); - if (tr.length > 0) { - window.location = $(tr).find('a.name').attr('href')+'&download'; - } - }); + return null; + }; } var file_upload_start = $('#file_upload_start'); diff --git a/core/js/js.js b/core/js/js.js index 976027dd06..1c7d89ea05 100644 --- a/core/js/js.js +++ b/core/js/js.js @@ -252,6 +252,12 @@ var OC={ } return link; }, + /** + * Redirect to the target URL, can also be used for downloads. + */ + redirect: function(targetUrl) { + window.location = targetUrl; + }, /** * get the absolute path to an image file * @param app the app id to which the image belongs From 506393090bf33ea1aa3a18983748e6a5b4078d4d Mon Sep 17 00:00:00 2001 From: Jens-Christian Fischer Date: Fri, 24 Jan 2014 14:04:37 +0100 Subject: [PATCH 103/181] Add 'mail_from_address' configuration In environments where there are rules for the email addresses, the "from address" that owncloud uses has to be configurable. This patch adds a new configuration variable 'mail_from_address'. If it is configured, owncloud will use this as the sender of *all* emails. (OwnCloud uses 'sharing-noreply' and 'password-noreply' by default). By using the 'mail_from_address' configuration, only this email address will be used. --- lib/public/util.php | 1 + tests/lib/util.php | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/lib/public/util.php b/lib/public/util.php index 8e85f9afc3..8514a168b4 100644 --- a/lib/public/util.php +++ b/lib/public/util.php @@ -256,6 +256,7 @@ class Util { * it would return 'lostpassword-noreply@example.com' */ public static function getDefaultEmailAddress($user_part) { + $user_part = \OC_Config::getValue('mail_from_address', $user_part); $host_name = self::getServerHostName(); $host_name = \OC_Config::getValue('mail_domain', $host_name); $defaultEmailAddress = $user_part.'@'.$host_name; diff --git a/tests/lib/util.php b/tests/lib/util.php index 852caaeccc..bfe68f5f68 100644 --- a/tests/lib/util.php +++ b/tests/lib/util.php @@ -88,6 +88,15 @@ class Test_Util extends PHPUnit_Framework_TestCase { OC_Config::deleteKey('mail_domain'); } + function testGetConfiguredEmailAddressFromConfig() { + OC_Config::setValue('mail_domain', 'example.com'); + OC_Config::setValue('mail_from_address', 'owncloud'); + $email = \OCP\Util::getDefaultEmailAddress("no-reply"); + $this->assertEquals('owncloud@example.com', $email); + OC_Config::deleteKey('mail_domain'); + OC_Config::deleteKey('mail_from_address'); + } + function testGetInstanceIdGeneratesValidId() { OC_Config::deleteKey('instanceid'); $this->assertStringStartsWith('oc', OC_Util::getInstanceId()); From 0f6c60717140c885ebb33dfc38d94081a894dd6d Mon Sep 17 00:00:00 2001 From: Jens-Christian Fischer Date: Fri, 24 Jan 2014 14:22:42 +0100 Subject: [PATCH 104/181] added function documentation --- lib/public/util.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/public/util.php b/lib/public/util.php index 8514a168b4..6317f10a66 100644 --- a/lib/public/util.php +++ b/lib/public/util.php @@ -254,6 +254,10 @@ class Util { * Example: when given lostpassword-noreply as $user_part param, * and is currently accessed via http(s)://example.com/, * it would return 'lostpassword-noreply@example.com' + * + * If the configuration value 'mail_from_address' is set in + * config.php, this value will override the $user_part that + * is passed to this function */ public static function getDefaultEmailAddress($user_part) { $user_part = \OC_Config::getValue('mail_from_address', $user_part); From 2f8ebd03b011b705883bf9666b1bdaafb971f110 Mon Sep 17 00:00:00 2001 From: Otto Sabart Date: Fri, 24 Jan 2014 15:52:28 +0100 Subject: [PATCH 105/181] Add check for apc.enabled option Sometimes it's not possible to disable APC entirely and some of apc_functions are disabled. Only thing which is possible is to disable apc.enable option. --- lib/private/memcache/apc.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/private/memcache/apc.php b/lib/private/memcache/apc.php index 575ee4427d..e995cbc526 100644 --- a/lib/private/memcache/apc.php +++ b/lib/private/memcache/apc.php @@ -50,6 +50,8 @@ class APC extends Cache { static public function isAvailable() { if (!extension_loaded('apc')) { return false; + } elseif (!ini_get('apc.enabled')) { + return false; } elseif (!ini_get('apc.enable_cli') && \OC::$CLI) { return false; } else { From 19675c2c9de3580c32ee24b22b8ded11dc110b1c Mon Sep 17 00:00:00 2001 From: Pellaeon Lin Date: Fri, 24 Jan 2014 22:54:16 +0800 Subject: [PATCH 106/181] Fix variable name --- apps/files/js/file-upload.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/files/js/file-upload.js b/apps/files/js/file-upload.js index a003e5eec8..0d7df31f35 100644 --- a/apps/files/js/file-upload.js +++ b/apps/files/js/file-upload.js @@ -246,8 +246,8 @@ $(document).ready(function() { if (selection.totalBytes > $('#free_space').val()) { data.textStatus = 'notenoughspace'; data.errorThrown = t('files', 'Not enough free space, you are uploading {size1} but only {size2} is left', { - '{size1}': humanFileSize(selection.totalBytes), - '{size2}': humanFileSize($('#free_space').val()) + 'size1': humanFileSize(selection.totalBytes), + 'size2': humanFileSize($('#free_space').val()) }); } From 83878b9a7dc364c5f51c2ad7eb0960250e2fe42e Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Thu, 23 Jan 2014 15:45:34 +0100 Subject: [PATCH 107/181] only update file cache with the unenecrypted size when the file was written --- apps/files_encryption/lib/proxy.php | 31 ++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index 4fe76b9771..4e71ab1dd5 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -37,6 +37,7 @@ namespace OCA\Encryption; class Proxy extends \OC_FileProxy { private static $blackList = null; //mimetypes blacklisted from encryption + private static $unencryptedSizes = array(); // remember unencrypted size /** * Check if a file requires encryption @@ -114,14 +115,12 @@ class Proxy extends \OC_FileProxy { // get encrypted content $data = $view->file_get_contents($tmpPath); - // update file cache for target file + // store new unenecrypted size so that it can be updated + // in the post proxy $tmpFileInfo = $view->getFileInfo($tmpPath); - $fileInfo = $view->getFileInfo($path); - if (is_array($fileInfo) && is_array($tmpFileInfo)) { - $fileInfo['encrypted'] = true; - $fileInfo['unencrypted_size'] = $tmpFileInfo['size']; - $view->putFileInfo($path, $fileInfo); - } + if ( isset($tmpFileInfo['size']) ) { + self::$unencryptedSizes[\OC_Filesystem::normalizePath($path)] = $tmpFileInfo['size']; + } // remove our temp file $view->deleteAll('/' . \OCP\User::getUser() . '/cache/' . $cacheFolder); @@ -136,6 +135,24 @@ class Proxy extends \OC_FileProxy { } + /** + * @brief update file cache with the new unencrypted size after file was written + * @param string $path + * @param mixed $result + * @return mixed + */ + public function postFile_put_contents($path, $result) { + $normalizedPath = \OC_Filesystem::normalizePath($path); + if ( isset(self::$unencryptedSizes[$normalizedPath]) ) { + $view = new \OC_FilesystemView('/'); + $view->putFileInfo($normalizedPath, + array('encrypted' => true, 'encrypted_size' => self::$unencryptedSizes[$normalizedPath])); + unset(self::$unencryptedSizes[$normalizedPath]); + } + + return $result; + } + /** * @param string $path Path of file from which has been read * @param string $data Data that has been read from file From 1ab7ca0a19d5f3984e87f99945d81aecffbbae19 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Fri, 24 Jan 2014 16:01:19 +0100 Subject: [PATCH 108/181] Fix some phpdoc errors and rename interface --- lib/private/memcache/factory.php | 4 +++- lib/public/{cachefactory.php => icachefactory.php} | 8 +++++--- lib/public/iservercontainer.php | 2 +- 3 files changed, 9 insertions(+), 5 deletions(-) rename lib/public/{cachefactory.php => icachefactory.php} (64%) diff --git a/lib/private/memcache/factory.php b/lib/private/memcache/factory.php index 48c97b5955..334cf9a1f0 100644 --- a/lib/private/memcache/factory.php +++ b/lib/private/memcache/factory.php @@ -8,7 +8,9 @@ namespace OC\Memcache; -class Factory { +use \OCP\ICacheFactory; + +class Factory implements ICacheFactory { /** * @var string $globalPrefix */ diff --git a/lib/public/cachefactory.php b/lib/public/icachefactory.php similarity index 64% rename from lib/public/cachefactory.php rename to lib/public/icachefactory.php index 1bb0ea3dd5..874f1ec0a5 100644 --- a/lib/public/cachefactory.php +++ b/lib/public/icachefactory.php @@ -8,17 +8,19 @@ namespace OCP; -interface CacheFactory{ +interface ICacheFactory{ /** * Get a memory cache instance * + * All entries added trough the cache instance will be namespaced by $prefix to prevent collisions between apps + * * @param string $prefix - * @return $return \OCP\ICache + * @return \OCP\ICache */ public function create($prefix = ''); /** - * Check if a memory cache backend is available + * Check if any memory cache backend is available * * @return bool */ diff --git a/lib/public/iservercontainer.php b/lib/public/iservercontainer.php index 67884bdc3e..5473f3ee33 100644 --- a/lib/public/iservercontainer.php +++ b/lib/public/iservercontainer.php @@ -144,7 +144,7 @@ interface IServerContainer { /** * Returns an \OCP\CacheFactory instance * - * @return \OCP\CacheFactory + * @return \OCP\ICacheFactory */ function getMemCacheFactory(); From 3ca85cd841bae985082318cba1d88bae9fdac65a Mon Sep 17 00:00:00 2001 From: Jens-Christian Fischer Date: Fri, 24 Jan 2014 16:24:52 +0100 Subject: [PATCH 109/181] updated config.sample.php with mail_from_address parameter --- config/config.sample.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/config/config.sample.php b/config/config.sample.php index 1070ef72ed..01abc58368 100755 --- a/config/config.sample.php +++ b/config/config.sample.php @@ -80,6 +80,12 @@ $CONFIG = array( /* Domain name used by ownCloud for the sender mail address, e.g. no-reply@example.com */ "mail_domain" => "example.com", +/* FROM address used by ownCloud for the sender mail address, e.g. owncloud@example.com + This setting overwrites the built in 'sharing-noreply' and 'lostpassword-noreply' + FROM addresses, that ownCloud uses +*/ +"mail_from_address" => "owncloud", + /* Enable SMTP class debugging */ "mail_smtpdebug" => false, From c767ebcc03c604f3141af4c286ad099fdf64c561 Mon Sep 17 00:00:00 2001 From: Jan-Christoph Borchardt Date: Fri, 24 Jan 2014 18:20:52 +0100 Subject: [PATCH 110/181] fix multiselect bar being too short on big displays --- apps/files/css/files.css | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/files/css/files.css b/apps/files/css/files.css index 74e625f371..1c48d61c4e 100644 --- a/apps/files/css/files.css +++ b/apps/files/css/files.css @@ -103,7 +103,7 @@ table td { } table th#headerName { position: relative; - width: 100em; /* not really sure why this works better than 100% … table styling */ + width: 9999px; /* not really sure why this works better than 100% … table styling */ padding: 0; } #headerName-container { @@ -145,6 +145,7 @@ table.multiselect thead th { } table.multiselect #headerName { position: relative; + width: 9999px; /* when we use 100%, the styling breaks on mobile … table styling */ } table td.selection, table th.selection, table td.fileaction { width:2em; text-align:center; } table td.filename a.name { From 150d3856a0d3d82e3a7a4b4f6ae5899ed047a681 Mon Sep 17 00:00:00 2001 From: Jan-Christoph Borchardt Date: Fri, 24 Jan 2014 18:58:56 +0100 Subject: [PATCH 111/181] prevent autofill for password change settings, prevent leak of existing password, fix #6552 --- settings/templates/personal.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/settings/templates/personal.php b/settings/templates/personal.php index 1518b48b97..07d75587d5 100644 --- a/settings/templates/personal.php +++ b/settings/templates/personal.php @@ -39,9 +39,11 @@ if($_['passwordChangeSupported']) {

    t('Password'));?>

    t('Your password was changed');?>
    t('Unable to change your password');?>
    - + + placeholder="t('New password');?>" + data-typetoggle="#personal-show" autocomplete="off" />
    From 932e8f9f58cb9ce515c07b218b126d453bc3f46a Mon Sep 17 00:00:00 2001 From: raghunayyar Date: Sun, 26 Jan 2014 02:59:28 +0530 Subject: [PATCH 112/181] Fixes width of the dropdown menus as per computed styles. --- apps/files_versions/css/versions.css | 2 +- core/css/share.css | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/files_versions/css/versions.css b/apps/files_versions/css/versions.css index 80fa196b72..16755f35a7 100644 --- a/apps/files_versions/css/versions.css +++ b/apps/files_versions/css/versions.css @@ -1,5 +1,5 @@ #dropdown.drop-versions { - width:384px; + width:320px; } #found_versions li { diff --git a/core/css/share.css b/core/css/share.css index 938afabafe..4ae3b77757 100644 --- a/core/css/share.css +++ b/core/css/share.css @@ -11,7 +11,7 @@ margin-right:112px; position:absolute; right:0; - width:400px; + width:320px; z-index:500; padding:16px; } From 2a0e8329f9f35df33f3e379a6ec99eaf4e1ee973 Mon Sep 17 00:00:00 2001 From: raghunayyar Date: Sun, 26 Jan 2014 03:02:52 +0530 Subject: [PATCH 113/181] Fixes settings.css and converts more styles. --- apps/user_ldap/css/settings.css | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/apps/user_ldap/css/settings.css b/apps/user_ldap/css/settings.css index 44d74926b3..e09c377a90 100644 --- a/apps/user_ldap/css/settings.css +++ b/apps/user_ldap/css/settings.css @@ -33,9 +33,9 @@ width: 100% !important; height: 50px; background-color: lightyellow; - border-radius: 0.5em; - padding: 0.6em 0.5em 0.4em !important; - margin-bottom: 0.3em; + border-radius: 8px; + padding: 10px 8px 6px !important; + margin-bottom: 5px; } #ldapWizard1 .hostPortCombinator { @@ -68,17 +68,17 @@ } .ldapwarning { - margin-left: 1.4em; + margin-left: 22px; color: #FF3B3B; } .wizSpinner { height: 15px; - margin: 0.3em; + margin: 5px; } .ldapSettingControls { - margin-top: 3ex; + margin-top: 3px; } #ldap fieldset p label { @@ -110,10 +110,6 @@ select[multiple=multiple] + button { max-width: 40%; } -.ldapwarning { - margin-left: 22px; - color: #FF3B3B; -} .ldap_config_state_indicator_sign { display: inline-block; height: 16px; From c2ed8d5aa111ac537cf37bbf0d60fd503a62c24a Mon Sep 17 00:00:00 2001 From: Martial Saunois Date: Sun, 26 Jan 2014 18:46:09 +0100 Subject: [PATCH 114/181] New user agent added for the Freebox. The Freebox is the multimedia device of a french Internet provider: Free. This device provides a seedbox which uses the user agent "Mozilla/5.0". In the "Content-Disposition" header, if the "filename" key is used with the "filename*=UTF-8''" value, the seedbox does not take care about the header and saves the file name with the origin URL. This patch brings the support for the Freebox users. --- lib/private/request.php | 1 + lib/private/response.php | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/private/request.php b/lib/private/request.php index d9d5ae08e2..855148ac25 100755 --- a/lib/private/request.php +++ b/lib/private/request.php @@ -11,6 +11,7 @@ class OC_Request { const USER_AGENT_IE = '/MSIE/'; // Android Chrome user agent: https://developers.google.com/chrome/mobile/docs/user-agent const USER_AGENT_ANDROID_MOBILE_CHROME = '#Android.*Chrome/[.0-9]*#'; + const USER_AGENT_FREEBOX = '#Mozilla/5\.0$#'; /** * @brief Check overwrite condition diff --git a/lib/private/response.php b/lib/private/response.php index 0474643734..52dbb9d90f 100644 --- a/lib/private/response.php +++ b/lib/private/response.php @@ -153,7 +153,11 @@ class OC_Response { * @param string $type disposition type, either 'attachment' or 'inline' */ static public function setContentDispositionHeader( $filename, $type = 'attachment' ) { - if (OC_Request::isUserAgent(array(OC_Request::USER_AGENT_IE, OC_Request::USER_AGENT_ANDROID_MOBILE_CHROME))) { + if (OC_Request::isUserAgent(array( + OC_Request::USER_AGENT_IE, + OC_Request::USER_AGENT_ANDROID_MOBILE_CHROME, + OC_Request::USER_AGENT_FREEBOX + ))) { header( 'Content-Disposition: ' . rawurlencode($type) . '; filename="' . rawurlencode( $filename ) . '"' ); } else { header( 'Content-Disposition: ' . rawurlencode($type) . '; filename*=UTF-8\'\'' . rawurlencode( $filename ) From 11ef12a1060f3e34312ae40c690f95765d7c5f89 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Thu, 23 Jan 2014 12:11:53 +0100 Subject: [PATCH 115/181] Added exception logger plugin for sabre connector Whenever an exception occurs in the sabre connector code or code called by it, it will be logged. This plugin approach is needed because Sabre already catches exceptions to return them to the client in the XML response, so they don't appear logged in the web server log. This will make it much easier to debug syncing issues. --- apps/files/appinfo/remote.php | 1 + .../connector/sabre/exceptionloggerplugin.php | 50 +++++++++++++++++++ lib/private/connector/sabre/file.php | 6 +-- lib/public/util.php | 8 ++- 4 files changed, 60 insertions(+), 5 deletions(-) create mode 100644 lib/private/connector/sabre/exceptionloggerplugin.php diff --git a/apps/files/appinfo/remote.php b/apps/files/appinfo/remote.php index 9f29079620..ef22fe9218 100644 --- a/apps/files/appinfo/remote.php +++ b/apps/files/appinfo/remote.php @@ -52,6 +52,7 @@ $server->addPlugin(new OC_Connector_Sabre_FilesPlugin()); $server->addPlugin(new OC_Connector_Sabre_AbortedUploadDetectionPlugin()); $server->addPlugin(new OC_Connector_Sabre_QuotaPlugin()); $server->addPlugin(new OC_Connector_Sabre_MaintenancePlugin()); +$server->addPlugin(new OC_Connector_Sabre_ExceptionLoggerPlugin('webdav')); // And off we go! $server->exec(); diff --git a/lib/private/connector/sabre/exceptionloggerplugin.php b/lib/private/connector/sabre/exceptionloggerplugin.php new file mode 100644 index 0000000000..8e77afaf20 --- /dev/null +++ b/lib/private/connector/sabre/exceptionloggerplugin.php @@ -0,0 +1,50 @@ + + * + * @license AGPL3 + */ + +class OC_Connector_Sabre_ExceptionLoggerPlugin extends Sabre_DAV_ServerPlugin +{ + private $appName; + + /** + * @param string $loggerAppName app name to use when logging + */ + public function __construct($loggerAppName = 'webdav') { + $this->appName = $loggerAppName; + } + + /** + * This initializes the plugin. + * + * This function is called by Sabre_DAV_Server, after + * addPlugin is called. + * + * This method should set up the required event subscriptions. + * + * @param Sabre_DAV_Server $server + * @return void + */ + public function initialize(Sabre_DAV_Server $server) { + + $server->subscribeEvent('exception', array($this, 'logException'), 10); + } + + /** + * Log exception + * + * @internal param Exception $e exception + */ + public function logException($e) { + $exceptionClass = get_class($e); + if ($exceptionClass !== 'Sabre_DAV_Exception_NotAuthenticated') { + \OCP\Util::logException($this->appName, $e); + } + } +} diff --git a/lib/private/connector/sabre/file.php b/lib/private/connector/sabre/file.php index c3b5900729..ed27cef440 100644 --- a/lib/private/connector/sabre/file.php +++ b/lib/private/connector/sabre/file.php @@ -79,7 +79,7 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements Sabre_D \OC_Log::write('webdav', '\OC\Files\Filesystem::file_put_contents() failed', \OC_Log::ERROR); $fs->unlink($partpath); // because we have no clue about the cause we can only throw back a 500/Internal Server Error - throw new Sabre_DAV_Exception(); + throw new Sabre_DAV_Exception('Could not write file contents'); } } catch (\OCP\Files\NotPermittedException $e) { // a more general case - due to whatever reason the content could not be written @@ -105,7 +105,7 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements Sabre_D if ($renameOkay === false || $fileExists === false) { \OC_Log::write('webdav', '\OC\Files\Filesystem::rename() failed', \OC_Log::ERROR); $fs->unlink($partpath); - throw new Sabre_DAV_Exception(); + throw new Sabre_DAV_Exception('Could not rename part file to final file'); } // allow sync clients to send the mtime along in a header @@ -246,7 +246,7 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements Sabre_D if ($fileExists) { $fs->unlink($targetPath); } - throw new Sabre_DAV_Exception(); + throw new Sabre_DAV_Exception('Could not rename part file assembled from chunks'); } // allow sync clients to send the mtime along in a header diff --git a/lib/public/util.php b/lib/public/util.php index 8e85f9afc3..e893a76d81 100644 --- a/lib/public/util.php +++ b/lib/public/util.php @@ -88,14 +88,18 @@ class Util { * @param Exception $ex exception to log */ public static function logException( $app, \Exception $ex ) { - $message = $ex->getMessage(); + $class = get_class($ex); + if ($class !== 'Exception') { + $message = $class . ': '; + } + $message .= $ex->getMessage(); if ($ex->getCode()) { $message .= ' [' . $ex->getCode() . ']'; } \OCP\Util::writeLog($app, 'Exception: ' . $message, \OCP\Util::FATAL); if (defined('DEBUG') and DEBUG) { // also log stack trace - $stack = explode('#', $ex->getTraceAsString()); + $stack = explode("\n", $ex->getTraceAsString()); // first element is empty array_shift($stack); foreach ($stack as $s) { From 2bb13a8db96f8e17d04274b77f5062dca0df5b0e Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Mon, 27 Jan 2014 12:47:54 +0100 Subject: [PATCH 116/181] use localised date in notification mails --- core/ajax/share.php | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/core/ajax/share.php b/core/ajax/share.php index 268cd4f53a..8b48effb45 100644 --- a/core/ajax/share.php +++ b/core/ajax/share.php @@ -121,7 +121,7 @@ if (isset($_POST['action']) && isset($_POST['itemType']) && isset($_POST['itemSo if (isset($items[0]['expiration'])) { try { $date = new DateTime($items[0]['expiration']); - $expiration = $date->format('Y-m-d'); + $expiration = $l->l('date', $date->getTimestamp()); } catch (Exception $e) { \OCP\Util::writeLog('sharing', "Couldn't read date: " . $e->getMessage(), \OCP\Util::ERROR); } @@ -187,6 +187,8 @@ if (isset($_POST['action']) && isset($_POST['itemType']) && isset($_POST['itemSo break; case 'email': + // enable l10n support + $l = OC_L10N::get('core'); // read post variables $user = OCP\USER::getUser(); $displayName = OCP\User::getDisplayName(); @@ -199,16 +201,13 @@ if (isset($_POST['action']) && isset($_POST['itemType']) && isset($_POST['itemSo if (isset($_POST['expiration']) && $_POST['expiration'] !== '') { try { $date = new DateTime($_POST['expiration']); - $expiration = $date->format('Y-m-d'); + $expiration = $l->l('date', $date->getTimestamp()); } catch (Exception $e) { \OCP\Util::writeLog('sharing', "Couldn't read date: " . $e->getMessage(), \OCP\Util::ERROR); } } - // enable l10n support - $l = OC_L10N::get('core'); - // setup the email $subject = (string)$l->t('%s shared »%s« with you', array($displayName, $file)); From b590f019f66c6b540edcf90c35092bf389619c87 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Mon, 27 Jan 2014 16:51:32 +0100 Subject: [PATCH 117/181] Remove unused $freeSpace --- apps/files/index.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/files/index.php b/apps/files/index.php index 8f6838aa0d..2ce8fdb065 100644 --- a/apps/files/index.php +++ b/apps/files/index.php @@ -63,7 +63,6 @@ $files = array(); $user = OC_User::getUser(); if (\OC\Files\Cache\Upgrade::needUpgrade($user)) { //dont load anything if we need to upgrade the cache $needUpgrade = true; - $freeSpace = 0; } else { if ($isIE8){ // after the redirect above, the URL will have a format @@ -77,7 +76,6 @@ if (\OC\Files\Cache\Upgrade::needUpgrade($user)) { //dont load anything if we ne else{ $files = \OCA\Files\Helper::getFiles($dir); } - $freeSpace = \OC\Files\Filesystem::free_space($dir); $needUpgrade = false; } From 7f83f2a8f2e6e3f280c3562ebdbeae9331ab5f01 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Tue, 28 Jan 2014 11:25:12 +0100 Subject: [PATCH 118/181] use more accurate error codes --- apps/files_sharing/lib/api.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/files_sharing/lib/api.php b/apps/files_sharing/lib/api.php index 84e90c7168..cb3d3e42c3 100644 --- a/apps/files_sharing/lib/api.php +++ b/apps/files_sharing/lib/api.php @@ -162,7 +162,7 @@ class Api { $view = new \OC\Files\View('/'.\OCP\User::getUser().'/files'); if(!$view->is_dir($path)) { - return new \OC_OCS_Result(null, 404, "not a directory"); + return new \OC_OCS_Result(null, 400, "not a directory"); } $content = $view->getDirectoryContent($path); @@ -223,7 +223,7 @@ class Api { $encryptionEnabled = \OC_App::isEnabled('files_encryption'); if(isset($_POST['publicUpload']) && ($encryptionEnabled || $publicUploadEnabled !== 'yes')) { - return new \OC_OCS_Result(null, 404, "public upload disabled by the administrator"); + return new \OC_OCS_Result(null, 403, "public upload disabled by the administrator"); } $publicUpload = isset($_POST['publicUpload']) ? $_POST['publicUpload'] : 'false'; // read, create, update (7) if public upload is enabled or @@ -231,7 +231,7 @@ class Api { $permissions = $publicUpload === 'true' ? 7 : 1; break; default: - return new \OC_OCS_Result(null, 404, "unknown share type"); + return new \OC_OCS_Result(null, 400, "unknown share type"); } try { @@ -243,7 +243,7 @@ class Api { $permissions ); } catch (\Exception $e) { - return new \OC_OCS_Result(null, 404, $e->getMessage()); + return new \OC_OCS_Result(null, 403, $e->getMessage()); } if ($token) { @@ -365,7 +365,7 @@ class Api { $publicUploadEnabled = \OC_Appconfig::getValue('core', 'shareapi_allow_public_upload', 'yes'); $encryptionEnabled = \OC_App::isEnabled('files_encryption'); if($encryptionEnabled || $publicUploadEnabled !== 'yes') { - return new \OC_OCS_Result(null, 404, "public upload disabled by the administrator"); + return new \OC_OCS_Result(null, 403, "public upload disabled by the administrator"); } if ($share['item_type'] !== 'folder' || From cd4e044f66c62fc070b48fea40f9a96585f93269 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Tue, 28 Jan 2014 17:28:20 +0100 Subject: [PATCH 119/181] public upload is also possible with encryption enabled, since OC6 --- apps/files_sharing/lib/api.php | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/apps/files_sharing/lib/api.php b/apps/files_sharing/lib/api.php index cb3d3e42c3..f828a4e840 100644 --- a/apps/files_sharing/lib/api.php +++ b/apps/files_sharing/lib/api.php @@ -220,9 +220,7 @@ class Api { $shareWith = isset($_POST['password']) ? $_POST['password'] : null; //check public link share $publicUploadEnabled = \OC_Appconfig::getValue('core', 'shareapi_allow_public_upload', 'yes'); - $encryptionEnabled = \OC_App::isEnabled('files_encryption'); - if(isset($_POST['publicUpload']) && - ($encryptionEnabled || $publicUploadEnabled !== 'yes')) { + if(isset($_POST['publicUpload']) && $publicUploadEnabled !== 'yes') { return new \OC_OCS_Result(null, 403, "public upload disabled by the administrator"); } $publicUpload = isset($_POST['publicUpload']) ? $_POST['publicUpload'] : 'false'; @@ -321,11 +319,8 @@ class Api { $permissions = isset($params['_put']['permissions']) ? (int)$params['_put']['permissions'] : null; $publicUploadStatus = \OC_Appconfig::getValue('core', 'shareapi_allow_public_upload', 'yes'); - $encryptionEnabled = \OC_App::isEnabled('files_encryption'); - $publicUploadEnabled = false; - if(!$encryptionEnabled && $publicUploadStatus === 'yes') { - $publicUploadEnabled = true; - } + $publicUploadEnabled = ($publicUploadStatus === 'yes') ? true : false; + // only change permissions for public shares if public upload is enabled // and we want to set permissions to 1 (read only) or 7 (allow upload) @@ -363,8 +358,7 @@ class Api { private static function updatePublicUpload($share, $params) { $publicUploadEnabled = \OC_Appconfig::getValue('core', 'shareapi_allow_public_upload', 'yes'); - $encryptionEnabled = \OC_App::isEnabled('files_encryption'); - if($encryptionEnabled || $publicUploadEnabled !== 'yes') { + if($publicUploadEnabled !== 'yes') { return new \OC_OCS_Result(null, 403, "public upload disabled by the administrator"); } From 8507efc4273aa87e32090bcabb31b7bc5b98ec35 Mon Sep 17 00:00:00 2001 From: Martial Saunois Date: Tue, 28 Jan 2014 21:08:27 +0100 Subject: [PATCH 120/181] Unit tests added for the new Freebox user agent. --- tests/lib/request.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/lib/request.php b/tests/lib/request.php index c6401a5714..3cb58674d3 100644 --- a/tests/lib/request.php +++ b/tests/lib/request.php @@ -118,6 +118,16 @@ class Test_Request extends PHPUnit_Framework_TestCase { ), true ), + array( + 'Mozilla/5.0 (X11; Linux i686; rv:24.0) Gecko/20100101 Firefox/24.0', + OC_Request::USER_AGENT_FREEBOX, + false + ), + array( + 'Mozilla/5.0', + OC_Request::USER_AGENT_FREEBOX, + true + ), ); } } From e6f93fc84140931d13c8e77b12fd6ec53a04457a Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Wed, 29 Jan 2014 10:43:13 +0100 Subject: [PATCH 121/181] Fix warnings in logs when renaming over the web UI The determineIcon() method was expecting attributes to be set which caused warnings about undefined indices in the error log. This fix pre-initializes the array with 'directory' and 'isPreviewAvailable' to make them disappear. --- apps/files/lib/app.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/files/lib/app.php b/apps/files/lib/app.php index e04ac173d5..1ac266073d 100644 --- a/apps/files/lib/app.php +++ b/apps/files/lib/app.php @@ -83,14 +83,17 @@ class App { else { $meta['type'] = 'file'; } + // these need to be set for determineIcon() + $meta['isPreviewAvailable'] = \OC::$server->getPreviewManager()->isMimeSupported($meta['mimetype']); + $meta['directory'] = $dir; $fileinfo = array( 'id' => $meta['fileid'], 'mime' => $meta['mimetype'], 'size' => $meta['size'], 'etag' => $meta['etag'], - 'directory' => $dir, + 'directory' => $meta['directory'], 'name' => $newname, - 'isPreviewAvailable' => \OC::$server->getPreviewManager()->isMimeSupported($meta['mimetype']), + 'isPreviewAvailable' => $meta['isPreviewAvailable'], 'icon' => \OCA\Files\Helper::determineIcon($meta) ); $result['success'] = true; From 0f1c587e6baaa201f01683b6adac8cc907c4f3e3 Mon Sep 17 00:00:00 2001 From: Martial Saunois Date: Wed, 29 Jan 2014 10:58:34 +0100 Subject: [PATCH 122/181] The regexp of the Freebox user agent is now more strict. A new unit test has been added in consequence. --- lib/private/request.php | 2 +- tests/lib/request.php | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/private/request.php b/lib/private/request.php index 855148ac25..2c5b907846 100755 --- a/lib/private/request.php +++ b/lib/private/request.php @@ -11,7 +11,7 @@ class OC_Request { const USER_AGENT_IE = '/MSIE/'; // Android Chrome user agent: https://developers.google.com/chrome/mobile/docs/user-agent const USER_AGENT_ANDROID_MOBILE_CHROME = '#Android.*Chrome/[.0-9]*#'; - const USER_AGENT_FREEBOX = '#Mozilla/5\.0$#'; + const USER_AGENT_FREEBOX = '#^Mozilla/5\.0$#'; /** * @brief Check overwrite condition diff --git a/tests/lib/request.php b/tests/lib/request.php index 3cb58674d3..1d77acc70a 100644 --- a/tests/lib/request.php +++ b/tests/lib/request.php @@ -128,6 +128,11 @@ class Test_Request extends PHPUnit_Framework_TestCase { OC_Request::USER_AGENT_FREEBOX, true ), + array( + 'Fake Mozilla/5.0', + OC_Request::USER_AGENT_FREEBOX, + false + ), ); } } From 8f81f007cd8189af0b3920c0c5cdf5b7e705c930 Mon Sep 17 00:00:00 2001 From: Jan-Christoph Borchardt Date: Wed, 29 Jan 2014 11:06:19 +0100 Subject: [PATCH 123/181] fix horizontal scrollbar appearing when footer is too long, footer wraps now --- apps/files_sharing/css/public.css | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/files_sharing/css/public.css b/apps/files_sharing/css/public.css index c50624e20b..87e3ed78e1 100644 --- a/apps/files_sharing/css/public.css +++ b/apps/files_sharing/css/public.css @@ -49,9 +49,8 @@ footer { p.info { color: #777; text-align: center; - width: 352px; margin: 0 auto; - padding: 20px; + padding: 20px 0; } p.info a { From d310df505c0de1ed0ba4067a0c8304b8a675fa8c Mon Sep 17 00:00:00 2001 From: Jan-Christoph Borchardt Date: Wed, 29 Jan 2014 11:43:34 +0100 Subject: [PATCH 124/181] permanently show download action on mobile, only icon --- apps/files/js/fileactions.js | 4 ++-- apps/files_sharing/css/mobile.css | 23 +++++++++++++++++------ 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/apps/files/js/fileactions.js b/apps/files/js/fileactions.js index eb59e71a03..d0ef2491bd 100644 --- a/apps/files/js/fileactions.js +++ b/apps/files/js/fileactions.js @@ -103,9 +103,9 @@ var FileActions = { } var html = '
    '; if (img) { - html += ' '; + html += ''; } - html += t('files', name) + ''; + html += ' ' + t('files', name) + ''; var element = $(html); element.data('action', name); diff --git a/apps/files_sharing/css/mobile.css b/apps/files_sharing/css/mobile.css index 2118cd31e4..3c06d0650e 100644 --- a/apps/files_sharing/css/mobile.css +++ b/apps/files_sharing/css/mobile.css @@ -11,12 +11,7 @@ table td.date { /* restrict length of displayed filename to prevent overflow */ table td.filename .nametext { - max-width: 80% !important; -} -/* and to make room for download button on hover */ -table tr:hover td.filename .nametext, -table tr:focus td.filename .nametext { - max-width: 60% !important; + max-width: 75% !important; } /* on mobile, show single shared image at full width without margin */ @@ -26,5 +21,21 @@ table tr:focus td.filename .nametext { margin-bottom: 35px; } +/* always show actions on mobile */ +#fileList a.action { + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=20)" !important; + filter: alpha(opacity=20) !important; + opacity: .2 !important; + display: inline !important; +} +/* some padding for better clickability */ +#fileList a.action img { + padding: 0 6px 0 12px; +} +/* hide text of the actions on mobile */ +#fileList a.action span { + display: none; +} + } From 58c7042e708172b8e2fe252fc53abe87bcf8c1f1 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Wed, 22 Jan 2014 17:17:58 +0100 Subject: [PATCH 125/181] Added error message for when target folder was removed Whent trying to upload/rename/create files in a folder that was removed or rename, the correct error message is now shown. In the case of upload of multiple files, the upload is cancelled. This situation can happen if the target folder was renamed or removed from another browser window or client. --- apps/files/ajax/newfile.php | 9 ++++++ apps/files/ajax/newfolder.php | 9 ++++++ apps/files/ajax/upload.php | 6 ++-- apps/files/js/file-upload.js | 7 +++++ apps/files/lib/app.php | 7 +++++ apps/files/tests/ajax_rename.php | 49 ++++++++++++++++++++++++++++++-- 6 files changed, 83 insertions(+), 4 deletions(-) diff --git a/apps/files/ajax/newfile.php b/apps/files/ajax/newfile.php index ec5b716fb2..1853098c50 100644 --- a/apps/files/ajax/newfile.php +++ b/apps/files/ajax/newfile.php @@ -64,6 +64,15 @@ if(strpos($filename, '/') !== false) { exit(); } +if (!\OC\Files\Filesystem::file_exists($dir . '/')) { + $result['data'] = array('message' => (string)$l10n->t( + 'The target folder has been moved or deleted.'), + 'code' => 'targetnotfound' + ); + OCP\JSON::error($result); + exit(); +} + //TODO why is stripslashes used on foldername in newfolder.php but not here? $target = $dir.'/'.$filename; diff --git a/apps/files/ajax/newfolder.php b/apps/files/ajax/newfolder.php index 2cbc8cfeba..4cfcae3090 100644 --- a/apps/files/ajax/newfolder.php +++ b/apps/files/ajax/newfolder.php @@ -29,6 +29,15 @@ if(strpos($foldername, '/') !== false) { exit(); } +if (!\OC\Files\Filesystem::file_exists($dir . '/')) { + $result['data'] = array('message' => (string)$l10n->t( + 'The target folder has been moved or deleted.'), + 'code' => 'targetnotfound' + ); + OCP\JSON::error($result); + exit(); +} + //TODO why is stripslashes used on foldername here but not in newfile.php? $target = $dir . '/' . stripslashes($foldername); diff --git a/apps/files/ajax/upload.php b/apps/files/ajax/upload.php index bdaf6a77d1..8f6c42d662 100644 --- a/apps/files/ajax/upload.php +++ b/apps/files/ajax/upload.php @@ -8,6 +8,7 @@ OCP\JSON::setContentTypeHeader('text/plain'); // If no token is sent along, rely on login only $allowedPermissions = OCP\PERMISSION_ALL; +$errorCode = null; $l = OC_L10N::get('files'); if (empty($_POST['dirToken'])) { @@ -125,7 +126,8 @@ if (strpos($dir, '..') === false) { $meta = \OC\Files\Filesystem::getFileInfo($target); if ($meta === false) { - $error = $l->t('Upload failed. Could not get file info.'); + $error = $l->t('The target folder has been moved or deleted.'); + $errorCode = 'targetnotfound'; } else { $result[] = array('status' => 'success', 'mime' => $meta['mimetype'], @@ -177,5 +179,5 @@ if ($error === false) { OCP\JSON::encodedPrint($result); exit(); } else { - OCP\JSON::error(array(array('data' => array_merge(array('message' => $error), $storageStats)))); + OCP\JSON::error(array(array('data' => array_merge(array('message' => $error, 'code' => $errorCode), $storageStats)))); } diff --git a/apps/files/js/file-upload.js b/apps/files/js/file-upload.js index 225c331910..486273a910 100644 --- a/apps/files/js/file-upload.js +++ b/apps/files/js/file-upload.js @@ -315,6 +315,13 @@ $(document).ready(function() { } else { // HTTP connection problem OC.Notification.show(data.errorThrown); + if (data.result) { + var result = JSON.parse(data.result); + if (result && result[0] && result[0].data && result[0].data.code === 'targetnotfound') { + // abort upload of next files if any + OC.Upload.cancelUploads(); + } + } } //hide notification after 10 sec setTimeout(function() { diff --git a/apps/files/lib/app.php b/apps/files/lib/app.php index 1ac266073d..fea88faa92 100644 --- a/apps/files/lib/app.php +++ b/apps/files/lib/app.php @@ -59,6 +59,13 @@ class App { $result['data'] = array( 'message' => $this->l10n->t("Invalid folder name. Usage of 'Shared' is reserved.") ); + // rename to non-existing folder is denied + } else if (!$this->view->file_exists($dir)) { + $result['data'] = array('message' => (string)$this->l10n->t( + 'The target folder has been moved or deleted.', + array($dir)), + 'code' => 'targetnotfound' + ); // rename to existing file is denied } else if ($this->view->file_exists($dir . '/' . $newname)) { diff --git a/apps/files/tests/ajax_rename.php b/apps/files/tests/ajax_rename.php index 350ff5d368..a1a5c8983b 100644 --- a/apps/files/tests/ajax_rename.php +++ b/apps/files/tests/ajax_rename.php @@ -38,7 +38,7 @@ class Test_OC_Files_App_Rename extends \PHPUnit_Framework_TestCase { $l10nMock->expects($this->any()) ->method('t') ->will($this->returnArgument(0)); - $viewMock = $this->getMock('\OC\Files\View', array('rename', 'normalizePath', 'getFileInfo'), array(), '', false); + $viewMock = $this->getMock('\OC\Files\View', array('rename', 'normalizePath', 'getFileInfo', 'file_exists'), array(), '', false); $viewMock->expects($this->any()) ->method('normalizePath') ->will($this->returnArgument(0)); @@ -63,6 +63,11 @@ class Test_OC_Files_App_Rename extends \PHPUnit_Framework_TestCase { $oldname = 'Shared'; $newname = 'new_name'; + $this->viewMock->expects($this->at(0)) + ->method('file_exists') + ->with('/') + ->will($this->returnValue(true)); + $result = $this->files->rename($dir, $oldname, $newname); $expected = array( 'success' => false, @@ -80,6 +85,11 @@ class Test_OC_Files_App_Rename extends \PHPUnit_Framework_TestCase { $oldname = 'Shared'; $newname = 'new_name'; + $this->viewMock->expects($this->at(0)) + ->method('file_exists') + ->with('/test') + ->will($this->returnValue(true)); + $this->viewMock->expects($this->any()) ->method('getFileInfo') ->will($this->returnValue(array( @@ -129,6 +139,11 @@ class Test_OC_Files_App_Rename extends \PHPUnit_Framework_TestCase { $oldname = 'oldname'; $newname = 'newname'; + $this->viewMock->expects($this->at(0)) + ->method('file_exists') + ->with('/') + ->will($this->returnValue(true)); + $this->viewMock->expects($this->any()) ->method('getFileInfo') ->will($this->returnValue(array( @@ -141,7 +156,6 @@ class Test_OC_Files_App_Rename extends \PHPUnit_Framework_TestCase { 'name' => 'new_name', ))); - $result = $this->files->rename($dir, $oldname, $newname); $this->assertTrue($result['success']); @@ -154,4 +168,35 @@ class Test_OC_Files_App_Rename extends \PHPUnit_Framework_TestCase { $this->assertEquals(\OC_Helper::mimetypeIcon('dir'), $result['data']['icon']); $this->assertFalse($result['data']['isPreviewAvailable']); } + + /** + * Test rename inside a folder that doesn't exist any more + */ + function testRenameInNonExistingFolder() { + $dir = '/unexist'; + $oldname = 'oldname'; + $newname = 'newname'; + + $this->viewMock->expects($this->at(0)) + ->method('file_exists') + ->with('/unexist') + ->will($this->returnValue(false)); + + $this->viewMock->expects($this->any()) + ->method('getFileInfo') + ->will($this->returnValue(array( + 'fileid' => 123, + 'type' => 'dir', + 'mimetype' => 'httpd/unix-directory', + 'size' => 18, + 'etag' => 'abcdef', + 'directory' => '/unexist', + 'name' => 'new_name', + ))); + + $result = $this->files->rename($dir, $oldname, $newname); + + $this->assertFalse($result['success']); + $this->assertEquals('targetnotfound', $result['data']['code']); + } } From f798ad9a205ce43265e01e670f5a57611ee65711 Mon Sep 17 00:00:00 2001 From: jbtbnl Date: Wed, 29 Jan 2014 13:47:37 +0100 Subject: [PATCH 126/181] Add white color variant of checkmark icon --- core/css/icons.css | 4 ++++ core/img/actions/checkmark-white.png | Bin 0 -> 286 bytes core/img/actions/checkmark-white.svg | 4 ++++ 3 files changed, 8 insertions(+) create mode 100644 core/img/actions/checkmark-white.png create mode 100644 core/img/actions/checkmark-white.svg diff --git a/core/css/icons.css b/core/css/icons.css index 57c37c5c51..2dc3508412 100644 --- a/core/css/icons.css +++ b/core/css/icons.css @@ -47,6 +47,10 @@ background-image: url('../img/actions/checkmark.svg'); } +.icon-checkmark-white { + background-image: url('../img/actions/checkmark-white.svg'); +} + .icon-clock { background-image: url('../img/actions/clock.svg'); } diff --git a/core/img/actions/checkmark-white.png b/core/img/actions/checkmark-white.png new file mode 100644 index 0000000000000000000000000000000000000000..08b8783649f2a4cd77c29b96674fe2e78afc53c8 GIT binary patch literal 286 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4()zHt)6I2xKt)eO%Q>6UV+nj3E=!kueBt{rxZ{b1rT9tRBVJ+K|J&cR zzRBt|^@`TT{Q@RV9FxWQ?r-aEb~jt`INMR&ef`X(O?+ZA7XM}3w`eBUw2KG$)|!9# zaPnwVsL_tI2gG?EeN8&ZVgA%|d4U#(#B>k87t0I$CQP1l;q<}OrUuP#5#4;#vLC*m b|B_Fu;{~gV^3$zAXEJ!Y`njxgN@xNAF(_;n literal 0 HcmV?d00001 diff --git a/core/img/actions/checkmark-white.svg b/core/img/actions/checkmark-white.svg new file mode 100644 index 0000000000..5e8fe8abcc --- /dev/null +++ b/core/img/actions/checkmark-white.svg @@ -0,0 +1,4 @@ +image/svg+xml + + + From 929c930b0afd682bb98eb389d7ebad91bb34d643 Mon Sep 17 00:00:00 2001 From: Pellaeon Lin Date: Wed, 29 Jan 2014 21:24:31 +0800 Subject: [PATCH 127/181] Use $storageInfo['free'] --- apps/files/index.php | 2 +- apps/files/lib/helper.php | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/files/index.php b/apps/files/index.php index c8b04bd462..61b32bc6fe 100644 --- a/apps/files/index.php +++ b/apps/files/index.php @@ -103,7 +103,7 @@ if ($needUpgrade) { } else { // information about storage capacities $storageInfo=OC_Helper::getStorageInfo($dir); - $freeSpace=OCP\Util::freeSpace($dir); + $freeSpace=$storageInfo['free']; $uploadLimit=OCP\Util::uploadLimit(); $maxUploadFilesize=OCP\Util::maxUploadFilesize($dir); $publicUploadEnabled = \OC_Appconfig::getValue('core', 'shareapi_allow_public_upload', 'yes'); diff --git a/apps/files/lib/helper.php b/apps/files/lib/helper.php index e2f545e9e3..21d1f50e58 100644 --- a/apps/files/lib/helper.php +++ b/apps/files/lib/helper.php @@ -6,7 +6,6 @@ class Helper { public static function buildFileStorageStatistics($dir) { $l = new \OC_L10N('files'); - $freeSpace=\OCP\Util::freeSpace($dir); $maxUploadFilesize = \OCP\Util::maxUploadFilesize($dir); $maxHumanFilesize = \OCP\Util::humanFileSize($maxUploadFilesize); $maxHumanFilesize = $l->t('Upload') . ' max. ' . $maxHumanFilesize; @@ -16,7 +15,7 @@ class Helper return array('uploadMaxFilesize' => $maxUploadFilesize, 'maxHumanFilesize' => $maxHumanFilesize, - 'freeSpace' => $freeSpace, + 'freeSpace' => $storageInfo['free'], 'usedSpacePercent' => (int)$storageInfo['relative']); } From 229f13adc0eca770c07646e56773f1aa93fee643 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Wed, 29 Jan 2014 14:40:59 +0100 Subject: [PATCH 128/181] change order of issubdirectory() calls to avoid error messages for non-apps --- lib/private/l10n.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/private/l10n.php b/lib/private/l10n.php index 98665c84c5..1aa1dc5ea2 100644 --- a/lib/private/l10n.php +++ b/lib/private/l10n.php @@ -132,10 +132,10 @@ class OC_L10N implements \OCP\IL10N { $i18ndir = self::findI18nDir($app); // Localization is in /l10n, Texts are in $i18ndir // (Just no need to define date/time format etc. twice) - if((OC_Helper::issubdirectory($i18ndir.$lang.'.php', OC_App::getAppPath($app).'/l10n/') - || OC_Helper::issubdirectory($i18ndir.$lang.'.php', OC::$SERVERROOT.'/core/l10n/') + if((OC_Helper::issubdirectory($i18ndir.$lang.'.php', OC::$SERVERROOT.'/core/l10n/') || OC_Helper::issubdirectory($i18ndir.$lang.'.php', OC::$SERVERROOT.'/lib/l10n/') || OC_Helper::issubdirectory($i18ndir.$lang.'.php', OC::$SERVERROOT.'/settings') + || OC_Helper::issubdirectory($i18ndir.$lang.'.php', OC_App::getAppPath($app).'/l10n/') ) && file_exists($i18ndir.$lang.'.php')) { // Include the file, save the data from $CONFIG From 5a869732d1e3bff7e2c1afdb7b15c77c31b4b1cc Mon Sep 17 00:00:00 2001 From: Jan-Christoph Borchardt Date: Wed, 29 Jan 2014 15:28:57 +0100 Subject: [PATCH 129/181] adjust file type icon placement for when no preview can be generated --- apps/files_sharing/css/mobile.css | 4 ++++ apps/files_sharing/css/public.css | 5 +++++ apps/files_sharing/templates/public.php | 2 +- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/apps/files_sharing/css/mobile.css b/apps/files_sharing/css/mobile.css index 3c06d0650e..3312983b64 100644 --- a/apps/files_sharing/css/mobile.css +++ b/apps/files_sharing/css/mobile.css @@ -20,6 +20,10 @@ table td.filename .nametext { padding: 0; margin-bottom: 35px; } +/* some margin for the file type icon */ +#imgframe .publicpreview { + margin-top: 32px; +} /* always show actions on mobile */ #fileList a.action { diff --git a/apps/files_sharing/css/public.css b/apps/files_sharing/css/public.css index 87e3ed78e1..21f0c82b82 100644 --- a/apps/files_sharing/css/public.css +++ b/apps/files_sharing/css/public.css @@ -71,6 +71,11 @@ p.info a { max-width:100%; } +/* some margin for the file type icon */ +#imgframe .publicpreview { + margin-top: 10%; +} + thead { padding-left: 0 !important; /* fixes multiselect bar offset on shared page */ } diff --git a/apps/files_sharing/templates/public.php b/apps/files_sharing/templates/public.php index 2f9c7246be..5804f606d9 100644 --- a/apps/files_sharing/templates/public.php +++ b/apps/files_sharing/templates/public.php @@ -34,7 +34,7 @@
    - +
    From 7655728ddf4edcb02eb2e997e0d16567ee238460 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Wed, 29 Jan 2014 16:52:30 +0100 Subject: [PATCH 130/181] - adding class to header div: share-folder or share-file - for supported previews are shown with a size of 500px; icons with a size of 128px --- apps/files_sharing/templates/public.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/files_sharing/templates/public.php b/apps/files_sharing/templates/public.php index 5804f606d9..3ddaf4446d 100644 --- a/apps/files_sharing/templates/public.php +++ b/apps/files_sharing/templates/public.php @@ -9,7 +9,7 @@ -
    @@ -149,11 +149,11 @@

    + value="" autocomplete="off" />

    + value="" /> @@ -161,7 +161,7 @@

    @@ -169,14 +169,14 @@

    + value="" autocomplete="off" />

    + value="" />

    From d8ec7e270167594ed407b22cb9ae78b1501ca946 Mon Sep 17 00:00:00 2001 From: Bart Visscher Date: Fri, 31 Jan 2014 17:31:19 +0100 Subject: [PATCH 143/181] DRY for database type radiolist --- core/setup/controller.php | 17 +++++++++ core/templates/installation.php | 62 +++++---------------------------- 2 files changed, 25 insertions(+), 54 deletions(-) diff --git a/core/setup/controller.php b/core/setup/controller.php index 5189aba2f3..c628bda609 100644 --- a/core/setup/controller.php +++ b/core/setup/controller.php @@ -85,6 +85,22 @@ class Controller { $hasPostgreSQL = is_callable('pg_connect'); $hasOracle = is_callable('oci_connect'); $hasMSSQL = is_callable('sqlsrv_connect'); + $databases = array(); + if ($hasSQLite) { + $databases['sqlite'] = 'SQLite'; + } + if ($hasMySQL) { + $databases['mysql'] = 'MySQL'; + } + if ($hasPostgreSQL) { + $databases['pgsql'] = 'PostgreSQL'; + } + if ($hasOracle) { + $databases['oci'] = 'Oracle'; + } + if ($hasMSSQL) { + $databases['mssql'] = 'MS SQL'; + } $datadir = \OC_Config::getValue('datadirectory', \OC::$SERVERROOT.'/data'); $vulnerableToNullByte = false; if(@file_exists(__FILE__."\0Nullbyte")) { // Check if the used PHP version is vulnerable to the NULL Byte attack (CVE-2006-7243) @@ -111,6 +127,7 @@ class Controller { 'hasPostgreSQL' => $hasPostgreSQL, 'hasOracle' => $hasOracle, 'hasMSSQL' => $hasMSSQL, + 'databases' => $databases, 'directory' => $datadir, 'secureRNG' => \OC_Util::secureRNGAvailable(), 'htaccessWorking' => $htaccessWorking, diff --git a/core/templates/installation.php b/core/templates/installation.php index 7e216d0ee9..9356e62aa6 100644 --- a/core/templates/installation.php +++ b/core/templates/installation.php @@ -86,62 +86,16 @@ $hasOtherDB = true; else $hasOtherDB =false; //other than SQLite ?> t( 'Configure the database' )); ?>
    - - - -

    SQLite t( 'will be used' )); ?>.

    - + $label): ?> + +

    t( 'will be used' )); ?>.

    + - /> - - - - - - - -

    MySQL t( 'will be used' )); ?>.

    - - - /> - - - - - - -

    PostgreSQL t( 'will be used' )); ?>.

    - - - - /> - - - - - -

    Oracle t( 'will be used' )); ?>.

    - - - - /> - - - - - - -

    MS SQL t( 'will be used' )); ?>.

    - - - - /> - + /> + +
    From f1c60c7f8b12180917828775fcf4ba82ba68d573 Mon Sep 17 00:00:00 2001 From: Bart Visscher Date: Fri, 31 Jan 2014 17:33:15 +0100 Subject: [PATCH 144/181] Remove unused functions from OC_Helper init_var and init_radio where only used in the installation template --- lib/private/helper.php | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/lib/private/helper.php b/lib/private/helper.php index 58bee9c630..ce5708e2bb 100644 --- a/lib/private/helper.php +++ b/lib/private/helper.php @@ -448,29 +448,6 @@ class OC_Helper { * */ - //FIXME: should also check for value validation (i.e. the email is an email). - public static function init_var($s, $d = "") { - $r = $d; - if (isset($_REQUEST[$s]) && !empty($_REQUEST[$s])) { - $r = OC_Util::sanitizeHTML($_REQUEST[$s]); - } - - return $r; - } - - /** - * returns "checked"-attribute if request contains selected radio element - * OR if radio element is the default one -- maybe? - * - * @param string $s Name of radio-button element name - * @param string $v Value of current radio-button element - * @param string $d Value of default radio-button element - */ - public static function init_radio($s, $v, $d) { - if ((isset($_REQUEST[$s]) && $_REQUEST[$s] == $v) || (!isset($_REQUEST[$s]) && $v == $d)) - print "checked=\"checked\" "; - } - /** * detect if a given program is found in the search PATH * From 5610842e5669ed17983d219f6c779316f209ba92 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Fri, 31 Jan 2014 20:38:35 +0100 Subject: [PATCH 145/181] move unlink proxy to a hook which handles pre and post conditions --- apps/files_encryption/hooks/hooks.php | 64 +++++++++++++++++++++++++++ apps/files_encryption/lib/helper.php | 2 + apps/files_encryption/lib/proxy.php | 41 ----------------- 3 files changed, 66 insertions(+), 41 deletions(-) diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php index 09d5687e22..4c4b3f2040 100644 --- a/apps/files_encryption/hooks/hooks.php +++ b/apps/files_encryption/hooks/hooks.php @@ -32,6 +32,8 @@ class Hooks { // file for which we want to rename the keys after the rename operation was successful private static $renamedFiles = array(); + // file for which we want to delete the keys after the delete operation was successful + private static $deleteFiles = array(); /** * @brief Startup encryption backend upon user login @@ -630,4 +632,66 @@ class Hooks { } } + /** + * @brief if the file was really deleted we remove the encryption keys + * @param array $params + * @return boolean + */ + public static function postDelete($params) { + + if (!isset(self::$deleteFiles[$params[\OC\Files\Filesystem::signal_param_path]])) { + return true; + } + + $deletedFile = self::$deleteFiles[$params[\OC\Files\Filesystem::signal_param_path]]; + $path = $deletedFile['path']; + $user = $deletedFile['uid']; + + // we don't need to remember the file any longer + unset(self::$deleteFiles[$params[\OC\Files\Filesystem::signal_param_path]]); + + $view = new \OC\Files\View('/'); + + // return if the file still exists and wasn't deleted correctly + if ($view->file_exists('/' . $user . '/files/' . $path)) { + return true; + } + + // Disable encryption proxy to prevent recursive calls + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; + + // Delete keyfile & shareKey so it isn't orphaned + if (!Keymanager::deleteFileKey($view, $path, $user)) { + \OCP\Util::writeLog('Encryption library', + 'Keyfile or shareKey could not be deleted for file "' . $user.'/files/'.$path . '"', \OCP\Util::ERROR); + } + + Keymanager::delAllShareKeys($view, $user, $path); + + \OC_FileProxy::$enabled = $proxyStatus; + } + + /** + * @brief remember the file which should be deleted and it's owner + * @param array $params + * @return boolean + */ + public static function preDelete($params) { + $path = $params[\OC\Files\Filesystem::signal_param_path]; + + // skip this method if the trash bin is enabled or if we delete a file + // outside of /data/user/files + if (\OCP\App::isEnabled('files_trashbin')) { + return true; + } + + $util = new Util(new \OC_FilesystemView('/'), \OCP\USER::getUser()); + list($owner, $ownerPath) = $util->getUidAndFilename($path); + + self::$deleteFiles[$params[\OC\Files\Filesystem::signal_param_path]] = array( + 'uid' => $owner, + 'path' => $ownerPath); + } + } diff --git a/apps/files_encryption/lib/helper.php b/apps/files_encryption/lib/helper.php index 5dcb05fa19..bb06a57c71 100755 --- a/apps/files_encryption/lib/helper.php +++ b/apps/files_encryption/lib/helper.php @@ -63,6 +63,8 @@ class Helper { \OCP\Util::connectHook('OC_Filesystem', 'rename', 'OCA\Encryption\Hooks', 'preRename'); \OCP\Util::connectHook('OC_Filesystem', 'post_rename', 'OCA\Encryption\Hooks', 'postRename'); + \OCP\Util::connectHook('OC_Filesystem', 'post_delete', 'OCA\Encryption\Hooks', 'postDelete'); + \OCP\Util::connectHook('OC_Filesystem', 'delete', 'OCA\Encryption\Hooks', 'preDelete'); } /** diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index 4e71ab1dd5..1104800596 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -203,47 +203,6 @@ class Proxy extends \OC_FileProxy { } - /** - * @brief When a file is deleted, remove its keyfile also - */ - public function preUnlink($path) { - - $relPath = Helper::stripUserFilesPath($path); - - // skip this method if the trash bin is enabled or if we delete a file - // outside of /data/user/files - if (\OCP\App::isEnabled('files_trashbin') || $relPath === false) { - return true; - } - - // Disable encryption proxy to prevent recursive calls - $proxyStatus = \OC_FileProxy::$enabled; - \OC_FileProxy::$enabled = false; - - $view = new \OC_FilesystemView('/'); - - $userId = \OCP\USER::getUser(); - - $util = new Util($view, $userId); - - list($owner, $ownerPath) = $util->getUidAndFilename($relPath); - - // Delete keyfile & shareKey so it isn't orphaned - if (!Keymanager::deleteFileKey($view, $ownerPath)) { - \OCP\Util::writeLog('Encryption library', - 'Keyfile or shareKey could not be deleted for file "' . $ownerPath . '"', \OCP\Util::ERROR); - } - - Keymanager::delAllShareKeys($view, $owner, $ownerPath); - - \OC_FileProxy::$enabled = $proxyStatus; - - // If we don't return true then file delete will fail; better - // to leave orphaned keyfiles than to disallow file deletion - return true; - - } - /** * @param $path * @return bool From 4d1086c35fa8aed35ba8cdef75764564e75ba769 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Fri, 31 Jan 2014 20:39:11 +0100 Subject: [PATCH 146/181] better error detection and don't use glob() --- apps/files_encryption/lib/keymanager.php | 39 ++++++++++++++++-------- 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/apps/files_encryption/lib/keymanager.php b/apps/files_encryption/lib/keymanager.php index b2c756894b..17b8180bfd 100755 --- a/apps/files_encryption/lib/keymanager.php +++ b/apps/files_encryption/lib/keymanager.php @@ -214,15 +214,24 @@ class Keymanager { * * @param \OC_FilesystemView $view * @param string $path path of the file the key belongs to + * @param string $userId the user to whom the file belongs * @return bool Outcome of unlink operation * @note $path must be relative to data/user/files. e.g. mydoc.txt NOT * /data/admin/files/mydoc.txt */ - public static function deleteFileKey(\OC_FilesystemView $view, $path) { + public static function deleteFileKey($view, $path, $userId=null) { $trimmed = ltrim($path, '/'); - $userId = Helper::getUser($path); + if ($trimmed === '') { + \OCP\Util::writeLog('Encryption library', + 'Can\'t delete file-key empty path given!', \OCP\Util::ERROR); + return false; + } + + if ($userId === null) { + $userId = Helper::getUser($path); + } $util = new Util($view, $userId); if($util->isSystemWideMountPoint($path)) { @@ -402,7 +411,15 @@ class Keymanager { * @param string $userId owner of the file * @param string $filePath path to the file, relative to the owners file dir */ - public static function delAllShareKeys(\OC_FilesystemView $view, $userId, $filePath) { + public static function delAllShareKeys($view, $userId, $filePath) { + + $filePath = ltrim($filePath, '/'); + + if ($filePath === '') { + \OCP\Util::writeLog('Encryption library', + 'Can\'t delete share-keys empty path given!', \OCP\Util::ERROR); + return false; + } $util = new util($view, $userId); @@ -413,17 +430,15 @@ class Keymanager { } - if ($view->is_dir($userId . '/files/' . $filePath)) { + if ($view->is_dir($baseDir . $filePath)) { $view->unlink($baseDir . $filePath); } else { - $localKeyPath = $view->getLocalFile($baseDir . $filePath); - $escapedPath = Helper::escapeGlobPattern($localKeyPath); - $matches = glob($escapedPath . '*.shareKey'); - foreach ($matches as $ma) { - $result = unlink($ma); - if (!$result) { - \OCP\Util::writeLog('Encryption library', - 'Keyfile or shareKey could not be deleted for file "' . $filePath . '"', \OCP\Util::ERROR); + $parentDir = dirname($baseDir . $filePath); + $filename = pathinfo($filePath, PATHINFO_BASENAME); + foreach($view->getDirectoryContent($parentDir) as $content) { + $path = $content['path']; + if (strpos($content['name'], $filename) === 0) { + $view->unlink('/' . $userId . '/' . $path); } } } From bef58f5361eb5480d4633d733b3c8d3f80e034c4 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Fri, 31 Jan 2014 20:39:52 +0100 Subject: [PATCH 147/181] don't expect OC_FilesystemView, this is depreciated --- apps/files_encryption/lib/util.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 8816d4d649..ae3e2a2e15 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -57,7 +57,7 @@ class Util { * @param $userId * @param bool $client */ - public function __construct(\OC_FilesystemView $view, $userId, $client = false) { + public function __construct($view, $userId, $client = false) { $this->view = $view; $this->client = $client; From 5844d682a74533be8577160860758709bef706ba Mon Sep 17 00:00:00 2001 From: Morris Jobke Date: Sat, 1 Feb 2014 15:02:36 +0100 Subject: [PATCH 148/181] Use === instead of ==, add missing whitespace and CSS class --- core/templates/installation.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/templates/installation.php b/core/templates/installation.php index 9356e62aa6..9670a5e9ee 100644 --- a/core/templates/installation.php +++ b/core/templates/installation.php @@ -87,8 +87,8 @@ t( 'Configure the database' )); ?>
    $label): ?> - -

    t( 'will be used' )); ?>.

    + +

    t( 'will be used' )); ?>.

    Date: Fri, 31 Jan 2014 23:37:21 +0100 Subject: [PATCH 149/181] added tests for the delete hooks if the trash bin is disabled --- apps/files_encryption/tests/hooks.php | 271 ++++++++++++++++++++++++++ apps/files_encryption/tests/proxy.php | 50 ----- apps/files_encryption/tests/share.php | 44 +++-- 3 files changed, 300 insertions(+), 65 deletions(-) create mode 100644 apps/files_encryption/tests/hooks.php diff --git a/apps/files_encryption/tests/hooks.php b/apps/files_encryption/tests/hooks.php new file mode 100644 index 0000000000..c26cba6406 --- /dev/null +++ b/apps/files_encryption/tests/hooks.php @@ -0,0 +1,271 @@ + + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this library. If not, see . + * + */ + +require_once __DIR__ . '/../../../lib/base.php'; +require_once __DIR__ . '/../lib/crypt.php'; +require_once __DIR__ . '/../lib/keymanager.php'; +require_once __DIR__ . '/../lib/stream.php'; +require_once __DIR__ . '/../lib/util.php'; +require_once __DIR__ . '/../appinfo/app.php'; +require_once __DIR__ . '/util.php'; + +use OCA\Encryption; + +/** + * Class Test_Encryption_Hooks + * @brief this class provide basic hook app tests + */ +class Test_Encryption_Hooks extends \PHPUnit_Framework_TestCase { + + const TEST_ENCRYPTION_HOOKS_USER1 = "test-proxy-user1"; + const TEST_ENCRYPTION_HOOKS_USER2 = "test-proxy-user2"; + + /** + * @var \OC_FilesystemView + */ + public $user1View; // view on /data/user1/files + public $user2View; // view on /data/user2/files + public $rootView; // view on /data/user + public $data; + public $filename; + + public static function setUpBeforeClass() { + // reset backend + \OC_User::clearBackends(); + \OC_User::useBackend('database'); + + \OC_Hook::clear('OC_Filesystem'); + \OC_Hook::clear('OC_User'); + + // clear share hooks + \OC_Hook::clear('OCP\\Share'); + \OC::registerShareHooks(); + \OCP\Util::connectHook('OC_Filesystem', 'setup', '\OC\Files\Storage\Shared', 'setup'); + + // Filesystem related hooks + \OCA\Encryption\Helper::registerFilesystemHooks(); + + // Sharing related hooks + \OCA\Encryption\Helper::registerShareHooks(); + + // clear and register proxies + \OC_FileProxy::clearProxies(); + \OC_FileProxy::register(new OCA\Encryption\Proxy()); + + // create test user + \Test_Encryption_Util::loginHelper(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1, true); + \Test_Encryption_Util::loginHelper(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2, true); + } + + function setUp() { + // set user id + \Test_Encryption_Util::loginHelper(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1); + \OC_User::setUserId(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1); + + // init filesystem view + $this->user1View = new \OC_FilesystemView('/'. \Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1 . '/files'); + $this->user2View = new \OC_FilesystemView('/'. \Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2 . '/files'); + $this->rootView = new \OC_FilesystemView('/'); + + // init short data + $this->data = 'hats'; + $this->filename = 'enc_hooks_tests-' . uniqid() . '.txt'; + + } + + public static function tearDownAfterClass() { + // cleanup test user + \OC_User::deleteUser(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1); + \OC_User::deleteUser(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2); + } + + function testDeleteHooks() { + + // remember files_trashbin state + $stateFilesTrashbin = OC_App::isEnabled('files_trashbin'); + + // we want to tests with app files_trashbin disabled + \OC_App::disable('files_trashbin'); + + // make sure that the trash bin is disabled + $this->assertFalse(\OC_APP::isEnabled('files_trashbin')); + + $this->user1View->file_put_contents($this->filename, $this->data); + + // check if all keys are generated + $this->assertTrue($this->rootView->file_exists( + self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/share-keys/' + . $this->filename . '.' . \Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1 . '.shareKey')); + $this->assertTrue($this->rootView->file_exists( + self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/keyfiles/' . $this->filename . '.key')); + + + \Test_Encryption_Util::logoutHelper(); + \Test_Encryption_Util::loginHelper(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2); + \OC_User::setUserId(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2); + + + $this->user2View->file_put_contents($this->filename, $this->data); + + // check if all keys are generated + $this->assertTrue($this->rootView->file_exists( + self::TEST_ENCRYPTION_HOOKS_USER2 . '/files_encryption/share-keys/' + . $this->filename . '.' . \Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2 . '.shareKey')); + $this->assertTrue($this->rootView->file_exists( + self::TEST_ENCRYPTION_HOOKS_USER2 . '/files_encryption/keyfiles/' . $this->filename . '.key')); + + + // create a dummy file that we can delete something outside of data/user/files + // in this case no share or file keys should be deleted + $this->rootView->file_put_contents(self::TEST_ENCRYPTION_HOOKS_USER2 . "/" . $this->filename, $this->data); + + // delete dummy file outside of data/user/files + $this->rootView->unlink(self::TEST_ENCRYPTION_HOOKS_USER2 . "/" . $this->filename); + + // all keys should still exist + $this->assertTrue($this->rootView->file_exists( + self::TEST_ENCRYPTION_HOOKS_USER2 . '/files_encryption/share-keys/' + . $this->filename . '.' . \Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2 . '.shareKey')); + $this->assertTrue($this->rootView->file_exists( + self::TEST_ENCRYPTION_HOOKS_USER2 . '/files_encryption/keyfiles/' . $this->filename . '.key')); + + + // delete the file in data/user/files + // now the correspondig share and file keys from user2 should be deleted + $this->user2View->unlink($this->filename); + + // check if keys from user2 are really deleted + $this->assertFalse($this->rootView->file_exists( + self::TEST_ENCRYPTION_HOOKS_USER2 . '/files_encryption/share-keys/' + . $this->filename . '.' . \Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2 . '.shareKey')); + $this->assertFalse($this->rootView->file_exists( + self::TEST_ENCRYPTION_HOOKS_USER2 . '/files_encryption/keyfiles/' . $this->filename . '.key')); + + // but user1 keys should still exist + $this->assertTrue($this->rootView->file_exists( + self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/share-keys/' + . $this->filename . '.' . \Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1 . '.shareKey')); + $this->assertTrue($this->rootView->file_exists( + self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/keyfiles/' . $this->filename . '.key')); + + if ($stateFilesTrashbin) { + OC_App::enable('files_trashbin'); + } + else { + OC_App::disable('files_trashbin'); + } + } + + function testDeleteHooksForSharedFiles() { + + \Test_Encryption_Util::logoutHelper(); + \Test_Encryption_Util::loginHelper(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1); + \OC_User::setUserId(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1); + + // remember files_trashbin state + $stateFilesTrashbin = OC_App::isEnabled('files_trashbin'); + + // we want to tests with app files_trashbin disabled + \OC_App::disable('files_trashbin'); + + // make sure that the trash bin is disabled + $this->assertFalse(\OC_APP::isEnabled('files_trashbin')); + + $this->user1View->file_put_contents($this->filename, $this->data); + + // check if all keys are generated + $this->assertTrue($this->rootView->file_exists( + self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/share-keys/' + . $this->filename . '.' . \Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1 . '.shareKey')); + $this->assertTrue($this->rootView->file_exists( + self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/keyfiles/' . $this->filename . '.key')); + + // get the file info from previous created file + $fileInfo = $this->user1View->getFileInfo($this->filename); + + // check if we have a valid file info + $this->assertTrue(is_array($fileInfo)); + + // share the file with user2 + \OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, self::TEST_ENCRYPTION_HOOKS_USER2, OCP\PERMISSION_ALL); + + // check if new share key exists + $this->assertTrue($this->rootView->file_exists( + self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/share-keys/' + . $this->filename . '.' . \Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2 . '.shareKey')); + + \Test_Encryption_Util::logoutHelper(); + \Test_Encryption_Util::loginHelper(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2); + \OC_User::setUserId(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2); + + // user2 has a local file with the same name + $this->user2View->file_put_contents($this->filename, $this->data); + + // check if all keys are generated + $this->assertTrue($this->rootView->file_exists( + self::TEST_ENCRYPTION_HOOKS_USER2 . '/files_encryption/share-keys/' + . $this->filename . '.' . \Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2 . '.shareKey')); + $this->assertTrue($this->rootView->file_exists( + self::TEST_ENCRYPTION_HOOKS_USER2 . '/files_encryption/keyfiles/' . $this->filename . '.key')); + + // delete the Shared file from user1 in data/user2/files/Shared + $this->user2View->unlink('/Shared/' . $this->filename); + + // now keys from user1s home should be gone + $this->assertFalse($this->rootView->file_exists( + self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/share-keys/' + . $this->filename . '.' . \Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1 . '.shareKey')); + $this->assertFalse($this->rootView->file_exists( + self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/share-keys/' + . $this->filename . '.' . \Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2 . '.shareKey')); + $this->assertFalse($this->rootView->file_exists( + self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/keyfiles/' . $this->filename . '.key')); + + // but user2 keys should still exist + $this->assertTrue($this->rootView->file_exists( + self::TEST_ENCRYPTION_HOOKS_USER2 . '/files_encryption/share-keys/' + . $this->filename . '.' . \Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2 . '.shareKey')); + $this->assertTrue($this->rootView->file_exists( + self::TEST_ENCRYPTION_HOOKS_USER2 . '/files_encryption/keyfiles/' . $this->filename . '.key')); + + // cleanup + + $this->user2View->unlink($this->filename); + + \Test_Encryption_Util::logoutHelper(); + \Test_Encryption_Util::loginHelper(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1); + \OC_User::setUserId(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1); + + // unshare the file + \OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, self::TEST_ENCRYPTION_HOOKS_USER2); + + $this->user1View->unlink($this->filename); + + if ($stateFilesTrashbin) { + OC_App::enable('files_trashbin'); + } + else { + OC_App::disable('files_trashbin'); + } + } + +} diff --git a/apps/files_encryption/tests/proxy.php b/apps/files_encryption/tests/proxy.php index c3006274d6..51cc0b795e 100644 --- a/apps/files_encryption/tests/proxy.php +++ b/apps/files_encryption/tests/proxy.php @@ -112,54 +112,4 @@ class Test_Encryption_Proxy extends \PHPUnit_Framework_TestCase { } - function testPreUnlinkWithoutTrash() { - - // remember files_trashbin state - $stateFilesTrashbin = OC_App::isEnabled('files_trashbin'); - - // we want to tests with app files_trashbin enabled - \OC_App::disable('files_trashbin'); - - $this->view->file_put_contents($this->filename, $this->data); - - // create a dummy file that we can delete something outside of data/user/files - $this->rootView->file_put_contents("dummy.txt", $this->data); - - // check if all keys are generated - $this->assertTrue($this->rootView->file_exists( - '/files_encryption/share-keys/' - . $this->filename . '.' . \Test_Encryption_Proxy::TEST_ENCRYPTION_PROXY_USER1 . '.shareKey')); - $this->assertTrue($this->rootView->file_exists( - '/files_encryption/keyfiles/' . $this->filename . '.key')); - - - // delete dummy file outside of data/user/files - $this->rootView->unlink("dummy.txt"); - - // all keys should still exist - $this->assertTrue($this->rootView->file_exists( - '/files_encryption/share-keys/' - . $this->filename . '.' . \Test_Encryption_Proxy::TEST_ENCRYPTION_PROXY_USER1 . '.shareKey')); - $this->assertTrue($this->rootView->file_exists( - '/files_encryption/keyfiles/' . $this->filename . '.key')); - - - // delete the file in data/user/files - $this->view->unlink($this->filename); - - // now also the keys should be gone - $this->assertFalse($this->rootView->file_exists( - '/files_encryption/share-keys/' - . $this->filename . '.' . \Test_Encryption_Proxy::TEST_ENCRYPTION_PROXY_USER1 . '.shareKey')); - $this->assertFalse($this->rootView->file_exists( - '/files_encryption/keyfiles/' . $this->filename . '.key')); - - if ($stateFilesTrashbin) { - OC_App::enable('files_trashbin'); - } - else { - OC_App::disable('files_trashbin'); - } - } - } diff --git a/apps/files_encryption/tests/share.php b/apps/files_encryption/tests/share.php index e55427620a..acf408a07f 100755 --- a/apps/files_encryption/tests/share.php +++ b/apps/files_encryption/tests/share.php @@ -194,8 +194,9 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase { . $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '.shareKey')); // cleanup - $this->view->unlink( - '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->filename); + $this->view->chroot('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/'); + $this->view->unlink($this->filename); + $this->view->chroot('/'); // check if share key not exists $this->assertFalse($this->view->file_exists( @@ -265,8 +266,9 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase { . $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '.shareKey')); // cleanup - $this->view->unlink( - '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->filename); + $this->view->chroot('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/'); + $this->view->unlink($this->filename); + $this->view->chroot('/'); // check if share key not exists $this->assertFalse($this->view->file_exists( @@ -352,7 +354,9 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase { . $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '.shareKey')); // cleanup - $this->view->unlink('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files' . $this->folder1); + $this->view->chroot('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files'); + $this->view->unlink($this->folder1); + $this->view->chroot('/'); // check if share key not exists $this->assertFalse($this->view->file_exists( @@ -482,9 +486,9 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase { . $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '.shareKey')); // cleanup - $this->view->unlink( - '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files' . $this->folder1 . $this->subfolder - . $this->subsubfolder . '/' . $this->filename); + $this->view->chroot('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files'); + $this->view->unlink($this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename); + $this->view->chroot('/'); // check if share key not exists $this->assertFalse($this->view->file_exists( @@ -559,7 +563,9 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase { . $this->filename . '.' . $publicShareKeyId . '.shareKey')); // cleanup - $this->view->unlink('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->filename); + $this->view->chroot('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/'); + $this->view->unlink($this->filename); + $this->view->chroot('/'); // check if share key not exists $this->assertFalse($this->view->file_exists( @@ -636,7 +642,9 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase { . $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER4 . '.shareKey')); // cleanup - $this->view->unlink('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->filename); + $this->view->chroot('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/'); + $this->view->unlink($this->filename); + $this->view->chroot('/'); // check if share key not exists $this->assertFalse($this->view->file_exists( @@ -731,8 +739,10 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase { . $this->filename . '.' . $recoveryKeyId . '.shareKey')); // cleanup - $this->view->unlink('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->filename); - $this->view->unlink('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->folder1); + $this->view->chroot('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/'); + $this->view->unlink($this->filename); + $this->view->unlink($this->folder1); + $this->view->chroot('/'); // check if share key for recovery not exists $this->assertFalse($this->view->file_exists( @@ -828,8 +838,10 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase { $this->assertEquals($this->dataShort, $retrievedCryptedFile2); // cleanup - $this->view->unlink('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files/' . $this->folder1); - $this->view->unlink('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files/' . $this->filename); + $this->view->chroot('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files/'); + $this->view->unlink($this->folder1); + $this->view->unlink($this->filename); + $this->view->chroot('/'); // check if share key for user and recovery exists $this->assertFalse($this->view->file_exists( @@ -930,7 +942,9 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase { . $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3 . '.shareKey')); // cleanup - $this->view->unlink('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->filename); + $this->view->chroot('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/'); + $this->view->unlink($this->filename); + $this->view->chroot('/'); } } From 44b637470c57f098d328bc6d298be9385d3f30c4 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Fri, 31 Jan 2014 12:28:21 +0100 Subject: [PATCH 150/181] remove passwords in URLs from all log messages --- lib/private/log/errorhandler.php | 15 ++++++++++++--- lib/private/log/owncloud.php | 1 - 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/lib/private/log/errorhandler.php b/lib/private/log/errorhandler.php index 69cb960de9..4460468336 100644 --- a/lib/private/log/errorhandler.php +++ b/lib/private/log/errorhandler.php @@ -14,6 +14,15 @@ class ErrorHandler { /** @var LoggerInterface */ private static $logger; + /** + * @brief remove password in URLs + * @param string $msg + * @return string + */ + private static function removePassword($msg) { + return preg_replace('/\/\/(.*):(.*)@/', '//xxx:xxx@', $msg); + } + public static function register() { $handler = new ErrorHandler(); @@ -32,14 +41,14 @@ class ErrorHandler { if($error && self::$logger) { //ob_end_clean(); $msg = $error['message'] . ' at ' . $error['file'] . '#' . $error['line']; - self::$logger->critical($msg, array('app' => 'PHP')); + self::$logger->critical(self::removePassword($msg), array('app' => 'PHP')); } } // Uncaught exception handler public static function onException($exception) { $msg = $exception->getMessage() . ' at ' . $exception->getFile() . '#' . $exception->getLine(); - self::$logger->critical($msg, array('app' => 'PHP')); + self::$logger->critical(self::removePassword($msg), array('app' => 'PHP')); } //Recoverable errors handler @@ -48,7 +57,7 @@ class ErrorHandler { return; } $msg = $message . ' at ' . $file . '#' . $line; - self::$logger->warning($msg, array('app' => 'PHP')); + self::$logger->warning(self::removePassword($msg), array('app' => 'PHP')); } } diff --git a/lib/private/log/owncloud.php b/lib/private/log/owncloud.php index 4c86d0e45e..3590bbd436 100644 --- a/lib/private/log/owncloud.php +++ b/lib/private/log/owncloud.php @@ -69,7 +69,6 @@ class OC_Log_Owncloud { } $time = new DateTime(null, $timezone); // remove username/passswords from URLs before writing the to the log file - $message = preg_replace('/\/\/(.*):(.*)@/', '//xxx:xxx@', $message); $entry=array('app'=>$app, 'message'=>$message, 'level'=>$level, 'time'=> $time->format($format)); $entry = json_encode($entry); $handle = @fopen(self::$logFile, 'a'); From cf5277b558e1838a1b8126621cb8cd5a0ca60cb4 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Fri, 31 Jan 2014 13:27:51 +0100 Subject: [PATCH 151/181] also load error handler if debugging is enabled --- lib/base.php | 3 ++- lib/private/log/errorhandler.php | 18 +++++++++++++++--- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/lib/base.php b/lib/base.php index af78b4e4eb..b54b297355 100644 --- a/lib/base.php +++ b/lib/base.php @@ -504,11 +504,12 @@ class OC { if (!defined('PHPUNIT_RUN')) { if (defined('DEBUG') and DEBUG) { + OC\Log\ErrorHandler::register(true); set_exception_handler(array('OC_Template', 'printExceptionErrorPage')); } else { OC\Log\ErrorHandler::register(); - OC\Log\ErrorHandler::setLogger(OC_Log::$object); } + OC\Log\ErrorHandler::setLogger(OC_Log::$object); } // register the stream wrappers diff --git a/lib/private/log/errorhandler.php b/lib/private/log/errorhandler.php index 4460468336..f6c96ef821 100644 --- a/lib/private/log/errorhandler.php +++ b/lib/private/log/errorhandler.php @@ -23,10 +23,14 @@ class ErrorHandler { return preg_replace('/\/\/(.*):(.*)@/', '//xxx:xxx@', $msg); } - public static function register() { + public static function register($debug=false) { $handler = new ErrorHandler(); - set_error_handler(array($handler, 'onError')); + if ($debug) { + set_error_handler(array($handler, 'onAll'), E_ALL); + } else { + set_error_handler(array($handler, 'onError')); + } register_shutdown_function(array($handler, 'onShutdown')); set_exception_handler(array($handler, 'onException')); } @@ -57,7 +61,15 @@ class ErrorHandler { return; } $msg = $message . ' at ' . $file . '#' . $line; - self::$logger->warning(self::removePassword($msg), array('app' => 'PHP')); + self::$logger->error(self::removePassword($msg), array('app' => 'PHP')); } + + //Recoverable handler which catch all errors, warnings and notices + public static function onAll($number, $message, $file, $line) { + $msg = $message . ' at ' . $file . '#' . $line; + self::$logger->debug(self::removePassword($msg), array('app' => 'PHP')); + + } + } From 97921d0c25469bd905906406c70a96eeb7fd1664 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Mon, 3 Feb 2014 13:39:05 +0100 Subject: [PATCH 152/181] add function to extract filename from sharekey name + tests --- apps/files_encryption/lib/keymanager.php | 18 +++++++++++++++++- apps/files_encryption/tests/keymanager.php | 20 ++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/apps/files_encryption/lib/keymanager.php b/apps/files_encryption/lib/keymanager.php index 17b8180bfd..7abc565f60 100755 --- a/apps/files_encryption/lib/keymanager.php +++ b/apps/files_encryption/lib/keymanager.php @@ -437,7 +437,7 @@ class Keymanager { $filename = pathinfo($filePath, PATHINFO_BASENAME); foreach($view->getDirectoryContent($parentDir) as $content) { $path = $content['path']; - if (strpos($content['name'], $filename) === 0) { + if (self::getFilenameFromShareKey($content['name']) === $filename) { $view->unlink('/' . $userId . '/' . $path); } } @@ -538,4 +538,20 @@ class Keymanager { return $targetPath; } + + /** + * @brief extract filename from share key name + * @param string $shareKey (filename.userid.sharekey) + * @return mixed filename or false + */ + protected static function getFilenameFromShareKey($shareKey) { + $parts = explode('.', $shareKey); + + $filename = false; + if(count($parts) > 2) { + $filename = implode('.', array_slice($parts, 0, count($parts)-2)); + } + + return $filename; + } } diff --git a/apps/files_encryption/tests/keymanager.php b/apps/files_encryption/tests/keymanager.php index 58a57ee5af..6f32c50743 100644 --- a/apps/files_encryption/tests/keymanager.php +++ b/apps/files_encryption/tests/keymanager.php @@ -136,6 +136,17 @@ class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase { $this->assertArrayHasKey('key', $sslInfo); } + /** + * @small + */ + function testGetFilenameFromShareKey() { + $this->assertEquals("file", + \TestProtectedKeymanagerMethods::testGetFilenameFromShareKey("file.user.shareKey")); + $this->assertEquals("file.name.with.dots", + \TestProtectedKeymanagerMethods::testGetFilenameFromShareKey("file.name.with.dots.user.shareKey")); + $this->assertFalse(\TestProtectedKeymanagerMethods::testGetFilenameFromShareKey("file.txt")); + } + /** * @medium */ @@ -234,3 +245,12 @@ class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase { \OC_FileProxy::$enabled = $proxyStatus; } } + +/** + * dummy class to access protected methods of \OCA\Encryption\Keymanager for testing + */ +class TestProtectedKeymanagerMethods extends \OCA\Encryption\Keymanager { + public static function testGetFilenameFromShareKey($sharekey) { + return self::getFilenameFromShareKey($sharekey); + } +} \ No newline at end of file From 6d7d3c16d04596b0cd32ebc1aaddaaaf7c5fe481 Mon Sep 17 00:00:00 2001 From: Jan-Christoph Borchardt Date: Mon, 3 Feb 2014 17:23:30 +0100 Subject: [PATCH 153/181] ellipsize long modified dates to make room for showing delete button, fix #7040 --- apps/files/css/files.css | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/apps/files/css/files.css b/apps/files/css/files.css index 1d254ad04e..8c7938c79b 100644 --- a/apps/files/css/files.css +++ b/apps/files/css/files.css @@ -119,7 +119,9 @@ table th#headerDate, table td.date { -moz-box-sizing: border-box; box-sizing: border-box; position: relative; + /* this can not be just width, both need to be set … table styling */ min-width: 176px; + max-width: 176px; } /* Multiselect bar */ @@ -174,6 +176,14 @@ table td.filename .nametext, .uploadtext, .modified { float:left; padding:14px 0 } .modified { position: relative; + overflow: hidden; + text-overflow: ellipsis; + width: 90%; +} +/* ellipsize long modified dates to make room for showing delete button */ +#fileList tr:hover .modified, +#fileList tr:focus .modified { + width: 75%; } /* TODO fix usability bug (accidental file/folder selection) */ From b56dbbe0e5b593f53b686d5cada5a36ef2d4f39f Mon Sep 17 00:00:00 2001 From: Jan-Christoph Borchardt Date: Mon, 3 Feb 2014 17:26:49 +0100 Subject: [PATCH 154/181] fix misalignment of modified dates, shift to right --- apps/files/css/files.css | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/files/css/files.css b/apps/files/css/files.css index 8c7938c79b..5526abaf6e 100644 --- a/apps/files/css/files.css +++ b/apps/files/css/files.css @@ -176,6 +176,7 @@ table td.filename .nametext, .uploadtext, .modified { float:left; padding:14px 0 } .modified { position: relative; + padding-left: 8px; overflow: hidden; text-overflow: ellipsis; width: 90%; From cfcd71f3e4e8417541629de9c99e306dfd571d57 Mon Sep 17 00:00:00 2001 From: Jan-Christoph Borchardt Date: Mon, 3 Feb 2014 18:47:25 +0100 Subject: [PATCH 155/181] better picture icon, fix https://github.com/owncloud/apps/issues/1401 --- core/img/places/picture.png | Bin 242 -> 434 bytes core/img/places/picture.svg | 5 +---- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/core/img/places/picture.png b/core/img/places/picture.png index 7b3af8c7f841c99e326bedcd9cf7764906a91c6e..2b96ea518ce876eaefd2e90b7594b0b5bd3844ca 100644 GIT binary patch delta 363 zcmV-x0hIpo0kQ*-7#Ro#0001UdV2H#000DYLP=Bz2nYy#2xN$nFg$+&FG)l}R9J=W zm!WO~K@>&rLLtGRQB6g^0)=jZAwgBmhcqD-{eX&E3<)2Az}Jx#7ly;U;zqYBx?GIg{{T)niwn z+6EeujHJ}k*jTw>7utWK;XjO%b0~KN^9-aJ2GX((RC)&93dW9urv(k$^VHJV*r8>A z1V$kurd7IgQ5Q~U|*lHMhCvmPEZghNRyNrOFkPkG{!yfcu;Ch+RKHwW%B za=XA94?+#x0*joret>77WpmrWr%yc8zyt8LZ$aP#=mV1ixrIjz)PWaZQ)IzVxaR>E z9Z6G3y@25ig6}KnNm`y#T$0=hoc(-QiOpynQGc9py&GP-fnU+avmX`&)Gz=5002ov JPDHLkV1hZ8oHGCb delta 170 zcmdnQ{E2abgaivS0|P^2NcwRg#a!&<8N$KAar>eFgNcSV^$cP+Dz - - - - + From 36838b2837168b69aba82f88f110c174db25e6d7 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Tue, 4 Feb 2014 11:11:24 +0100 Subject: [PATCH 156/181] add test for password remove method --- lib/private/log/errorhandler.php | 2 +- tests/lib/errorHandler.php | 62 ++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 tests/lib/errorHandler.php diff --git a/lib/private/log/errorhandler.php b/lib/private/log/errorhandler.php index f6c96ef821..1dde6b507f 100644 --- a/lib/private/log/errorhandler.php +++ b/lib/private/log/errorhandler.php @@ -19,7 +19,7 @@ class ErrorHandler { * @param string $msg * @return string */ - private static function removePassword($msg) { + protected static function removePassword($msg) { return preg_replace('/\/\/(.*):(.*)@/', '//xxx:xxx@', $msg); } diff --git a/tests/lib/errorHandler.php b/tests/lib/errorHandler.php new file mode 100644 index 0000000000..68b87deccb --- /dev/null +++ b/tests/lib/errorHandler.php @@ -0,0 +1,62 @@ + + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this library. If not, see . + * + */ + +class Test_ErrorHandler extends \PHPUnit_Framework_TestCase { + + /** + * @brief provide username, password combinations for testRemovePassword + * @return array + */ + function passwordProvider() { + return array( + array('user', 'password'), + array('user@owncloud.org', 'password'), + array('user', 'pass@word'), + array('us:er', 'password'), + array('user', 'pass:word'), + ); + + } + + /** + * @dataProvider passwordProvider + * @param string $username + * @param string $password + */ + function testRemovePassword($username, $password) { + $url = 'http://'.$username.':'.$password.'@owncloud.org'; + $expectedResult = 'http://xxx:xxx@owncloud.org'; + $result = TestableErrorHandler::testRemovePassword($url); + + $this->assertEquals($expectedResult, $result); + } + +} + +/** + * @brief dummy class to access protected methods of \OC\Log\ErrorHandler + */ +class TestableErrorHandler extends \OC\Log\ErrorHandler { + public static function testRemovePassword($msg) { + return self::removePassword($msg); + } +} From d55ef442cd861d04b9ccfd4493aedf0c9a4164ff Mon Sep 17 00:00:00 2001 From: Georg Ehrke Date: Tue, 4 Feb 2014 12:59:14 +0100 Subject: [PATCH 157/181] properly check if pdf and svg modules are installed --- lib/private/preview/office.php | 2 +- lib/private/preview/pdf.php | 2 +- lib/private/preview/svg.php | 2 +- lib/private/preview/unknown.php | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/private/preview/office.php b/lib/private/preview/office.php index 7a4826c76e..884b6e7dc9 100644 --- a/lib/private/preview/office.php +++ b/lib/private/preview/office.php @@ -6,7 +6,7 @@ * See the COPYING-README file. */ //both, libreoffice backend and php fallback, need imagick -if (extension_loaded('imagick')) { +if (extension_loaded('imagick') && count(\Imagick::queryFormats("PDF")) === 1) { $isShellExecEnabled = \OC_Helper::is_function_enabled('shell_exec'); // LibreOffice preview is currently not supported on Windows diff --git a/lib/private/preview/pdf.php b/lib/private/preview/pdf.php index cc974b6881..572b8788ac 100644 --- a/lib/private/preview/pdf.php +++ b/lib/private/preview/pdf.php @@ -7,7 +7,7 @@ */ namespace OC\Preview; -if (extension_loaded('imagick')) { +if (extension_loaded('imagick') && count(\Imagick::queryFormats("PDF")) === 1) { class PDF extends Provider { diff --git a/lib/private/preview/svg.php b/lib/private/preview/svg.php index b49e51720f..07a37e8f8c 100644 --- a/lib/private/preview/svg.php +++ b/lib/private/preview/svg.php @@ -7,7 +7,7 @@ */ namespace OC\Preview; -if (extension_loaded('imagick')) { +if (extension_loaded('imagick') && count(\Imagick::queryFormats("SVG")) === 1) { class SVG extends Provider { diff --git a/lib/private/preview/unknown.php b/lib/private/preview/unknown.php index 4747f9e25e..8145c82614 100644 --- a/lib/private/preview/unknown.php +++ b/lib/private/preview/unknown.php @@ -22,7 +22,7 @@ class Unknown extends Provider { $svgPath = substr_replace($path, 'svg', -3); - if (extension_loaded('imagick') && file_exists($svgPath)) { + if (extension_loaded('imagick') && file_exists($svgPath) && count(\Imagick::queryFormats("SVG")) === 1) { // http://www.php.net/manual/de/imagick.setresolution.php#85284 $svg = new \Imagick(); From 912da8d27756d9f0d55821338f6d8698af2dbd27 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Tue, 4 Feb 2014 13:56:10 +0100 Subject: [PATCH 158/181] Added session_keepalive setting When session_keepalive is true (default) the heartbeat will be send as often as the half of the session timeout value. --- config/config.sample.php | 7 ++++++ core/js/config.php | 6 +++++ core/js/js.js | 53 ++++++++++++++++++++++++++++------------ 3 files changed, 51 insertions(+), 15 deletions(-) diff --git a/config/config.sample.php b/config/config.sample.php index 01abc58368..ef5fb7ea5a 100755 --- a/config/config.sample.php +++ b/config/config.sample.php @@ -184,6 +184,13 @@ $CONFIG = array( /* Life time of a session after inactivity */ "session_lifetime" => 60 * 60 * 24, +/* + * Enable/disable session keep alive when a user is logged in in the Web UI. + * This is achieved by sending a "heartbeat" to the server to prevent + * the session timing out. + */ +"session_keepalive" => true, + /* Custom CSP policy, changing this will overwrite the standard policy */ "custom_csp_policy" => "default-src 'self'; script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; frame-src *; img-src *; font-src 'self' data:; media-src *", diff --git a/core/js/config.php b/core/js/config.php index dd46f7889d..517ea1615a 100644 --- a/core/js/config.php +++ b/core/js/config.php @@ -55,6 +55,12 @@ $array = array( ) ), "firstDay" => json_encode($l->l('firstday', 'firstday')) , + "oc_config" => json_encode( + array( + 'session_lifetime' => \OCP\Config::getSystemValue('session_lifetime', 60 * 60 * 24), + 'session_keepalive' => \OCP\Config::getSystemValue('session_keepalive', true) + ) + ) ); // Echo it diff --git a/core/js/js.js b/core/js/js.js index 1c7d89ea05..cd9b8bd301 100644 --- a/core/js/js.js +++ b/core/js/js.js @@ -11,6 +11,8 @@ var oc_webroot; var oc_current_user = document.getElementsByTagName('head')[0].getAttribute('data-user'); var oc_requesttoken = document.getElementsByTagName('head')[0].getAttribute('data-requesttoken'); +window.oc_config = window.oc_config || {}; + if (typeof oc_webroot === "undefined") { oc_webroot = location.pathname; var pos = oc_webroot.indexOf('/index.php/'); @@ -742,8 +744,39 @@ function fillWindow(selector) { console.warn("This function is deprecated! Use CSS instead"); } -$(document).ready(function(){ - sessionHeartBeat(); +/** + * Initializes core + */ +function initCore() { + + /** + * Calls the server periodically to ensure that session doesnt + * time out + */ + function initSessionHeartBeat(){ + // interval in seconds + var interval = 900; + if (oc_config.session_lifetime) { + interval = Math.floor(oc_config.session_lifetime / 2); + } + // minimum one minute + if (interval < 60) { + interval = 60; + } + OC.Router.registerLoadedCallback(function(){ + var url = OC.Router.generate('heartbeat'); + setInterval(function(){ + $.post(url); + }, interval * 1000); + }); + } + + // session heartbeat (defalts to enabled) + if (typeof(oc_config.session_keepalive) === 'undefined' || + !!oc_config.session_keepalive) { + + initSessionHeartBeat(); + } if(!SVGSupport()){ //replace all svg images with png images for browser that dont support svg replaceSVG(); @@ -856,7 +889,9 @@ $(document).ready(function(){ $('input[type=text]').focus(function(){ this.select(); }); -}); +} + +$(document).ready(initCore); /** * Filter Jquery selector by attribute value @@ -986,15 +1021,3 @@ jQuery.fn.exists = function(){ return this.length > 0; }; -/** - * Calls the server periodically every 15 mins to ensure that session doesnt - * time out - */ -function sessionHeartBeat(){ - OC.Router.registerLoadedCallback(function(){ - var url = OC.Router.generate('heartbeat'); - setInterval(function(){ - $.post(url); - }, 900000); - }); -} From e75f7e58e9778bbe5bed6ba387c781c2ece94bbf Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Tue, 4 Feb 2014 13:56:41 +0100 Subject: [PATCH 159/181] Added unit tests for session_keepalive / heartbeat --- core/js/tests/specHelper.js | 18 +++++++- core/js/tests/specs/coreSpec.js | 74 +++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 1 deletion(-) diff --git a/core/js/tests/specHelper.js b/core/js/tests/specHelper.js index 4a30878df5..1848d08354 100644 --- a/core/js/tests/specHelper.js +++ b/core/js/tests/specHelper.js @@ -19,6 +19,8 @@ * */ +/* global OC */ + /** * Simulate the variables that are normally set by PHP code */ @@ -57,10 +59,15 @@ window.oc_webroot = location.href + '/'; window.oc_appswebroots = { "files": window.oc_webroot + '/apps/files/' }; +window.oc_config = { + session_lifetime: 600 * 1000, + session_keepalive: false +}; // global setup for all tests (function setupTests() { - var fakeServer = null; + var fakeServer = null, + routesRequestStub; beforeEach(function() { // enforce fake XHR, tests should not depend on the server and @@ -78,9 +85,18 @@ window.oc_appswebroots = { // make it globally available, so that other tests can define // custom responses window.fakeServer = fakeServer; + + OC.Router.routes = []; + OC.Router.routes_request = { + state: sinon.stub().returns('resolved'), + done: sinon.stub() + }; }); afterEach(function() { + OC.Router.routes_request.state.reset(); + OC.Router.routes_request.done.reset(); + // uncomment this to log requests // console.log(window.fakeServer.requests); fakeServer.restore(); diff --git a/core/js/tests/specs/coreSpec.js b/core/js/tests/specs/coreSpec.js index 28c20a0642..18652d4177 100644 --- a/core/js/tests/specs/coreSpec.js +++ b/core/js/tests/specs/coreSpec.js @@ -104,4 +104,78 @@ describe('Core base tests', function() { })).toEqual('number=123'); }); }); + describe('Session heartbeat', function() { + var clock, + oldConfig, + loadedStub, + routeStub, + counter; + + beforeEach(function() { + clock = sinon.useFakeTimers(); + oldConfig = window.oc_config; + loadedStub = sinon.stub(OC.Router, 'registerLoadedCallback'); + routeStub = sinon.stub(OC.Router, 'generate').returns('/heartbeat'); + counter = 0; + + fakeServer.autoRespond = true; + fakeServer.autoRespondAfter = 0; + fakeServer.respondWith(/\/heartbeat/, function(xhr) { + counter++; + xhr.respond(200, {'Content-Type': 'application/json'}, '{}'); + }); + }); + afterEach(function() { + clock.restore(); + window.oc_config = oldConfig; + loadedStub.restore(); + routeStub.restore(); + }); + it('sends heartbeat half the session lifetime when heartbeat enabled', function() { + window.oc_config = { + session_keepalive: true, + session_lifetime: 300 + }; + window.initCore(); + expect(loadedStub.calledOnce).toEqual(true); + loadedStub.yield(); + expect(routeStub.calledWith('heartbeat')).toEqual(true); + + expect(counter).toEqual(0); + + // less than half, still nothing + clock.tick(100 * 1000); + expect(counter).toEqual(0); + + // reach past half (160), one call + clock.tick(55 * 1000); + expect(counter).toEqual(1); + + // almost there to the next, still one + clock.tick(140 * 1000); + expect(counter).toEqual(1); + + // past it, second call + clock.tick(20 * 1000); + expect(counter).toEqual(2); + }); + it('does no send heartbeat when heartbeat disabled', function() { + window.oc_config = { + session_keepalive: false, + session_lifetime: 300 + }; + window.initCore(); + expect(loadedStub.notCalled).toEqual(true); + expect(routeStub.notCalled).toEqual(true); + + expect(counter).toEqual(0); + + clock.tick(1000000); + + // still nothing + expect(counter).toEqual(0); + }); + + }); }); + From 11f46e121caa30f46250a1980e315520d68eb593 Mon Sep 17 00:00:00 2001 From: Jens-Christian Fischer Date: Tue, 4 Feb 2014 17:03:52 +0100 Subject: [PATCH 160/181] close statement in MimeType detection is executed [#7069] close statement was never executed due to it being after a return statement. --- lib/private/files/type/detection.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/private/files/type/detection.php b/lib/private/files/type/detection.php index d7cc9ebbf4..11e439032c 100644 --- a/lib/private/files/type/detection.php +++ b/lib/private/files/type/detection.php @@ -72,11 +72,12 @@ class Detection { and function_exists('finfo_file') and $finfo = finfo_open(FILEINFO_MIME) ) { $info = @strtolower(finfo_file($finfo, $path)); + finfo_close($finfo); if ($info) { $mimeType = substr($info, 0, strpos($info, ';')); return empty($mimeType) ? 'application/octet-stream' : $mimeType; } - finfo_close($finfo); + } $isWrapped = (strpos($path, '://') !== false) and (substr($path, 0, 7) === 'file://'); if (!$isWrapped and $mimeType === 'application/octet-stream' && function_exists("mime_content_type")) { From fe2a63ffd425b354ee1cf6c2faaca19ca71717bb Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Tue, 4 Feb 2014 11:14:00 +0100 Subject: [PATCH 161/181] Scroll to the top after switching dir Fixes #7061 --- apps/files/js/filelist.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js index 23b31e7246..027a7bb947 100644 --- a/apps/files/js/filelist.js +++ b/apps/files/js/filelist.js @@ -28,7 +28,8 @@ var FileList={ } FileList.updateFileSummary(); procesSelection(); - + + $(window).scrollTop(0); $fileList.trigger(jQuery.Event("updated")); }, createRow:function(type, name, iconurl, linktarget, size, lastModified, permissions) { @@ -394,7 +395,7 @@ var FileList={ } return true; }; - + form.submit(function(event) { event.stopPropagation(); event.preventDefault(); @@ -468,7 +469,7 @@ var FileList={ var basename = newname; if (newname.indexOf('.') > 0 && tr.data('type') !== 'dir') { basename = newname.substr(0, newname.lastIndexOf('.')); - } + } td.find('a.name span.nametext').text(basename); if (newname.indexOf('.') > 0 && tr.data('type') !== 'dir') { if ( ! td.find('a.name span.extension').exists() ) { @@ -834,7 +835,7 @@ $(document).ready(function() { {name: 'requesttoken', value: oc_requesttoken} ]; }; - } + } }); file_upload_start.on('fileuploadadd', function(e, data) { @@ -873,7 +874,7 @@ $(document).ready(function() { */ file_upload_start.on('fileuploaddone', function(e, data) { OC.Upload.log('filelist handle fileuploaddone', e, data); - + var response; if (typeof data.result === 'string') { response = data.result; From 45ab9810c597939074f750f985decc6d56a38c97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Tue, 4 Feb 2014 20:58:06 +0100 Subject: [PATCH 162/181] fixing typos --- core/js/js.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/js/js.js b/core/js/js.js index cd9b8bd301..cb177712a3 100644 --- a/core/js/js.js +++ b/core/js/js.js @@ -750,7 +750,7 @@ function fillWindow(selector) { function initCore() { /** - * Calls the server periodically to ensure that session doesnt + * Calls the server periodically to ensure that session doesn't * time out */ function initSessionHeartBeat(){ @@ -771,7 +771,7 @@ function initCore() { }); } - // session heartbeat (defalts to enabled) + // session heartbeat (defaults to enabled) if (typeof(oc_config.session_keepalive) === 'undefined' || !!oc_config.session_keepalive) { From fa5ddc3e18a7bddc5510318b34062b31831403a5 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Wed, 5 Feb 2014 12:00:08 +0100 Subject: [PATCH 163/181] Fixed searchByMime in shared cache - searchByMime now correctly returns files recursively search through all the dirs - added unit test for searchByMime --- apps/files_sharing/lib/cache.php | 37 ++++++-- apps/files_sharing/tests/cache.php | 134 +++++++++++++++++++++++++++++ 2 files changed, 163 insertions(+), 8 deletions(-) create mode 100644 apps/files_sharing/tests/cache.php diff --git a/apps/files_sharing/lib/cache.php b/apps/files_sharing/lib/cache.php index 425d51113b..86e324409f 100644 --- a/apps/files_sharing/lib/cache.php +++ b/apps/files_sharing/lib/cache.php @@ -259,17 +259,38 @@ class Shared_Cache extends Cache { * @return array */ public function searchByMime($mimetype) { - - if (strpos($mimetype, '/')) { - $where = '`mimetype` = ? AND '; - } else { - $where = '`mimepart` = ? AND '; + $mimepart = null; + if (strpos($mimetype, '/') === false) { + $mimepart = $mimetype; + $mimetype = null; } - $value = $this->getMimetypeId($mimetype); - - return $this->searchWithWhere($where, $value); + // note: searchWithWhere is currently broken as it doesn't + // recurse into subdirs nor returns the correct + // file paths, so using getFolderContents() for now + $result = array(); + $exploreDirs = array(''); + while (count($exploreDirs) > 0) { + $dir = array_pop($exploreDirs); + $files = $this->getFolderContents($dir); + // no results? + if (!$files) { + continue; + } + foreach ($files as $file) { + if ($file['mimetype'] === 'httpd/unix-directory') { + $exploreDirs[] = ltrim($dir . '/' . $file['name'], '/'); + } + else if (($mimepart && $file['mimepart'] === $mimepart) || ($mimetype && $file['mimetype'] === $mimetype)) { + // usersPath not reliable + //$file['path'] = $file['usersPath']; + $file['path'] = ltrim($dir . '/' . $file['name'], '/'); + $result[] = $file; + } + } + } + return $result; } /** diff --git a/apps/files_sharing/tests/cache.php b/apps/files_sharing/tests/cache.php new file mode 100644 index 0000000000..56a51c83f6 --- /dev/null +++ b/apps/files_sharing/tests/cache.php @@ -0,0 +1,134 @@ + + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this library. If not, see . + * + */ +require_once __DIR__ . '/base.php'; + +class Test_Files_Sharing_Cache extends Test_Files_Sharing_Base { + + function setUp() { + parent::setUp(); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER1); + + // prepare user1's dir structure + $textData = "dummy file data\n"; + $this->view->mkdir('container'); + $this->view->mkdir('container/shareddir'); + $this->view->mkdir('container/shareddir/subdir'); + $this->view->mkdir('container/shareddir/emptydir'); + + $textData = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; + $this->view->file_put_contents('container/not shared.txt', $textData); + $this->view->file_put_contents('container/shared single file.txt', $textData); + $this->view->file_put_contents('container/shareddir/bar.txt', $textData); + $this->view->file_put_contents('container/shareddir/subdir/another.txt', $textData); + $this->view->file_put_contents('container/shareddir/subdir/another too.txt', $textData); + $this->view->file_put_contents('container/shareddir/subdir/not a text file.xml', ''); + + list($this->ownerStorage, $internalPath) = $this->view->resolvePath(''); + $this->ownerCache = $this->ownerStorage->getCache(); + $this->ownerStorage->getScanner()->scan(''); + + // share "shareddir" with user2 + $fileinfo = $this->view->getFileInfo('container/shareddir'); + \OCP\Share::shareItem('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER, + self::TEST_FILES_SHARING_API_USER2, 31); + + $fileinfo = $this->view->getFileInfo('container/shared single file.txt'); + \OCP\Share::shareItem('file', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER, + self::TEST_FILES_SHARING_API_USER2, 31); + + // login as user2 + self::loginHelper(self::TEST_FILES_SHARING_API_USER2); + + // retrieve the shared storage + $secondView = new \OC\Files\View('/' . self::TEST_FILES_SHARING_API_USER2); + list($this->sharedStorage, $internalPath) = $secondView->resolvePath('files/Shared/shareddir'); + $this->sharedCache = $this->sharedStorage->getCache(); + } + + function tearDown() { + $this->sharedCache->clear(); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER1); + + $fileinfo = $this->view->getFileInfo('container/shareddir'); + \OCP\Share::unshare('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER, + self::TEST_FILES_SHARING_API_USER2); + + $fileinfo = $this->view->getFileInfo('container/shared single file.txt'); + \OCP\Share::unshare('file', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER, + self::TEST_FILES_SHARING_API_USER2); + + $this->view->deleteAll('container'); + + $this->ownerCache->clear(); + + parent::tearDown(); + } + + /** + * Test searching by mime type + */ + function testSearchByMime() { + $results = $this->sharedStorage->getCache()->searchByMime('text'); + $check = array( + array( + 'name' => 'shared single file.txt', + 'path' => 'shared single file.txt' + ), + array( + 'name' => 'bar.txt', + 'path' => 'shareddir/bar.txt' + ), + array( + 'name' => 'another too.txt', + 'path' => 'shareddir/subdir/another too.txt' + ), + array( + 'name' => 'another.txt', + 'path' => 'shareddir/subdir/another.txt' + ), + ); + $this->verifyFiles($check, $results); + + $results2 = $this->sharedStorage->getCache()->searchByMime('text/plain'); + + $this->verifyFiles($check, $results); + } + + /** + * Checks that all provided attributes exist in the files list, + * only the values provided in $examples will be used to check against + * the file list. The files order also needs to be the same. + * + * @param array $examples array of example files + * @param array $files array of files + */ + private function verifyFiles($examples, $files) { + $this->assertEquals(count($examples), count($files)); + foreach ($files as $i => $file) { + foreach ($examples[$i] as $key => $value) { + $this->assertEquals($value, $file[$key]); + } + } + } +} From 20935f4e2496b23c07d76d5ce2daf85bb60f0cce Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Wed, 5 Feb 2014 15:34:08 +0100 Subject: [PATCH 164/181] Catch setup errors during autotest --- autotest.sh | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/autotest.sh b/autotest.sh index 94fc692a94..b88e9cf68b 100755 --- a/autotest.sh +++ b/autotest.sh @@ -185,19 +185,23 @@ EOF cp $BASEDIR/tests/autoconfig-$1.php $BASEDIR/config/autoconfig.php # trigger installation - php -f index.php + echo "INDEX" + php -f index.php | grep -i -C9999 error && echo "Error during setup" && exit 101 + echo "END INDEX" #test execution echo "Testing with $1 ..." cd tests rm -rf coverage-html-$1 mkdir coverage-html-$1 - php -f enable_all.php + php -f enable_all.php | grep -i -C9999 error && echo "Error during setup" && exit 101 if [ -z "$NOCOVERAGE" ]; then $PHPUNIT --configuration phpunit-autotest.xml --log-junit autotest-results-$1.xml --coverage-clover autotest-clover-$1.xml --coverage-html coverage-html-$1 $2 $3 + RESULT=$? else echo "No coverage" $PHPUNIT --configuration phpunit-autotest.xml --log-junit autotest-results-$1.xml $2 $3 + RESULT=$? fi } From e2625ae7aafc52f4b2869f2296d2de74a9b2c3a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Wed, 5 Feb 2014 18:23:40 +0100 Subject: [PATCH 165/181] fixing autoconfig handling --- core/setup/controller.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/core/setup/controller.php b/core/setup/controller.php index c628bda609..58ed4d28dc 100644 --- a/core/setup/controller.php +++ b/core/setup/controller.php @@ -56,17 +56,18 @@ class Controller { } public function loadAutoConfig($post) { - $dbIsSet = isset($post['dbtype']); - $directoryIsSet = isset($post['directory']); - $adminAccountIsSet = isset($post['adminlogin']); - $autosetup_file = \OC::$SERVERROOT.'/config/autoconfig.php'; if( file_exists( $autosetup_file )) { \OC_Log::write('core', 'Autoconfig file found, setting up owncloud...', \OC_Log::INFO); + $AUTOCONFIG = array(); include $autosetup_file; $post = array_merge ($post, $AUTOCONFIG); } + $dbIsSet = isset($post['dbtype']); + $directoryIsSet = isset($post['directory']); + $adminAccountIsSet = isset($post['adminlogin']); + if ($dbIsSet AND $directoryIsSet AND $adminAccountIsSet) { $post['install'] = 'true'; if( file_exists( $autosetup_file )) { From 8c56e21ced30f5e354b3a62c040a790a41548382 Mon Sep 17 00:00:00 2001 From: Pellaeon Lin Date: Thu, 6 Feb 2014 12:06:16 +0800 Subject: [PATCH 166/181] Move template variable assignment to correct place --- apps/files_sharing/public.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/files_sharing/public.php b/apps/files_sharing/public.php index b187da4132..fc716a514b 100644 --- a/apps/files_sharing/public.php +++ b/apps/files_sharing/public.php @@ -143,8 +143,6 @@ if (isset($path)) { OCP\Util::addScript('files', 'jquery.iframe-transport'); OCP\Util::addScript('files', 'jquery.fileupload'); $maxUploadFilesize=OCP\Util::maxUploadFilesize($path); - $freeSpace=OCP\Util::freeSpace($dir); - $uploadLimit=OCP\Util::uploadLimit(); $tmpl = new OCP\Template('files_sharing', 'public', 'base'); $tmpl->assign('uidOwner', $shareOwner); $tmpl->assign('displayName', \OCP\User::getDisplayName($shareOwner)); @@ -164,8 +162,6 @@ if (isset($path)) { } $tmpl->assign('uploadMaxFilesize', $maxUploadFilesize); $tmpl->assign('uploadMaxHumanFilesize', OCP\Util::humanFileSize($maxUploadFilesize)); - $tmpl->assign('freeSpace', $freeSpace); - $tmpl->assign('uploadLimit', $uploadLimit); // PHP upload limit $urlLinkIdentifiers= (isset($token)?'&t='.$token:'') .(isset($_GET['dir'])?'&dir='.$_GET['dir']:'') @@ -226,6 +222,9 @@ if (isset($path)) { $maxUploadFilesize=OCP\Util::maxUploadFilesize($path); $fileHeader = (!isset($files) or count($files) > 0); $emptyContent = ($allowPublicUploadEnabled and !$fileHeader); + + $freeSpace=OCP\Util::freeSpace($path); + $uploadLimit=OCP\Util::uploadLimit(); $folder = new OCP\Template('files', 'index', ''); $folder->assign('fileList', $list->fetchPage()); $folder->assign('breadcrumb', $breadcrumbNav->fetchPage()); @@ -238,6 +237,8 @@ if (isset($path)) { $folder->assign('files', $files); $folder->assign('uploadMaxFilesize', $maxUploadFilesize); $folder->assign('uploadMaxHumanFilesize', OCP\Util::humanFileSize($maxUploadFilesize)); + $folder->assign('freeSpace', $freeSpace); + $folder->assign('uploadLimit', $uploadLimit); // PHP upload limit $folder->assign('allowZipDownload', intval(OCP\Config::getSystemValue('allowZipDownload', true))); $folder->assign('usedSpacePercent', 0); $folder->assign('fileHeader', $fileHeader); From 946fccc0dd5b7e51203d51fd2c60161cad7050ba Mon Sep 17 00:00:00 2001 From: Pellaeon Lin Date: Thu, 6 Feb 2014 12:26:12 +0800 Subject: [PATCH 167/181] Remove unused template variable assignment of files_sharing/template/public.php --- apps/files_sharing/public.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/apps/files_sharing/public.php b/apps/files_sharing/public.php index fc716a514b..f03ac7205a 100644 --- a/apps/files_sharing/public.php +++ b/apps/files_sharing/public.php @@ -144,15 +144,12 @@ if (isset($path)) { OCP\Util::addScript('files', 'jquery.fileupload'); $maxUploadFilesize=OCP\Util::maxUploadFilesize($path); $tmpl = new OCP\Template('files_sharing', 'public', 'base'); - $tmpl->assign('uidOwner', $shareOwner); $tmpl->assign('displayName', \OCP\User::getDisplayName($shareOwner)); $tmpl->assign('filename', $file); $tmpl->assign('directory_path', $linkItem['file_target']); $tmpl->assign('mimetype', \OC\Files\Filesystem::getMimeType($path)); - $tmpl->assign('fileTarget', basename($linkItem['file_target'])); $tmpl->assign('dirToken', $linkItem['token']); $tmpl->assign('sharingToken', $token); - $tmpl->assign('disableSharing', true); $allowPublicUploadEnabled = (bool) ($linkItem['permissions'] & OCP\PERMISSION_CREATE); if (OC_Appconfig::getValue('core', 'shareapi_allow_public_upload', 'yes') === 'no') { $allowPublicUploadEnabled = false; @@ -160,8 +157,6 @@ if (isset($path)) { if ($linkItem['item_type'] !== 'folder') { $allowPublicUploadEnabled = false; } - $tmpl->assign('uploadMaxFilesize', $maxUploadFilesize); - $tmpl->assign('uploadMaxHumanFilesize', OCP\Util::humanFileSize($maxUploadFilesize)); $urlLinkIdentifiers= (isset($token)?'&t='.$token:'') .(isset($_GET['dir'])?'&dir='.$_GET['dir']:'') From 88087b21c7dad792a73a764248829e2c83faa49e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Fri, 7 Feb 2014 00:40:08 +0100 Subject: [PATCH 168/181] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ca7b04a925..47778c8c93 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,8 @@ A personal cloud which runs on your own server. ### Build Status on [Jenkins CI](https://ci.owncloud.org/) -Git master: [![Build Status](https://ci.owncloud.org/buildStatus/icon?job=ownCloud-Server%28master%29)](https://ci.owncloud.org/job/ownCloud-Server%28master%29/) +Git master: [![Build Status](https://ci.owncloud.org/job/server-master-linux/badge/icon)](https://ci.owncloud.org/job/server-master-linux/) +Quality: [![Scrutinizer Quality Score](https://scrutinizer-ci.com/g/owncloud/core/badges/quality-score.png?s=ce2f5ded03d4ac628e9ee5c767243fa7412e644f)](https://scrutinizer-ci.com/g/owncloud/core/) ### Installation instructions http://doc.owncloud.org/server/5.0/developer_manual/app/gettingstarted.html From b9e724d4ae7635435b3cc7793237c3ab9fe2a1c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Fri, 7 Feb 2014 00:40:57 +0100 Subject: [PATCH 169/181] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 47778c8c93..3f76c1a477 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ A personal cloud which runs on your own server. ### Build Status on [Jenkins CI](https://ci.owncloud.org/) Git master: [![Build Status](https://ci.owncloud.org/job/server-master-linux/badge/icon)](https://ci.owncloud.org/job/server-master-linux/) + Quality: [![Scrutinizer Quality Score](https://scrutinizer-ci.com/g/owncloud/core/badges/quality-score.png?s=ce2f5ded03d4ac628e9ee5c767243fa7412e644f)](https://scrutinizer-ci.com/g/owncloud/core/) ### Installation instructions From a8943ad02207afbf142ec48f4b53cbe1be943253 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Thu, 6 Feb 2014 16:01:42 +0100 Subject: [PATCH 170/181] replace 'size' with 'unencrypted_size' if encryption is enabled --- apps/files_sharing/lib/cache.php | 15 +++++++++++++-- apps/files_sharing/lib/share/file.php | 9 ++++++++- lib/public/share.php | 2 +- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/apps/files_sharing/lib/cache.php b/apps/files_sharing/lib/cache.php index 86e324409f..1b102f9e5f 100644 --- a/apps/files_sharing/lib/cache.php +++ b/apps/files_sharing/lib/cache.php @@ -92,12 +92,11 @@ class Shared_Cache extends Cache { } else { $query = \OC_DB::prepare( 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`,' - .' `size`, `mtime`, `encrypted`' + .' `size`, `mtime`, `encrypted`, `unencrypted_size`' .' FROM `*PREFIX*filecache` WHERE `fileid` = ?'); $result = $query->execute(array($file)); $data = $result->fetchRow(); $data['fileid'] = (int)$data['fileid']; - $data['size'] = (int)$data['size']; $data['mtime'] = (int)$data['mtime']; $data['storage_mtime'] = (int)$data['storage_mtime']; $data['encrypted'] = (bool)$data['encrypted']; @@ -106,6 +105,12 @@ class Shared_Cache extends Cache { if ($data['storage_mtime'] === 0) { $data['storage_mtime'] = $data['mtime']; } + if ($data['encrypted'] or ($data['unencrypted_size'] > 0 and $data['mimetype'] === 'httpd/unix-directory')) { + $data['encrypted_size'] = (int)$data['size']; + $data['size'] = (int)$data['unencrypted_size']; + } else { + $data['size'] = (int)$data['size']; + } return $data; } return false; @@ -334,6 +339,12 @@ class Shared_Cache extends Cache { } $row['mimetype'] = $this->getMimetype($row['mimetype']); $row['mimepart'] = $this->getMimetype($row['mimepart']); + if ($row['encrypted'] or ($row['unencrypted_size'] > 0 and $row['mimetype'] === 'httpd/unix-directory')) { + $row['encrypted_size'] = $row['size']; + $row['size'] = $row['unencrypted_size']; + } else { + $row['size'] = $row['size']; + } $files[] = $row; } } diff --git a/apps/files_sharing/lib/share/file.php b/apps/files_sharing/lib/share/file.php index c956c55a1d..ec0f368386 100644 --- a/apps/files_sharing/lib/share/file.php +++ b/apps/files_sharing/lib/share/file.php @@ -91,10 +91,17 @@ class OC_Share_Backend_File implements OCP\Share_Backend_File_Dependent { $file['name'] = basename($item['file_target']); $file['mimetype'] = $item['mimetype']; $file['mimepart'] = $item['mimepart']; - $file['size'] = $item['size']; $file['mtime'] = $item['mtime']; $file['encrypted'] = $item['encrypted']; $file['etag'] = $item['etag']; + $storage = \OC\Files\Filesystem::getStorage('/'); + $cache = $storage->getCache(); + if ($item['encrypted'] or ($item['unencrypted_size'] > 0 and $cache->getMimetype($item['mimetype']) === 'httpd/unix-directory')) { + $file['size'] = $item['unencrypted_size']; + $file['encrypted_size'] = $item['size']; + } else { + $file['size'] = $item['size']; + } $files[] = $file; } return $files; diff --git a/lib/public/share.php b/lib/public/share.php index f832d04a70..ae7d29e8b8 100644 --- a/lib/public/share.php +++ b/lib/public/share.php @@ -1152,7 +1152,7 @@ class Share { $select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `*PREFIX*share`.`parent`, `uid_owner`, ' .'`share_type`, `share_with`, `file_source`, `path`, `file_target`, ' .'`permissions`, `expiration`, `storage`, `*PREFIX*filecache`.`parent` as `file_parent`, ' - .'`name`, `mtime`, `mimetype`, `mimepart`, `size`, `encrypted`, `etag`, `mail_send`'; + .'`name`, `mtime`, `mimetype`, `mimepart`, `size`, `unencrypted_size`, `encrypted`, `etag`, `mail_send`'; } else { $select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `item_target`, `*PREFIX*share`.`parent`, `share_type`, `share_with`, `uid_owner`, From af7366cd30f0df27cc1043f2c2b55def836d03db Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Fri, 7 Feb 2014 12:53:42 +0100 Subject: [PATCH 171/181] Only add files to file list when uploading to current directory Fix Issue #6683 --- apps/files/ajax/upload.php | 6 ++++-- apps/files/js/filelist.js | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/files/ajax/upload.php b/apps/files/ajax/upload.php index 8f6c42d662..754c34ef08 100644 --- a/apps/files/ajax/upload.php +++ b/apps/files/ajax/upload.php @@ -139,7 +139,8 @@ if (strpos($dir, '..') === false) { 'originalname' => $files['tmp_name'][$i], 'uploadMaxFilesize' => $maxUploadFileSize, 'maxHumanFilesize' => $maxHumanFileSize, - 'permissions' => $meta['permissions'] & $allowedPermissions + 'permissions' => $meta['permissions'] & $allowedPermissions, + 'directory' => \OC\Files\Filesystem::normalizePath(stripslashes($dir)), ); } @@ -166,7 +167,8 @@ if (strpos($dir, '..') === false) { 'originalname' => $files['tmp_name'][$i], 'uploadMaxFilesize' => $maxUploadFileSize, 'maxHumanFilesize' => $maxHumanFileSize, - 'permissions' => $meta['permissions'] & $allowedPermissions + 'permissions' => $meta['permissions'] & $allowedPermissions, + 'directory' => \OC\Files\Filesystem::normalizePath(stripslashes($dir)), ); } } diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js index f538af1036..e6aefd33c9 100644 --- a/apps/files/js/filelist.js +++ b/apps/files/js/filelist.js @@ -924,8 +924,8 @@ $(document).ready(function() { data.context.find('td.filesize').text(humanFileSize(size)); } else { - // only append new file if dragged onto current dir's crumb (last) - if (data.context && data.context.hasClass('crumb') && !data.context.hasClass('last')) { + // only append new file if uploaded into the current folder + if (file.directory !== FileList.getCurrentDirectory()) { return; } From dbec143f09f32832a52fb507ababb84518721370 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Fri, 7 Feb 2014 16:09:31 +0100 Subject: [PATCH 172/181] Change MySQL to MySQL/MariaDB in the frontend Fix issue #6269 --- core/setup/controller.php | 2 +- lib/private/setup/mysql.php | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/core/setup/controller.php b/core/setup/controller.php index 58ed4d28dc..697408cfb5 100644 --- a/core/setup/controller.php +++ b/core/setup/controller.php @@ -91,7 +91,7 @@ class Controller { $databases['sqlite'] = 'SQLite'; } if ($hasMySQL) { - $databases['mysql'] = 'MySQL'; + $databases['mysql'] = 'MySQL/MariaDB'; } if ($hasPostgreSQL) { $databases['pgsql'] = 'PostgreSQL'; diff --git a/lib/private/setup/mysql.php b/lib/private/setup/mysql.php index d97b6d2602..b2c28173b1 100644 --- a/lib/private/setup/mysql.php +++ b/lib/private/setup/mysql.php @@ -3,13 +3,13 @@ namespace OC\Setup; class MySQL extends AbstractDatabase { - public $dbprettyname = 'MySQL'; + public $dbprettyname = 'MySQL/MariaDB'; public function setupDatabase($username) { //check if the database user has admin right $connection = @mysql_connect($this->dbhost, $this->dbuser, $this->dbpassword); if(!$connection) { - throw new \DatabaseSetupException($this->trans->t('MySQL username and/or password not valid'), + throw new \DatabaseSetupException($this->trans->t('MySQL/MariaDB username and/or password not valid'), $this->trans->t('You need to enter either an existing account or the administrator.')); } $oldUser=\OC_Config::getValue('dbuser', false); @@ -82,14 +82,14 @@ class MySQL extends AbstractDatabase { $query = "CREATE USER '$name'@'localhost' IDENTIFIED BY '$password'"; $result = mysql_query($query, $connection); if (!$result) { - throw new \DatabaseSetupException($this->trans->t("MySQL user '%s'@'localhost' exists already.", array($name)), - $this->trans->t("Drop this user from MySQL", array($name))); + throw new \DatabaseSetupException($this->trans->t("MySQL/MariaDB user '%s'@'localhost' exists already.", array($name)), + $this->trans->t("Drop this user from MySQL/MariaDB", array($name))); } $query = "CREATE USER '$name'@'%' IDENTIFIED BY '$password'"; $result = mysql_query($query, $connection); if (!$result) { - throw new \DatabaseSetupException($this->trans->t("MySQL user '%s'@'%%' already exists", array($name)), - $this->trans->t("Drop this user from MySQL.")); + throw new \DatabaseSetupException($this->trans->t("MySQL/MariaDB user '%s'@'%%' already exists", array($name)), + $this->trans->t("Drop this user from MySQL/MariaDB.")); } } } From 13fa0e2a9d3f89e4479f30b847c7c197276e5537 Mon Sep 17 00:00:00 2001 From: Morris Jobke Date: Fri, 7 Feb 2014 17:47:42 +0100 Subject: [PATCH 173/181] Fix implied evals and doubled definition of variable fixes #7119 fixes #7120 fixes #7121 fixes #7122 --- apps/files/js/filelist.js | 10 ++++------ apps/files/js/files.js | 2 +- settings/js/personal.js | 4 ++-- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js index f538af1036..2883218b2c 100644 --- a/apps/files/js/filelist.js +++ b/apps/files/js/filelist.js @@ -435,10 +435,9 @@ window.FileList={ tr.attr('data-file', newname); var path = td.children('a.name').attr('href'); td.children('a.name').attr('href', path.replace(encodeURIComponent(oldname), encodeURIComponent(newname))); + var basename = newname; if (newname.indexOf('.') > 0 && tr.data('type') !== 'dir') { - var basename=newname.substr(0,newname.lastIndexOf('.')); - } else { - var basename=newname; + basename = newname.substr(0,newname.lastIndexOf('.')); } td.find('a.name span.nametext').text(basename); if (newname.indexOf('.') > 0 && tr.data('type') !== 'dir') { @@ -544,10 +543,9 @@ window.FileList={ td.children('a.name .span').text(newName); var path = td.children('a.name').attr('href'); td.children('a.name').attr('href', path.replace(encodeURIComponent(oldName), encodeURIComponent(newName))); + var basename = newName; if (newName.indexOf('.') > 0) { - var basename = newName.substr(0, newName.lastIndexOf('.')); - } else { - var basename = newName; + basename = newName.substr(0, newName.lastIndexOf('.')); } td.children('a.name').empty(); var span = $(''); diff --git a/apps/files/js/files.js b/apps/files/js/files.js index a535700c1b..1ec4c4ec7a 100644 --- a/apps/files/js/files.js +++ b/apps/files/js/files.js @@ -405,7 +405,7 @@ $(document).ready(function() { Files.resizeBreadcrumbs(width, true); // display storage warnings - setTimeout ( "Files.displayStorageWarnings()", 100 ); + setTimeout(Files.displayStorageWarnings, 100); OC.Notification.setDefault(Files.displayStorageWarnings); // only possible at the moment if user is logged in diff --git a/settings/js/personal.js b/settings/js/personal.js index e6e1d538a1..3b87646775 100644 --- a/settings/js/personal.js +++ b/settings/js/personal.js @@ -158,7 +158,7 @@ $(document).ready(function(){ if(typeof timeout !== 'undefined'){ clearTimeout(timeout); } - timeout = setTimeout('changeDisplayName()',1000); + timeout = setTimeout(changeDisplayName, 1000); } }); @@ -173,7 +173,7 @@ $(document).ready(function(){ if(typeof timeout !== 'undefined'){ clearTimeout(timeout); } - timeout = setTimeout('changeEmailAddress()',1000); + timeout = setTimeout(changeEmailAddress, 1000); } }); From 91254c304d454b6f7977037dbd5dd2db5e00ff9f Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Fri, 7 Feb 2014 15:57:13 +0100 Subject: [PATCH 174/181] name users after test --- apps/files_encryption/tests/hooks.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/files_encryption/tests/hooks.php b/apps/files_encryption/tests/hooks.php index c26cba6406..4452579174 100644 --- a/apps/files_encryption/tests/hooks.php +++ b/apps/files_encryption/tests/hooks.php @@ -36,8 +36,8 @@ use OCA\Encryption; */ class Test_Encryption_Hooks extends \PHPUnit_Framework_TestCase { - const TEST_ENCRYPTION_HOOKS_USER1 = "test-proxy-user1"; - const TEST_ENCRYPTION_HOOKS_USER2 = "test-proxy-user2"; + const TEST_ENCRYPTION_HOOKS_USER1 = "test-encryption-hooks-user1"; + const TEST_ENCRYPTION_HOOKS_USER2 = "test-encryption-hooks-user2"; /** * @var \OC_FilesystemView From 050e84a08fa8eee14e52f4dbbee572596ba002ce Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Mon, 10 Feb 2014 10:56:11 +0100 Subject: [PATCH 175/181] refuse login as long as the initial encryption is running --- apps/files_encryption/hooks/hooks.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php index 4c4b3f2040..83abf3ba9d 100644 --- a/apps/files_encryption/hooks/hooks.php +++ b/apps/files_encryption/hooks/hooks.php @@ -80,8 +80,15 @@ class Hooks { // Check if first-run file migration has already been performed $ready = false; - if ($util->getMigrationStatus() === Util::MIGRATION_OPEN) { + $migrationStatus = $util->getMigrationStatus(); + if ($migrationStatus === Util::MIGRATION_OPEN) { $ready = $util->beginMigration(); + } elseif ($migrationStatus === Util::MIGRATION_IN_PROGRESS) { + // refuse login as long as the initial encryption is running + while ($migrationStatus === Util::MIGRATION_IN_PROGRESS) { + sleep(60); + $migrationStatus = $util->getMigrationStatus(); + } } // If migration not yet done From bc17b40650875102521214d5f8b7580c3193b8df Mon Sep 17 00:00:00 2001 From: Arthur Schiwon Date: Tue, 4 Feb 2014 17:56:53 +0100 Subject: [PATCH 176/181] LDAP: extend LDAP wrapper search method for sizelimit, improves performance in wizard --- apps/user_ldap/lib/ildapwrapper.php | 4 +++- apps/user_ldap/lib/ldap.php | 6 +++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/user_ldap/lib/ildapwrapper.php b/apps/user_ldap/lib/ildapwrapper.php index 20587cba7d..e60cf5ec63 100644 --- a/apps/user_ldap/lib/ildapwrapper.php +++ b/apps/user_ldap/lib/ildapwrapper.php @@ -145,9 +145,11 @@ interface ILDAPWrapper { * @param $baseDN The DN of the entry to read from * @param $filter An LDAP filter * @param $attr array of the attributes to read + * @param $attrsonly optional, 1 if only attribute types shall be returned + * @param $limit optional, limits the result entries * @return an LDAP search result resource, false on error */ - public function search($link, $baseDN, $filter, $attr); + public function search($link, $baseDN, $filter, $attr, $attrsonly = 0, $limit = 0); /** * @brief Sets the value of the specified option to be $value diff --git a/apps/user_ldap/lib/ldap.php b/apps/user_ldap/lib/ldap.php index dda8533c41..a99c648012 100644 --- a/apps/user_ldap/lib/ldap.php +++ b/apps/user_ldap/lib/ldap.php @@ -85,9 +85,9 @@ class LDAP implements ILDAPWrapper { return $this->invokeLDAPMethod('read', $link, $baseDN, $filter, $attr); } - public function search($link, $baseDN, $filter, $attr) { - return $this->invokeLDAPMethod('search', $link, $baseDN, - $filter, $attr); + public function search($link, $baseDN, $filter, $attr, $attrsonly = 0, $limit = 0) { + return $this->invokeLDAPMethod('search', $link, $baseDN, $filter, + $attr, $attrsonly, $limit); } public function setOption($link, $option, $value) { From a908bd56953edb94f48dc483278f5427d51c17b2 Mon Sep 17 00:00:00 2001 From: Arthur Schiwon Date: Tue, 4 Feb 2014 19:37:40 +0100 Subject: [PATCH 177/181] throw an info message, when base dn test failed --- apps/user_ldap/lib/wizard.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/user_ldap/lib/wizard.php b/apps/user_ldap/lib/wizard.php index b70ede8599..30ce455274 100644 --- a/apps/user_ldap/lib/wizard.php +++ b/apps/user_ldap/lib/wizard.php @@ -567,6 +567,10 @@ class Wizard extends LDAPUtility { //get a result set > 0 on a proper base $rr = $this->ldap->search($cr, $base, 'objectClass=*', array('dn'), 0, 1); if(!$this->ldap->isResource($rr)) { + $errorNo = $this->ldap->errno($cr); + $errorMsg = $this->ldap->error($cr); + \OCP\Util::writeLog('user_ldap', 'Wiz: Could not search base '.$base. + ' Error '.$errorNo.': '.$errorMsg, \OCP\Util::INFO); return false; } $entries = $this->ldap->countEntries($cr, $rr); From e825a008c9b99199bc91b87cb0e5ca88109aa202 Mon Sep 17 00:00:00 2001 From: Arthur Schiwon Date: Wed, 5 Feb 2014 10:29:09 +0100 Subject: [PATCH 178/181] Wizard: disable LDAP referrals, fixes #6670 --- apps/user_ldap/lib/wizard.php | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/user_ldap/lib/wizard.php b/apps/user_ldap/lib/wizard.php index 30ce455274..00623b74fb 100644 --- a/apps/user_ldap/lib/wizard.php +++ b/apps/user_ldap/lib/wizard.php @@ -1014,6 +1014,7 @@ class Wizard extends LDAPUtility { $this->configuration->ldapPort); $this->ldap->setOption($cr, LDAP_OPT_PROTOCOL_VERSION, 3); + $this->ldap->setOption($cr, LDAP_OPT_REFERRALS, 0); $this->ldap->setOption($cr, LDAP_OPT_NETWORK_TIMEOUT, self::LDAP_NW_TIMEOUT); if($this->configuration->ldapTLS === 1) { $this->ldap->startTls($cr); From a76840d20650b09d1a403c3f8e78dbf398a46fda Mon Sep 17 00:00:00 2001 From: Arthur Schiwon Date: Wed, 5 Feb 2014 10:30:56 +0100 Subject: [PATCH 179/181] Wizard: enable base DN for editing, if not base DN could have been detected. Also part of fix for #6670 --- apps/user_ldap/js/settings.js | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/user_ldap/js/settings.js b/apps/user_ldap/js/settings.js index acf88ef58a..792638f2b5 100644 --- a/apps/user_ldap/js/settings.js +++ b/apps/user_ldap/js/settings.js @@ -240,6 +240,7 @@ var LdapWizard = { LdapWizard.hideSpinner('#ldap_base'); LdapWizard.showInfoBox('Please specify a Base DN'); LdapWizard.showInfoBox('Could not determine Base DN'); + $('#ldap_base').prop('disabled', false); } ); } From e156f85bfb7ea1b6d74227a49507e1a3b0e0e374 Mon Sep 17 00:00:00 2001 From: Arthur Schiwon Date: Wed, 5 Feb 2014 10:33:44 +0100 Subject: [PATCH 180/181] Rephrase and clarify log message --- apps/user_ldap/lib/access.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/user_ldap/lib/access.php b/apps/user_ldap/lib/access.php index 72f9c74092..b619f62f29 100644 --- a/apps/user_ldap/lib/access.php +++ b/apps/user_ldap/lib/access.php @@ -729,7 +729,7 @@ class Access extends LDAPUtility { } } else { if(!is_null($limit)) { - \OCP\Util::writeLog('user_ldap', 'Paged search failed :(', \OCP\Util::INFO); + \OCP\Util::writeLog('user_ldap', 'Paged search was not available', \OCP\Util::INFO); } } } From 299d37154b749855915c8dbc7ab8a123c4aa27f2 Mon Sep 17 00:00:00 2001 From: Arthur Schiwon Date: Fri, 7 Feb 2014 15:55:35 +0100 Subject: [PATCH 181/181] LDAP: add documentation info in info.xml --- apps/user_ldap/appinfo/info.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/user_ldap/appinfo/info.xml b/apps/user_ldap/appinfo/info.xml index 148a72cecb..9cc908e852 100644 --- a/apps/user_ldap/appinfo/info.xml +++ b/apps/user_ldap/appinfo/info.xml @@ -14,4 +14,7 @@ + + http://doc.owncloud.org/server/6.0/go.php?to=admin-ldap +