Merge branch 'master' into migration_unit_tests

This commit is contained in:
Bart Visscher 2014-02-10 21:32:17 +01:00
commit 082abdc620
304 changed files with 19753 additions and 6901 deletions

1
.gitignore vendored
View File

@ -88,6 +88,7 @@ nbproject
# Tests - auto-generated files # Tests - auto-generated files
/data-autotest /data-autotest
/tests/coverage* /tests/coverage*
/tests/karma-coverage
/tests/autoconfig* /tests/autoconfig*
/tests/autotest* /tests/autotest*
/tests/data/lorem-copy.txt /tests/data/lorem-copy.txt

View File

@ -26,7 +26,7 @@ RewriteRule ^.well-known/carddav /remote.php/carddav/ [R]
RewriteRule ^.well-known/caldav /remote.php/caldav/ [R] RewriteRule ^.well-known/caldav /remote.php/caldav/ [R]
RewriteRule ^apps/calendar/caldav.php remote.php/caldav/ [QSA,L] RewriteRule ^apps/calendar/caldav.php remote.php/caldav/ [QSA,L]
RewriteRule ^apps/contacts/carddav.php remote.php/carddav/ [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] RewriteRule ^remote/(.*) remote.php [QSA,L]
</IfModule> </IfModule>
<IfModule mod_mime.c> <IfModule mod_mime.c>
@ -38,3 +38,6 @@ DirectoryIndex index.php index.html
</IfModule> </IfModule>
AddDefaultCharset utf-8 AddDefaultCharset utf-8
Options -Indexes Options -Indexes
<IfModule pagespeed_module>
ModPagespeed Off
</IfModule>

28
.jshintrc Normal file
View File

@ -0,0 +1,28 @@
{
"camelCase": true,
"eqeqeq": true,
"immed": true,
"latedef": false,
"noarg": true,
"nonbsp": true,
"undef": true,
"unused": true,
"trailing": true,
"maxparams": 5,
"curly": true,
"jquery": true,
"maxlen": 80,
"indent": 4,
"browser": true,
"globals": {
"console": true,
"it": true,
"itx": true,
"expect": true,
"describe": true,
"beforeEach": true,
"afterEach": true,
"sinon": true,
"fakeServer": true
}
}

@ -1 +1 @@
Subproject commit daf25846dbb8a326f4801dc3310cd2b8ab1f84b9 Subproject commit 7c2c94c904c2721763e97d5bafd115f863080a60

View File

@ -4,7 +4,9 @@
A personal cloud which runs on your own server. A personal cloud which runs on your own server.
### Build Status on [Jenkins CI](https://ci.owncloud.org/) ### 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 ### Installation instructions
http://doc.owncloud.org/server/5.0/developer_manual/app/gettingstarted.html http://doc.owncloud.org/server/5.0/developer_manual/app/gettingstarted.html

View File

@ -64,6 +64,15 @@ if(strpos($filename, '/') !== false) {
exit(); 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? //TODO why is stripslashes used on foldername in newfolder.php but not here?
$target = $dir.'/'.$filename; $target = $dir.'/'.$filename;

View File

@ -29,6 +29,15 @@ if(strpos($foldername, '/') !== false) {
exit(); 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? //TODO why is stripslashes used on foldername here but not in newfile.php?
$target = $dir . '/' . stripslashes($foldername); $target = $dir . '/' . stripslashes($foldername);

View File

@ -8,6 +8,7 @@ OCP\JSON::setContentTypeHeader('text/plain');
// If no token is sent along, rely on login only // If no token is sent along, rely on login only
$allowedPermissions = OCP\PERMISSION_ALL; $allowedPermissions = OCP\PERMISSION_ALL;
$errorCode = null;
$l = OC_L10N::get('files'); $l = OC_L10N::get('files');
if (empty($_POST['dirToken'])) { if (empty($_POST['dirToken'])) {
@ -34,6 +35,7 @@ if (empty($_POST['dirToken'])) {
// resolve reshares // resolve reshares
$rootLinkItem = OCP\Share::resolveReShare($linkItem); $rootLinkItem = OCP\Share::resolveReShare($linkItem);
OCP\JSON::checkUserExists($rootLinkItem['uid_owner']);
// Setup FS with owner // Setup FS with owner
OC_Util::tearDownFS(); OC_Util::tearDownFS();
OC_Util::setupFS($rootLinkItem['uid_owner']); OC_Util::setupFS($rootLinkItem['uid_owner']);
@ -124,7 +126,8 @@ if (strpos($dir, '..') === false) {
$meta = \OC\Files\Filesystem::getFileInfo($target); $meta = \OC\Files\Filesystem::getFileInfo($target);
if ($meta === false) { 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 { } else {
$result[] = array('status' => 'success', $result[] = array('status' => 'success',
'mime' => $meta['mimetype'], 'mime' => $meta['mimetype'],
@ -136,7 +139,8 @@ if (strpos($dir, '..') === false) {
'originalname' => $files['tmp_name'][$i], 'originalname' => $files['tmp_name'][$i],
'uploadMaxFilesize' => $maxUploadFileSize, 'uploadMaxFilesize' => $maxUploadFileSize,
'maxHumanFilesize' => $maxHumanFileSize, 'maxHumanFilesize' => $maxHumanFileSize,
'permissions' => $meta['permissions'] & $allowedPermissions 'permissions' => $meta['permissions'] & $allowedPermissions,
'directory' => \OC\Files\Filesystem::normalizePath(stripslashes($dir)),
); );
} }
@ -163,7 +167,8 @@ if (strpos($dir, '..') === false) {
'originalname' => $files['tmp_name'][$i], 'originalname' => $files['tmp_name'][$i],
'uploadMaxFilesize' => $maxUploadFileSize, 'uploadMaxFilesize' => $maxUploadFileSize,
'maxHumanFilesize' => $maxHumanFileSize, 'maxHumanFilesize' => $maxHumanFileSize,
'permissions' => $meta['permissions'] & $allowedPermissions 'permissions' => $meta['permissions'] & $allowedPermissions,
'directory' => \OC\Files\Filesystem::normalizePath(stripslashes($dir)),
); );
} }
} }
@ -176,5 +181,5 @@ if ($error === false) {
OCP\JSON::encodedPrint($result); OCP\JSON::encodedPrint($result);
exit(); exit();
} else { } 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))));
} }

View File

@ -52,6 +52,7 @@ $server->addPlugin(new OC_Connector_Sabre_FilesPlugin());
$server->addPlugin(new OC_Connector_Sabre_AbortedUploadDetectionPlugin()); $server->addPlugin(new OC_Connector_Sabre_AbortedUploadDetectionPlugin());
$server->addPlugin(new OC_Connector_Sabre_QuotaPlugin()); $server->addPlugin(new OC_Connector_Sabre_QuotaPlugin());
$server->addPlugin(new OC_Connector_Sabre_MaintenancePlugin()); $server->addPlugin(new OC_Connector_Sabre_MaintenancePlugin());
$server->addPlugin(new OC_Connector_Sabre_ExceptionLoggerPlugin('webdav'));
// And off we go! // And off we go!
$server->exec(); $server->exec();

View File

@ -3,7 +3,7 @@
See the COPYING-README file. */ See the COPYING-README file. */
/* FILE MENU */ /* 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 input, .actions button, .actions .button { margin:0; float:left; }
.actions .button a { color: #555; } .actions .button a { color: #555; }
.actions .button a:hover, .actions .button a:active { color: #333; } .actions .button a:hover, .actions .button a:active { color: #333; }
@ -33,9 +33,9 @@
#new>ul { #new>ul {
display: none; display: none;
position: fixed; position: fixed;
min-width: 7em; min-width: 112px;
z-index: 10; z-index: 10;
padding: .5em; padding: 8px;
padding-bottom: 0; padding-bottom: 0;
margin-top: 14px; margin-top: 14px;
margin-left: -1px; margin-left: -1px;
@ -46,7 +46,7 @@
border-top-left-radius: 0; border-top-left-radius: 0;
box-shadow:0 2px 7px rgba(170,170,170,.4); 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; } background-repeat:no-repeat; cursor:pointer; }
#new>ul>li>p { cursor:pointer; padding-top: 7px; padding-bottom: 7px;} #new>ul>li>p { cursor:pointer; padding-top: 7px; padding-bottom: 7px;}
@ -65,10 +65,15 @@
top: 44px; top: 44px;
width: 100%; width: 100%;
} }
#filestable, #controls { /* make sure there's enough room for the file actions */
min-width: 680px; #body-user #filestable {
min-width: 750px;
} }
#filestable tbody tr { background-color:#fff; height:2.5em; } #body-user #controls {
min-width: 600px;
}
#filestable tbody tr { background-color:#fff; height:40px; }
#filestable tbody tr:hover, tbody tr:active { #filestable tbody tr:hover, tbody tr:active {
background-color: rgb(240,240,240); background-color: rgb(240,240,240);
} }
@ -83,7 +88,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; } 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; } 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 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 { table th .name {
position: absolute; position: absolute;
left: 55px; left: 55px;
@ -98,7 +103,7 @@ table td {
} }
table th#headerName { table th#headerName {
position: relative; 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; padding: 0;
} }
#headerName-container { #headerName-container {
@ -106,15 +111,17 @@ table th#headerName {
height: 50px; height: 50px;
} }
table th#headerSize, table td.filesize { table th#headerSize, table td.filesize {
min-width: 3em; min-width: 48px;
padding: 0 1em; padding: 0 16px;
text-align: right; text-align: right;
} }
table th#headerDate, table td.date { table th#headerDate, table td.date {
-moz-box-sizing: border-box; -moz-box-sizing: border-box;
box-sizing: border-box; box-sizing: border-box;
position: relative; position: relative;
min-width: 11em; /* this can not be just width, both need to be set … table styling */
min-width: 176px;
max-width: 176px;
} }
/* Multiselect bar */ /* Multiselect bar */
@ -140,9 +147,9 @@ table.multiselect thead th {
} }
table.multiselect #headerName { table.multiselect #headerName {
position: relative; position: relative;
width: 100%; 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.selection, table th.selection, table td.fileaction { width:32px; text-align:center; }
table td.filename a.name { table td.filename a.name {
position:relative; /* Firefox needs to explicitly have this default set … */ position:relative; /* Firefox needs to explicitly have this default set … */
-moz-box-sizing: border-box; -moz-box-sizing: border-box;
@ -160,8 +167,8 @@ table td.filename input.filename {
margin-left: 2px; margin-left: 2px;
cursor: text; 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 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:.3em 0; } table td.filename .nametext, .uploadtext, .modified { float:left; padding:14px 0; }
#modified { #modified {
position: absolute; position: absolute;
@ -169,6 +176,15 @@ table td.filename .nametext, .uploadtext, .modified { float:left; padding:.3em 0
} }
.modified { .modified {
position: relative; position: relative;
padding-left: 8px;
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) */ /* TODO fix usability bug (accidental file/folder selection) */
@ -181,8 +197,8 @@ table td.filename .nametext {
text-overflow: ellipsis; text-overflow: ellipsis;
max-width: 800px; max-width: 800px;
} }
table td.filename .uploadtext { font-weight:normal; margin-left:.5em; } table td.filename .uploadtext { font-weight:normal; margin-left:8px; }
table td.filename form { font-size:.85em; margin-left:3em; margin-right:3em; } table td.filename form { font-size:14px; margin-left:48px; margin-right:48px; }
.ie8 input[type="checkbox"]{ .ie8 input[type="checkbox"]{
padding: 0; padding: 0;
@ -217,6 +233,11 @@ table td.filename form { font-size:.85em; margin-left:3em; margin-right:3em; }
width: 50px; width: 50px;
z-index: 5; 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 { #fileList tr td.filename>input[type="checkbox"] + label {
left: 0; left: 0;
} }
@ -237,7 +258,7 @@ table td.filename form { font-size:.85em; margin-left:3em; margin-right:3em; }
#fileList tr td.filename a.name label { #fileList tr td.filename a.name label {
position: absolute; position: absolute;
width: 100%; width: 80%;
height: 50px; height: 50px;
} }
@ -248,14 +269,16 @@ table td.filename form { font-size:.85em; margin-left:3em; margin-right:3em; }
position: absolute; position: absolute;
top: 14px; top: 14px;
right: 0; right: 0;
font-size: 11px;
} }
#fileList img.move2trash { display:inline; margin:-.5em 0; padding:1em .5em 1em .5em !important; float:right; } #fileList img.move2trash { display:inline; margin:-8px 0; padding:16px 8px 16px 8px !important; float:right; }
#fileList a.action.delete { #fileList a.action.delete {
position: absolute; position: absolute;
right: 0; 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; } a.action>img { max-height:16px; max-width:16px; vertical-align:text-bottom; }
/* Actions for selected files */ /* Actions for selected files */
@ -272,19 +295,23 @@ a.action>img { max-height:16px; max-width:16px; vertical-align:text-bottom; }
} }
.selectedActions a img { .selectedActions a img {
position:relative; position:relative;
top:.3em; top:5px;
} }
#fileList a.action { #fileList a.action {
display: inline; display: inline;
margin: -.5em 0; margin: -8px 0;
padding: 18px 8px !important; padding: 18px 8px !important;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";
filter: alpha(opacity=0); filter: alpha(opacity=0);
opacity: 0; opacity: 0;
display:none; display:none;
} }
#fileList a.action[data-action="Rename"] {
padding:18px 14px !important;
}
#fileList tr:hover a.action, #fileList a.action.permanent { #fileList tr:hover a.action, #fileList a.action.permanent {
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=50)"; -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=50)";
filter: alpha(opacity=50); filter: alpha(opacity=50);

View File

@ -5,7 +5,7 @@
height: 36px; height: 36px;
width: 39px; width: 39px;
padding: 0 !important; /* override default control bar button padding */ padding: 0 !important; /* override default control bar button padding */
margin-left: .2em; margin-left: 3px;
overflow: hidden; overflow: hidden;
vertical-align: top; vertical-align: top;
} }
@ -18,9 +18,6 @@
margin: -5px -3px; margin: -5px -3px;
cursor: pointer; cursor: pointer;
z-index: 10; z-index: 10;
background-image: url('%webroot%/core/img/actions/upload.svg');
background-repeat: no-repeat;
background-position: center;
opacity: .65; opacity: .65;
} }
.file_upload_target { display:none; } .file_upload_target { display:none; }
@ -33,7 +30,7 @@
height: 44px; height: 44px;
margin: -5px -3px; margin: -5px -3px;
padding: 0; padding: 0;
font-size: 1em; font-size: 16px;
-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; filter:alpha(opacity=0); opacity:0; -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; filter:alpha(opacity=0); opacity:0;
z-index: 20; z-index: 20;
cursor: pointer; cursor: pointer;
@ -119,11 +116,6 @@
.oc-dialog .fileexists .conflict input[type='checkbox'] { .oc-dialog .fileexists .conflict input[type='checkbox'] {
float: left; float: left;
} }
.oc-dialog .fileexists .toggle {
background-image: url('%webroot%/core/img/actions/triangle-e.png');
width: 16px;
height: 16px;
}
.oc-dialog .fileexists #allfileslabel { .oc-dialog .fileexists #allfileslabel {
float:right; float:right;
} }

View File

@ -37,12 +37,7 @@ if(!\OC\Files\Filesystem::file_exists($filename)) {
$ftype=\OC\Files\Filesystem::getMimeType( $filename ); $ftype=\OC\Files\Filesystem::getMimeType( $filename );
header('Content-Type:'.$ftype); header('Content-Type:'.$ftype);
if ( preg_match( "/MSIE/", $_SERVER["HTTP_USER_AGENT"] ) ) { OCP\Response::setContentDispositionHeader(basename($filename), 'attachment');
header( 'Content-Disposition: attachment; filename="' . rawurlencode( basename($filename) ) . '"' );
} else {
header( 'Content-Disposition: attachment; filename*=UTF-8\'\'' . rawurlencode( basename($filename) )
. '; filename="' . rawurlencode( basename($filename) ) . '"' );
}
OCP\Response::disableCaching(); OCP\Response::disableCaching();
header('Content-Length: '.\OC\Files\Filesystem::filesize($filename)); header('Content-Length: '.\OC\Files\Filesystem::filesize($filename));

View File

@ -63,7 +63,6 @@ $files = array();
$user = OC_User::getUser(); $user = OC_User::getUser();
if (\OC\Files\Cache\Upgrade::needUpgrade($user)) { //dont load anything if we need to upgrade the cache if (\OC\Files\Cache\Upgrade::needUpgrade($user)) { //dont load anything if we need to upgrade the cache
$needUpgrade = true; $needUpgrade = true;
$freeSpace = 0;
} else { } else {
if ($isIE8){ if ($isIE8){
// after the redirect above, the URL will have a format // 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{ else{
$files = \OCA\Files\Helper::getFiles($dir); $files = \OCA\Files\Helper::getFiles($dir);
} }
$freeSpace = \OC\Files\Filesystem::free_space($dir);
$needUpgrade = false; $needUpgrade = false;
} }
@ -103,6 +101,8 @@ if ($needUpgrade) {
} else { } else {
// information about storage capacities // information about storage capacities
$storageInfo=OC_Helper::getStorageInfo($dir); $storageInfo=OC_Helper::getStorageInfo($dir);
$freeSpace=$storageInfo['free'];
$uploadLimit=OCP\Util::uploadLimit();
$maxUploadFilesize=OCP\Util::maxUploadFilesize($dir); $maxUploadFilesize=OCP\Util::maxUploadFilesize($dir);
$publicUploadEnabled = \OC_Appconfig::getValue('core', 'shareapi_allow_public_upload', 'yes'); $publicUploadEnabled = \OC_Appconfig::getValue('core', 'shareapi_allow_public_upload', 'yes');
// if the encryption app is disabled, than everything is fine (INIT_SUCCESSFUL status code) // if the encryption app is disabled, than everything is fine (INIT_SUCCESSFUL status code)
@ -134,8 +134,10 @@ if ($needUpgrade) {
$tmpl->assign('files', $files); $tmpl->assign('files', $files);
$tmpl->assign('trash', $trashEnabled); $tmpl->assign('trash', $trashEnabled);
$tmpl->assign('trashEmpty', $trashEmpty); $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('uploadMaxHumanFilesize', OCP\Util::humanFileSize($maxUploadFilesize));
$tmpl->assign('freeSpace', $freeSpace);
$tmpl->assign('uploadLimit', $uploadLimit); // PHP upload limit
$tmpl->assign('allowZipDownload', intval(OCP\Config::getSystemValue('allowZipDownload', true))); $tmpl->assign('allowZipDownload', intval(OCP\Config::getSystemValue('allowZipDownload', true)));
$tmpl->assign('usedSpacePercent', (int)$storageInfo['relative']); $tmpl->assign('usedSpacePercent', (int)$storageInfo['relative']);
$tmpl->assign('isPublic', false); $tmpl->assign('isPublic', false);

View File

@ -1,3 +1,13 @@
/*
* Copyright (c) 2014
*
* This file is licensed under the Affero General Public License version 3
* or later.
*
* See the COPYING-README file.
*
*/
function switchPublicFolder() function switchPublicFolder()
{ {
var publicEnable = $('#publicEnable').is(':checked'); var publicEnable = $('#publicEnable').is(':checked');

View File

@ -1,3 +1,13 @@
/*
* Copyright (c) 2014
*
* This file is licensed under the Affero General Public License version 3
* or later.
*
* See the COPYING-README file.
*
*/
/** /**
* The file upload code uses several hooks to interact with blueimps jQuery file upload library: * The file upload code uses several hooks to interact with blueimps jQuery file upload library:
* 1. the core upload handling hooks are added when initializing the plugin, * 1. the core upload handling hooks are added when initializing the plugin,
@ -8,6 +18,8 @@
* - TODO music upload button * - TODO music upload button
*/ */
/* global OC, t, n */
/** /**
* Function that will allow us to know if Ajax uploads are supported * Function that will allow us to know if Ajax uploads are supported
* @link https://github.com/New-Bamboo/example-ajax-upload/blob/master/public/index.html * @link https://github.com/New-Bamboo/example-ajax-upload/blob/master/public/index.html
@ -222,6 +234,14 @@ $(document).ready(function() {
//examine file //examine file
var file = data.files[0]; var file = data.files[0];
try {
// FIXME: not so elegant... need to refactor that method to return a value
Files.isFileNameValid(file.name);
}
catch (errorMessage) {
data.textStatus = 'invalidcharacters';
data.errorThrown = errorMessage;
}
if (file.type === '' && file.size === 4096) { if (file.type === '' && file.size === 4096) {
data.textStatus = 'dirorzero'; data.textStatus = 'dirorzero';
@ -233,10 +253,22 @@ $(document).ready(function() {
// add size // add size
selection.totalBytes += file.size; selection.totalBytes += file.size;
//check max upload size // check PHP upload limit
if (selection.totalBytes > $('#max_upload').val()) { if (selection.totalBytes > $('#upload_limit').val()) {
data.textStatus = 'sizeexceedlimit';
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.textStatus = 'notenoughspace';
data.errorThrown = t('files', 'Not enough space available'); 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 // end upload for whole selection on error
@ -307,6 +339,13 @@ $(document).ready(function() {
} else { } else {
// HTTP connection problem // HTTP connection problem
OC.Notification.show(data.errorThrown); 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 //hide notification after 10 sec
setTimeout(function() { setTimeout(function() {
@ -605,7 +644,7 @@ $(document).ready(function() {
if (result.status === 'success') { if (result.status === 'success') {
var date=new Date(); var date=new Date();
FileList.addDir(name, 0, date, hidden); FileList.addDir(name, 0, date, hidden);
var tr=$('tr[data-file="'+name+'"]'); var tr = FileList.findFileEl(name);
tr.attr('data-id', result.data.id); tr.attr('data-id', result.data.id);
} else { } else {
OC.dialogs.alert(result.data.message, t('core', 'Could not create folder')); OC.dialogs.alert(result.data.message, t('core', 'Could not create folder'));
@ -647,7 +686,7 @@ $(document).ready(function() {
$('#uploadprogressbar').fadeOut(); $('#uploadprogressbar').fadeOut();
var date = new Date(); var date = new Date();
FileList.addFile(localName, size, date, false, hidden); FileList.addFile(localName, size, date, false, hidden);
var tr = $('tr[data-file="'+localName+'"]'); var tr = FileList.findFileEl(localName);
tr.data('mime', mime).data('id', id); tr.data('mime', mime).data('id', id);
tr.attr('data-id', id); tr.attr('data-id', id);
var path = $('#dir').val()+'/'+localName; var path = $('#dir').val()+'/'+localName;

View File

@ -1,3 +1,15 @@
/*
* Copyright (c) 2014
*
* This file is licensed under the Affero General Public License version 3
* or later.
*
* See the COPYING-README file.
*
*/
/* global OC, FileList */
/* global trashBinApp */
var FileActions = { var FileActions = {
actions: {}, actions: {},
defaults: {}, defaults: {},
@ -45,8 +57,9 @@ var FileActions = {
return filteredActions; return filteredActions;
}, },
getDefault: function (mime, type, permissions) { getDefault: function (mime, type, permissions) {
var mimePart;
if (mime) { if (mime) {
var mimePart = mime.substr(0, mime.indexOf('/')); mimePart = mime.substr(0, mime.indexOf('/'));
} }
var name = false; var name = false;
if (mime && FileActions.defaults[mime]) { if (mime && FileActions.defaults[mime]) {
@ -71,13 +84,15 @@ var FileActions = {
FileActions.currentFile = parent; FileActions.currentFile = parent;
var actions = FileActions.get(FileActions.getCurrentMimeType(), FileActions.getCurrentType(), FileActions.getCurrentPermissions()); var actions = FileActions.get(FileActions.getCurrentMimeType(), FileActions.getCurrentType(), FileActions.getCurrentPermissions());
var file = FileActions.getCurrentFile(); var file = FileActions.getCurrentFile();
if ($('tr[data-file="'+file+'"]').data('renaming')) { var nameLinks;
if (FileList.findFileEl(file).data('renaming')) {
return; return;
} }
// recreate fileactions // recreate fileactions
parent.children('a.name').find('.fileactions').remove(); nameLinks = parent.children('a.name');
parent.children('a.name').append('<span class="fileactions" />'); nameLinks.find('.fileactions, .nametext .action').remove();
nameLinks.append('<span class="fileactions" />');
var defaultAction = FileActions.getDefault(FileActions.getCurrentMimeType(), FileActions.getCurrentType(), FileActions.getCurrentPermissions()); var defaultAction = FileActions.getDefault(FileActions.getCurrentMimeType(), FileActions.getCurrentType(), FileActions.getCurrentPermissions());
var actionHandler = function (event) { var actionHandler = function (event) {
@ -97,21 +112,30 @@ var FileActions = {
} }
if ((name === 'Download' || action !== defaultAction) && name !== 'Delete') { if ((name === 'Download' || action !== defaultAction) && name !== 'Delete') {
var img = FileActions.icons[name]; var img = FileActions.icons[name],
actionText = t('files', name),
actionContainer = 'a.name>span.fileactions';
if (name === 'Rename') {
// rename has only an icon which appears behind
// the file name
actionText = '';
actionContainer = 'a.name span.nametext';
}
if (img.call) { if (img.call) {
img = img(file); img = img(file);
} }
var html = '<a href="#" class="action" data-action="' + name + '">'; var html = '<a href="#" class="action" data-action="' + name + '">';
if (img) { if (img) {
html += '<img class ="svg" src="' + img + '" /> '; html += '<img class ="svg" src="' + img + '" />';
} }
html += t('files', name) + '</a>'; html += '<span> ' + actionText + '</span></a>';
var element = $(html); var element = $(html);
element.data('action', name); element.data('action', name);
//alert(element); //alert(element);
element.on('click', {a: null, elem: parent, actionFunc: actions[name]}, actionHandler); element.on('click', {a: null, elem: parent, actionFunc: actions[name]}, actionHandler);
parent.find('a.name>span.fileactions').append(element); parent.find(actionContainer).append(element);
} }
}; };
@ -130,13 +154,14 @@ var FileActions = {
parent.parent().children().last().find('.action.delete').remove(); parent.parent().children().last().find('.action.delete').remove();
if (actions['Delete']) { if (actions['Delete']) {
var img = FileActions.icons['Delete']; var img = FileActions.icons['Delete'];
var html;
if (img.call) { if (img.call) {
img = img(file); img = img(file);
} }
if (typeof trashBinApp !== 'undefined' && trashBinApp) { if (typeof trashBinApp !== 'undefined' && trashBinApp) {
var html = '<a href="#" original-title="' + t('files', 'Delete permanently') + '" class="action delete delete-icon" />'; html = '<a href="#" original-title="' + t('files', 'Delete permanently') + '" class="action delete delete-icon" />';
} else { } else {
var html = '<a href="#" class="action delete delete-icon" />'; html = '<a href="#" class="action delete delete-icon" />';
} }
var element = $(html); var element = $(html);
element.data('action', actions['Delete']); element.data('action', actions['Delete']);
@ -163,17 +188,21 @@ var FileActions = {
}; };
$(document).ready(function () { $(document).ready(function () {
var downloadScope;
if ($('#allowZipDownload').val() == 1) { if ($('#allowZipDownload').val() == 1) {
var downloadScope = 'all'; downloadScope = 'all';
} else { } else {
var downloadScope = 'file'; downloadScope = 'file';
} }
if (typeof disableDownloadActions == 'undefined' || !disableDownloadActions) { if (typeof disableDownloadActions == 'undefined' || !disableDownloadActions) {
FileActions.register(downloadScope, 'Download', OC.PERMISSION_READ, function () { FileActions.register(downloadScope, 'Download', OC.PERMISSION_READ, function () {
return OC.imagePath('core', 'actions/download'); return OC.imagePath('core', 'actions/download');
}, function (filename) { }, 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 () { $('#fileList tr').each(function () {

View File

@ -1,4 +1,16 @@
var FileList={ /*
* Copyright (c) 2014
*
* This file is licensed under the Affero General Public License version 3
* or later.
*
* See the COPYING-README file.
*
*/
/* global OC, t, n, FileList, FileActions, Files */
/* global procesSelection, dragOptions, SVGSupport, replaceSVG */
window.FileList={
useUndo:true, useUndo:true,
postProcessList: function() { postProcessList: function() {
$('#fileList tr').each(function() { $('#fileList tr').each(function() {
@ -6,6 +18,13 @@ var FileList={
$(this).attr('data-file',decodeURIComponent($(this).attr('data-file'))); $(this).attr('data-file',decodeURIComponent($(this).attr('data-file')));
}); });
}, },
/**
* Returns the tr element for a given file name
*/
findFileEl: function(fileName){
// use filterAttr to avoid escaping issues
return $('#fileList tr').filterAttr('data-file', fileName);
},
update:function(fileListHtml) { update:function(fileListHtml) {
var $fileList = $('#fileList'); var $fileList = $('#fileList');
$fileList.empty().html(fileListHtml); $fileList.empty().html(fileListHtml);
@ -20,6 +39,9 @@ var FileList={
Files.setupDragAndDrop(); Files.setupDragAndDrop();
} }
FileList.updateFileSummary(); FileList.updateFileSummary();
procesSelection();
$(window).scrollTop(0);
$fileList.trigger(jQuery.Event("updated")); $fileList.trigger(jQuery.Event("updated"));
}, },
createRow:function(type, name, iconurl, linktarget, size, lastModified, permissions) { createRow:function(type, name, iconurl, linktarget, size, lastModified, permissions) {
@ -182,6 +204,7 @@ var FileList={
return OC.linkTo('files', 'index.php')+"?dir="+ encodeURIComponent(dir).replace(/%2F/g, '/'); return OC.linkTo('files', 'index.php')+"?dir="+ encodeURIComponent(dir).replace(/%2F/g, '/');
}, },
setCurrentDir: function(targetDir, changeUrl) { setCurrentDir: function(targetDir, changeUrl) {
var url;
$('#dir').val(targetDir); $('#dir').val(targetDir);
if (changeUrl !== false) { if (changeUrl !== false) {
if (window.history.pushState && changeUrl !== false) { if (window.history.pushState && changeUrl !== false) {
@ -292,8 +315,12 @@ var FileList={
$('#filestable').toggleClass('hidden', show); $('#filestable').toggleClass('hidden', show);
}, },
remove:function(name){ remove:function(name){
$('tr').filterAttr('data-file',name).find('td.filename').draggable('destroy'); var fileEl = FileList.findFileEl(name);
$('tr').filterAttr('data-file',name).remove(); if (fileEl.data('permissions') & OC.PERMISSION_DELETE) {
// file is only draggable when delete permissions are set
fileEl.find('td.filename').draggable('destroy');
}
fileEl.remove();
FileList.updateFileSummary(); FileList.updateFileSummary();
if ( ! $('tr[data-file]').exists() ) { if ( ! $('tr[data-file]').exists() ) {
$('#emptycontent').removeClass('hidden'); $('#emptycontent').removeClass('hidden');
@ -334,7 +361,7 @@ var FileList={
FileList.updateFileSummary(); FileList.updateFileSummary();
}, },
loadingDone:function(name, id) { loadingDone:function(name, id) {
var mime, tr = $('tr[data-file="'+name+'"]'); var mime, tr = FileList.findFileEl(name);
tr.data('loading', false); tr.data('loading', false);
mime = tr.data('mime'); mime = tr.data('mime');
tr.attr('data-mime', mime); tr.attr('data-mime', mime);
@ -347,12 +374,12 @@ var FileList={
}, null, null, tr.attr('data-etag')); }, null, null, tr.attr('data-etag'));
tr.find('td.filename').draggable(dragOptions); tr.find('td.filename').draggable(dragOptions);
}, },
isLoading:function(name) { isLoading:function(file) {
return $('tr[data-file="'+name+'"]').data('loading'); return FileList.findFileEl(file).data('loading');
}, },
rename:function(oldname) { rename:function(oldname) {
var tr, td, input, form; var tr, td, input, form;
tr = $('tr[data-file="'+oldname+'"]'); tr = FileList.findFileEl(oldname);
tr.data('renaming',true); tr.data('renaming',true);
td = tr.children('td.filename'); td = tr.children('td.filename');
input = $('<input type="text" class="filename"/>').val(oldname); input = $('<input type="text" class="filename"/>').val(oldname);
@ -408,10 +435,9 @@ var FileList={
tr.attr('data-file', newname); tr.attr('data-file', newname);
var path = td.children('a.name').attr('href'); var path = td.children('a.name').attr('href');
td.children('a.name').attr('href', path.replace(encodeURIComponent(oldname), encodeURIComponent(newname))); td.children('a.name').attr('href', path.replace(encodeURIComponent(oldname), encodeURIComponent(newname)));
var basename = newname;
if (newname.indexOf('.') > 0 && tr.data('type') !== 'dir') { if (newname.indexOf('.') > 0 && tr.data('type') !== 'dir') {
var basename=newname.substr(0,newname.lastIndexOf('.')); basename = newname.substr(0,newname.lastIndexOf('.'));
} else {
var basename=newname;
} }
td.find('a.name span.nametext').text(basename); td.find('a.name span.nametext').text(basename);
if (newname.indexOf('.') > 0 && tr.data('type') !== 'dir') { if (newname.indexOf('.') > 0 && tr.data('type') !== 'dir') {
@ -464,6 +490,7 @@ var FileList={
td.find('a.name span.extension').text(newname.substr(newname.lastIndexOf('.'))); td.find('a.name span.extension').text(newname.substr(newname.lastIndexOf('.')));
} }
form.remove(); form.remove();
FileActions.display( tr.find('td.filename'), true);
td.children('a.name').show(); td.children('a.name').show();
} catch (error) { } catch (error) {
input.attr('title', error); input.attr('title', error);
@ -500,24 +527,25 @@ var FileList={
form.trigger('submit'); form.trigger('submit');
}); });
}, },
inList:function(filename) { inList:function(file) {
return $('#fileList tr[data-file="'+filename+'"]').length; return FileList.findFileEl(file).length;
}, },
replace:function(oldName, newName, isNewFile) { replace:function(oldName, newName, isNewFile) {
// Finish any existing actions // Finish any existing actions
$('tr[data-file="'+oldName+'"]').hide(); var oldFileEl = FileList.findFileEl(oldName);
$('tr[data-file="'+newName+'"]').hide(); var newFileEl = FileList.findFileEl(newName);
var tr = $('tr[data-file="'+oldName+'"]').clone(); oldFileEl.hide();
newFileEl.hide();
var tr = oldFileEl.clone();
tr.attr('data-replace', 'true'); tr.attr('data-replace', 'true');
tr.attr('data-file', newName); tr.attr('data-file', newName);
var td = tr.children('td.filename'); var td = tr.children('td.filename');
td.children('a.name .span').text(newName); td.children('a.name .span').text(newName);
var path = td.children('a.name').attr('href'); var path = td.children('a.name').attr('href');
td.children('a.name').attr('href', path.replace(encodeURIComponent(oldName), encodeURIComponent(newName))); td.children('a.name').attr('href', path.replace(encodeURIComponent(oldName), encodeURIComponent(newName)));
if (newName.indexOf('.') > 0) {
var basename = newName.substr(0, newName.lastIndexOf('.'));
} else {
var basename = newName; var basename = newName;
if (newName.indexOf('.') > 0) {
basename = newName.substr(0, newName.lastIndexOf('.'));
} }
td.children('a.name').empty(); td.children('a.name').empty();
var span = $('<span class="nametext"></span>'); var span = $('<span class="nametext"></span>');
@ -559,7 +587,7 @@ var FileList={
files=[files]; files=[files];
} }
for (var i=0; i<files.length; i++) { for (var i=0; i<files.length; i++) {
var deleteAction = $('tr[data-file="'+files[i]+'"]').children("td.date").children(".action.delete"); var deleteAction = FileList.findFileEl(files[i]).children("td.date").children(".action.delete");
deleteAction.removeClass('delete-icon').addClass('progress-icon'); deleteAction.removeClass('delete-icon').addClass('progress-icon');
} }
// Finish any existing actions // Finish any existing actions
@ -573,7 +601,7 @@ var FileList={
function(result) { function(result) {
if (result.status === 'success') { if (result.status === 'success') {
$.each(files,function(index,file) { $.each(files,function(index,file) {
var files = $('tr[data-file="'+file+'"]'); var files = FileList.findFileEl(file);
files.remove(); files.remove();
files.find('input[type="checkbox"]').removeAttr('checked'); files.find('input[type="checkbox"]').removeAttr('checked');
files.removeClass('selected'); files.removeClass('selected');
@ -595,7 +623,7 @@ var FileList={
OC.Notification.hide(); OC.Notification.hide();
}, 10000); }, 10000);
$.each(files,function(index,file) { $.each(files,function(index,file) {
var deleteAction = $('tr[data-file="' + file + '"] .action.delete'); var deleteAction = FileList.findFileEl(file).find('.action.delete');
deleteAction.removeClass('progress-icon').addClass('delete-icon'); deleteAction.removeClass('progress-icon').addClass('delete-icon');
}); });
} }
@ -737,7 +765,7 @@ var FileList={
}, },
scrollTo:function(file) { scrollTo:function(file) {
//scroll to and highlight preselected file //scroll to and highlight preselected file
var $scrolltorow = $('tr[data-file="'+file+'"]'); var $scrolltorow = FileList.findFileEl(file);
if ($scrolltorow.exists()) { if ($scrolltorow.exists()) {
$scrolltorow.addClass('searchresult'); $scrolltorow.addClass('searchresult');
$(window).scrollTop($scrolltorow.position().top); $(window).scrollTop($scrolltorow.position().top);
@ -765,6 +793,20 @@ var FileList={
$('#fileList tr.searchresult').each(function(i,e) { $('#fileList tr.searchresult').each(function(i,e) {
$(e).removeClass("searchresult"); $(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);
} }
}; };
@ -880,8 +922,8 @@ $(document).ready(function() {
data.context.find('td.filesize').text(humanFileSize(size)); data.context.find('td.filesize').text(humanFileSize(size));
} else { } else {
// only append new file if dragged onto current dir's crumb (last) // only append new file if uploaded into the current folder
if (data.context && data.context.hasClass('crumb') && !data.context.hasClass('last')) { if (file.directory !== FileList.getCurrentDirectory()) {
return; return;
} }
@ -949,7 +991,7 @@ $(document).ready(function() {
$('#notification').on('click', '.undo', function() { $('#notification').on('click', '.undo', function() {
if (FileList.deleteFiles) { if (FileList.deleteFiles) {
$.each(FileList.deleteFiles,function(index,file) { $.each(FileList.deleteFiles,function(index,file) {
$('tr[data-file="'+file+'"]').show(); FileList.findFileEl(file).show();
}); });
FileList.deleteCanceled=true; FileList.deleteCanceled=true;
FileList.deleteFiles=null; FileList.deleteFiles=null;
@ -959,10 +1001,10 @@ $(document).ready(function() {
FileList.deleteCanceled = false; FileList.deleteCanceled = false;
FileList.deleteFiles = [FileList.replaceOldName]; FileList.deleteFiles = [FileList.replaceOldName];
} else { } else {
$('tr[data-file="'+FileList.replaceOldName+'"]').show(); FileList.findFileEl(FileList.replaceOldName).show();
} }
$('tr[data-replace="true"').remove(); $('tr[data-replace="true"').remove();
$('tr[data-file="'+FileList.replaceNewName+'"]').show(); FileList.findFileEl(FileList.replaceNewName).show();
FileList.replaceCanceled = true; FileList.replaceCanceled = true;
FileList.replaceOldName = null; FileList.replaceOldName = null;
FileList.replaceNewName = null; FileList.replaceNewName = null;
@ -977,7 +1019,8 @@ $(document).ready(function() {
}); });
}); });
$('#notification:first-child').on('click', '.suggest', function() { $('#notification:first-child').on('click', '.suggest', function() {
$('tr[data-file="'+$('#notification > span').attr('data-oldName')+'"]').show(); var file = $('#notification > span').attr('data-oldName');
FileList.findFileEl(file).show();
OC.Notification.hide(); OC.Notification.hide();
}); });
$('#notification:first-child').on('click', '.cancel', function() { $('#notification:first-child').on('click', '.cancel', function() {

View File

@ -1,4 +1,16 @@
Files={ /*
* Copyright (c) 2014
*
* This file is licensed under the Affero General Public License version 3
* or later.
*
* See the COPYING-README file.
*
*/
/* global OC, t, n, FileList, FileActions */
/* global getURLParameter, isPublic */
var Files = {
// file space size sync // file space size sync
_updateStorageStatistics: function() { _updateStorageStatistics: function() {
Files._updateStorageStatisticsTimeout = null; Files._updateStorageStatisticsTimeout = null;
@ -41,6 +53,7 @@ Files={
} }
if (response.data !== undefined && response.data.uploadMaxFilesize !== undefined) { if (response.data !== undefined && response.data.uploadMaxFilesize !== undefined) {
$('#max_upload').val(response.data.uploadMaxFilesize); $('#max_upload').val(response.data.uploadMaxFilesize);
$('#free_space').val(response.data.freeSpace);
$('#upload.button').attr('original-title', response.data.maxHumanFilesize); $('#upload.button').attr('original-title', response.data.maxHumanFilesize);
$('#usedSpacePercent').val(response.data.usedSpacePercent); $('#usedSpacePercent').val(response.data.usedSpacePercent);
Files.displayStorageWarnings(); Files.displayStorageWarnings();
@ -67,17 +80,25 @@ Files={
return fileName; return fileName;
}, },
isFileNameValid:function (name) { /**
if (name === '.') { * Checks whether the given file name is valid.
throw t('files', '\'.\' is an invalid file name.'); * @param name file name to check
} else if (name.length === 0) { * @return true if the file name is valid.
* Throws a string exception with an error message if
* the file name is not valid
*/
isFileNameValid: function (name) {
var trimmedName = name.trim();
if (trimmedName === '.' || trimmedName === '..') {
throw t('files', '"{name}" is an invalid file name.', {name: name});
} else if (trimmedName.length === 0) {
throw t('files', 'File name cannot be empty.'); throw t('files', 'File name cannot be empty.');
} }
// check for invalid characters // check for invalid characters
var invalid_characters = ['\\', '/', '<', '>', ':', '"', '|', '?', '*']; var invalid_characters =
['\\', '/', '<', '>', ':', '"', '|', '?', '*', '\n'];
for (var i = 0; i < invalid_characters.length; i++) { for (var i = 0; i < invalid_characters.length; i++) {
if (name.indexOf(invalid_characters[i]) !== -1) { if (trimmedName.indexOf(invalid_characters[i]) !== -1) {
throw t('files', "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed."); throw t('files', "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed.");
} }
} }
@ -282,7 +303,7 @@ $(document).ready(function() {
procesSelection(); procesSelection();
} else { } else {
var filename=$(this).parent().parent().attr('data-file'); var filename=$(this).parent().parent().attr('data-file');
var tr=$('tr[data-file="'+filename+'"]'); var tr = FileList.findFileEl(filename);
var renaming=tr.data('renaming'); var renaming=tr.data('renaming');
if (!renaming && !FileList.isLoading(filename)) { if (!renaming && !FileList.isLoading(filename)) {
FileActions.currentFile = $(this).parent(); FileActions.currentFile = $(this).parent();
@ -384,7 +405,7 @@ $(document).ready(function() {
Files.resizeBreadcrumbs(width, true); Files.resizeBreadcrumbs(width, true);
// display storage warnings // display storage warnings
setTimeout ( "Files.displayStorageWarnings()", 100 ); setTimeout(Files.displayStorageWarnings, 100);
OC.Notification.setDefault(Files.displayStorageWarnings); OC.Notification.setDefault(Files.displayStorageWarnings);
// only possible at the moment if user is logged in // only possible at the moment if user is logged in
@ -493,7 +514,7 @@ var createDragShadow = function(event) {
var dir=$('#dir').val(); var dir=$('#dir').val();
$(selectedFiles).each(function(i,elem) { $(selectedFiles).each(function(i,elem) {
var newtr = $('<tr/>').attr('data-dir', dir).attr('data-filename', elem.name); var newtr = $('<tr/>').attr('data-dir', dir).attr('data-filename', elem.name).attr('data-origin', elem.origin);
newtr.append($('<td/>').addClass('filename').text(elem.name)); newtr.append($('<td/>').addClass('filename').text(elem.name));
newtr.append($('<td/>').addClass('size').text(humanFileSize(elem.size))); newtr.append($('<td/>').addClass('size').text(humanFileSize(elem.size)));
tbody.append(newtr); tbody.append(newtr);
@ -511,11 +532,28 @@ var createDragShadow = function(event) {
}; };
//options for file drag/drop //options for file drag/drop
//start&stop handlers needs some cleaning up
var dragOptions={ var dragOptions={
revert: 'invalid', revertDuration: 300, revert: 'invalid', revertDuration: 300,
opacity: 0.7, zIndex: 100, appendTo: 'body', cursorAt: { left: 24, top: 18 }, opacity: 0.7, zIndex: 100, appendTo: 'body', cursorAt: { left: 24, top: 18 },
helper: createDragShadow, cursor: 'move', helper: createDragShadow, cursor: 'move',
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) { 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'); $('#fileList tr td.filename').addClass('ui-draggable');
} }
}; };
@ -525,6 +563,7 @@ if ( $('html.ie').length === 0) {
} }
var folderDropOptions={ var folderDropOptions={
hoverClass: "canDrop",
drop: function( event, ui ) { drop: function( event, ui ) {
//don't allow moving a file into a selected folder //don't allow moving a file into a selected folder
if ($(event.target).parents('tr').find('td input:first').prop('checked') === true) { if ($(event.target).parents('tr').find('td input:first').prop('checked') === true) {
@ -537,14 +576,21 @@ var folderDropOptions={
$(files).each(function(i,row) { $(files).each(function(i,row) {
var dir = $(row).data('dir'); var dir = $(row).data('dir');
var file = $(row).data('filename'); 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) { $.post(OC.filePath('files', 'ajax', 'move.php'), { dir: dir, file: file, target: dir+'/'+target }, function(result) {
if (result) { if (result) {
if (result.status === 'success') { if (result.status === 'success') {
//recalculate folder size //recalculate folder size
var oldSize = $('#fileList tr[data-file="'+target+'"]').data('size'); var oldFile = FileList.findFileEl(target);
var newSize = oldSize + $('#fileList tr[data-file="'+file+'"]').data('size'); var newFile = FileList.findFileEl(file);
$('#fileList tr[data-file="'+target+'"]').data('size', newSize); var oldSize = oldFile.data('size');
$('#fileList tr[data-file="'+target+'"]').find('td.filesize').text(humanFileSize(newSize)); var newSize = oldSize + newFile.data('size');
oldFile.data('size', newSize);
oldFile.find('td.filesize').text(humanFileSize(newSize));
FileList.remove(file); FileList.remove(file);
procesSelection(); procesSelection();
@ -557,6 +603,7 @@ var folderDropOptions={
} else { } else {
OC.dialogs.alert(t('files', 'Error moving file'), t('files', 'Error')); OC.dialogs.alert(t('files', 'Error moving file'), t('files', 'Error'));
} }
td.css('background-image', oldBackgroundImage);
}); });
}); });
}, },
@ -581,6 +628,11 @@ var crumbDropOptions={
$(files).each(function(i,row) { $(files).each(function(i,row) {
var dir = $(row).data('dir'); var dir = $(row).data('dir');
var file = $(row).data('filename'); 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) { $.post(OC.filePath('files', 'ajax', 'move.php'), { dir: dir, file: file, target: target }, function(result) {
if (result) { if (result) {
if (result.status === 'success') { if (result.status === 'success') {
@ -595,6 +647,7 @@ var crumbDropOptions={
} else { } else {
OC.dialogs.alert(t('files', 'Error moving file'), t('files', 'Error')); OC.dialogs.alert(t('files', 'Error moving file'), t('files', 'Error'));
} }
td.css('background-image', oldBackgroundImage);
}); });
}); });
}, },
@ -610,21 +663,22 @@ function procesSelection() {
return el.type==='dir'; return el.type==='dir';
}); });
if (selectedFiles.length === 0 && selectedFolders.length === 0) { if (selectedFiles.length === 0 && selectedFolders.length === 0) {
$('#headerName>span.name').text(t('files','Name')); $('#headerName span.name').text(t('files','Name'));
$('#headerSize').text(t('files','Size')); $('#headerSize').text(t('files','Size'));
$('#modified').text(t('files','Modified')); $('#modified').text(t('files','Modified'));
$('table').removeClass('multiselect'); $('table').removeClass('multiselect');
$('.selectedActions').hide(); $('.selectedActions').hide();
$('#select_all').removeAttr('checked');
} }
else { else {
$('.selectedActions').show(); $('.selectedActions').show();
var totalSize = 0; var totalSize = 0;
for(var i=0; i<selectedFiles.length; i++) { for(var i=0; i<selectedFiles.length; i++) {
totalSize+=selectedFiles[i].size; totalSize+=selectedFiles[i].size;
}; }
for(var i=0; i<selectedFolders.length; i++) { for(var i=0; i<selectedFolders.length; i++) {
totalSize+=selectedFolders[i].size; totalSize+=selectedFolders[i].size;
}; }
$('#headerSize').text(humanFileSize(totalSize)); $('#headerSize').text(humanFileSize(totalSize));
var selection = ''; var selection = '';
if (selectedFolders.length > 0) { if (selectedFolders.length > 0) {
@ -660,7 +714,8 @@ function getSelectedFilesTrash(property) {
mime:$(element).data('mime'), mime:$(element).data('mime'),
type:$(element).data('type'), type:$(element).data('type'),
size:$(element).data('size'), size:$(element).data('size'),
etag:$(element).data('etag') etag:$(element).data('etag'),
origin: $(element).data('id')
}; };
if (property) { if (property) {
files.push(file[property]); files.push(file[property]);
@ -717,7 +772,7 @@ Files.lazyLoadPreview = function(path, mime, ready, width, height, etag) {
console.warn('Files.lazyLoadPreview(): missing etag argument'); console.warn('Files.lazyLoadPreview(): missing etag argument');
} }
if ( $('#publicUploadButtonMock').length ) { if ( $('#isPublic').length ) {
urlSpec.t = $('#dirToken').val(); urlSpec.t = $('#dirToken').val();
previewURL = OC.Router.generate('core_ajax_public_preview', urlSpec); previewURL = OC.Router.generate('core_ajax_public_preview', urlSpec);
} else { } else {
@ -735,10 +790,11 @@ Files.lazyLoadPreview = function(path, mime, ready, width, height, etag) {
} }
img.src = previewURL; img.src = previewURL;
}); });
} };
function getUniqueName(name) { function getUniqueName(name) {
if ($('tr[data-file="'+name+'"]').exists()) { if (FileList.findFileEl(name).exists()) {
var numMatch;
var parts=name.split('.'); var parts=name.split('.');
var extension = ""; var extension = "";
if (parts.length > 1) { if (parts.length > 1) {
@ -772,7 +828,7 @@ function checkTrashStatus() {
function onClickBreadcrumb(e) { function onClickBreadcrumb(e) {
var $el = $(e.target).closest('.crumb'), var $el = $(e.target).closest('.crumb'),
$targetDir = $el.data('dir'); $targetDir = $el.data('dir'),
isPublic = !!$('#isPublic').val(); isPublic = !!$('#isPublic').val();
if ($targetDir !== undefined && !isPublic) { if ($targetDir !== undefined && !isPublic) {
@ -780,3 +836,4 @@ function onClickBreadcrumb(e) {
FileList.changeDirectory(decodeURIComponent($targetDir)); FileList.changeDirectory(decodeURIComponent($targetDir));
} }
} }

View File

@ -1,3 +1,14 @@
/*
* Copyright (c) 2014
*
* This file is licensed under the Affero General Public License version 3
* or later.
*
* See the COPYING-README file.
*
*/
/* global OC */
$(document).ready(function () { $(document).ready(function () {
var eventSource, total, bar = $('#progressbar'); var eventSource, total, bar = $('#progressbar');
console.log('start'); console.log('start');

View File

@ -1,3 +1,14 @@
/*
* Copyright (c) 2014
*
* This file is licensed under the Affero General Public License version 3
* or later.
*
* See the COPYING-README file.
*
*/
/* global OC */
function Upload(fileSelector) { function Upload(fileSelector) {
if ($.support.xhrFileUpload) { if ($.support.xhrFileUpload) {
return new XHRUpload(fileSelector.target.files); return new XHRUpload(fileSelector.target.files);

View File

@ -6,6 +6,7 @@ $TRANSLATIONS = array(
"File name must not contain \"/\". Please choose a different name." => "Faili nimi ei tohi sisaldada \"/\". Palun vali mõni teine nimi.", "File name must not contain \"/\". Please choose a different name." => "Faili nimi ei tohi sisaldada \"/\". Palun vali mõni teine nimi.",
"The name %s is already used in the folder %s. Please choose a different name." => "Nimi %s on juba kasutusel kataloogis %s. Palun vali mõni teine nimi.", "The name %s is already used in the folder %s. Please choose a different name." => "Nimi %s on juba kasutusel kataloogis %s. Palun vali mõni teine nimi.",
"Not a valid source" => "Pole korrektne lähteallikas", "Not a valid source" => "Pole korrektne lähteallikas",
"Server is not allowed to open URLs, please check the server configuration" => "Server ei võimalda URL-ide avamist, palun kontrolli serveri seadistust",
"Error while downloading %s to %s" => "Viga %s allalaadimisel %s", "Error while downloading %s to %s" => "Viga %s allalaadimisel %s",
"Error when creating the file" => "Viga faili loomisel", "Error when creating the file" => "Viga faili loomisel",
"Folder name cannot be empty." => "Kataloogi nimi ei saa olla tühi.", "Folder name cannot be empty." => "Kataloogi nimi ei saa olla tühi.",
@ -36,6 +37,7 @@ $TRANSLATIONS = array(
"{new_name} already exists" => "{new_name} on juba olemas", "{new_name} already exists" => "{new_name} on juba olemas",
"Could not create file" => "Ei suuda luua faili", "Could not create file" => "Ei suuda luua faili",
"Could not create folder" => "Ei suuda luua kataloogi", "Could not create folder" => "Ei suuda luua kataloogi",
"Error fetching URL" => "Viga URL-i haaramisel",
"Share" => "Jaga", "Share" => "Jaga",
"Delete permanently" => "Kustuta jäädavalt", "Delete permanently" => "Kustuta jäädavalt",
"Rename" => "Nimeta ümber", "Rename" => "Nimeta ümber",

View File

@ -1,21 +0,0 @@
<?php
$TRANSLATIONS = array(
"File name cannot be empty." => "Имя файла не может быть пустым.",
"Files" => "Файлы",
"Share" => "Сделать общим",
"Rename" => "Переименовать",
"_%n folder_::_%n folders_" => array("","",""),
"_%n file_::_%n files_" => array("","",""),
"_Uploading %n file_::_Uploading %n files_" => array("","",""),
"'.' is an invalid file name." => "'.' является неверным именем файла.",
"Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "Некорректное имя, '\\', '/', '<', '>', ':', '\"', '|', '?' и '*' не допустимы.",
"Error" => "Ошибка",
"Size" => "Размер",
"Upload" => "Загрузка",
"0 is unlimited" => "0 без ограничений",
"Save" => "Сохранить",
"Cancel upload" => "Отмена загрузки",
"Download" => "Загрузка",
"Delete" => "Удалить"
);
$PLURAL_FORMS = "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);";

7
apps/files/l10n/ur.php Normal file
View File

@ -0,0 +1,7 @@
<?php
$TRANSLATIONS = array(
"_%n folder_::_%n folders_" => array("",""),
"_%n file_::_%n files_" => array("",""),
"_Uploading %n file_::_Uploading %n files_" => array("","")
);
$PLURAL_FORMS = "nplurals=2; plural=(n != 1);";

View File

@ -59,6 +59,13 @@ class App {
$result['data'] = array( $result['data'] = array(
'message' => $this->l10n->t("Invalid folder name. Usage of 'Shared' is reserved.") '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 // rename to existing file is denied
} else if ($this->view->file_exists($dir . '/' . $newname)) { } else if ($this->view->file_exists($dir . '/' . $newname)) {
@ -83,14 +90,17 @@ class App {
else { else {
$meta['type'] = 'file'; $meta['type'] = 'file';
} }
// these need to be set for determineIcon()
$meta['isPreviewAvailable'] = \OC::$server->getPreviewManager()->isMimeSupported($meta['mimetype']);
$meta['directory'] = $dir;
$fileinfo = array( $fileinfo = array(
'id' => $meta['fileid'], 'id' => $meta['fileid'],
'mime' => $meta['mimetype'], 'mime' => $meta['mimetype'],
'size' => $meta['size'], 'size' => $meta['size'],
'etag' => $meta['etag'], 'etag' => $meta['etag'],
'directory' => $dir, 'directory' => $meta['directory'],
'name' => $newname, 'name' => $newname,
'isPreviewAvailable' => \OC::$server->getPreviewManager()->isMimeSupported($meta['mimetype']), 'isPreviewAvailable' => $meta['isPreviewAvailable'],
'icon' => \OCA\Files\Helper::determineIcon($meta) 'icon' => \OCA\Files\Helper::determineIcon($meta)
); );
$result['success'] = true; $result['success'] = true;

View File

@ -15,6 +15,7 @@ class Helper
return array('uploadMaxFilesize' => $maxUploadFilesize, return array('uploadMaxFilesize' => $maxUploadFilesize,
'maxHumanFilesize' => $maxHumanFilesize, 'maxHumanFilesize' => $maxHumanFilesize,
'freeSpace' => $storageInfo['free'],
'usedSpacePercent' => (int)$storageInfo['relative']); 'usedSpacePercent' => (int)$storageInfo['relative']);
} }

View File

@ -5,7 +5,7 @@
<h2><?php p($l->t('File handling')); ?></h2> <h2><?php p($l->t('File handling')); ?></h2>
<?php if($_['uploadChangable']):?> <?php if($_['uploadChangable']):?>
<label for="maxUploadSize"><?php p($l->t( 'Maximum upload size' )); ?> </label> <label for="maxUploadSize"><?php p($l->t( 'Maximum upload size' )); ?> </label>
<input name='maxUploadSize' id="maxUploadSize" value='<?php p($_['uploadMaxFilesize']) ?>'/> <input type="text" name='maxUploadSize' id="maxUploadSize" value='<?php p($_['uploadMaxFilesize']) ?>'/>
<?php if($_['displayMaxPossibleUploadSize']):?> <?php if($_['displayMaxPossibleUploadSize']):?>
(<?php p($l->t('max. possible: ')); p($_['maxPossibleUploadSize']) ?>) (<?php p($l->t('max. possible: ')); p($_['maxPossibleUploadSize']) ?>)
<?php endif;?> <?php endif;?>

View File

@ -1,6 +1,7 @@
<div id="controls"> <div id="controls">
<?php print_unescaped($_['breadcrumb']); ?> <?php print_unescaped($_['breadcrumb']); ?>
<div class="actions creatable <?php if (!$_['isCreatable']):?>hidden<?php endif; ?>"> <div class="actions creatable <?php if (!$_['isCreatable']):?>hidden<?php endif; ?>">
<?php if(!isset($_['dirToken'])):?>
<div id="new" class="button"> <div id="new" class="button">
<a><?php p($l->t('New'));?></a> <a><?php p($l->t('New'));?></a>
<ul> <ul>
@ -12,21 +13,27 @@
data-type='web'><p><?php p($l->t('From link'));?></p></li> data-type='web'><p><?php p($l->t('From link'));?></p></li>
</ul> </ul>
</div> </div>
<?php endif;?>
<div id="upload" class="button" <div id="upload" class="button"
title="<?php p($l->t('Upload') . ' max. '.$_['uploadMaxHumanFilesize']) ?>"> title="<?php p($l->t('Upload') . ' max. '.$_['uploadMaxHumanFilesize']) ?>">
<?php if($_['uploadMaxFilesize'] >= 0):?> <?php if($_['uploadMaxFilesize'] >= 0):?>
<input type="hidden" name="MAX_FILE_SIZE" id="max_upload" <input type="hidden" id="max_upload" name="MAX_FILE_SIZE" value="<?php p($_['uploadMaxFilesize']) ?>">
value="<?php p($_['uploadMaxFilesize']) ?>"> <?php endif;?>
<input type="hidden" id="upload_limit" value="<?php p($_['uploadLimit']) ?>">
<input type="hidden" id="free_space" value="<?php p($_['freeSpace']) ?>">
<?php if(isset($_['dirToken'])):?>
<input type="hidden" id="publicUploadRequestToken" name="requesttoken" value="<?php p($_['requesttoken']) ?>" />
<input type="hidden" id="dirToken" name="dirToken" value="<?php p($_['dirToken']) ?>" />
<?php endif;?> <?php endif;?>
<input type="hidden" class="max_human_file_size" <input type="hidden" class="max_human_file_size"
value="(max <?php p($_['uploadMaxHumanFilesize']); ?>)"> value="(max <?php p($_['uploadMaxHumanFilesize']); ?>)">
<input type="hidden" name="dir" value="<?php p($_['dir']) ?>" id="dir"> <input type="hidden" name="dir" value="<?php p($_['dir']) ?>" id="dir">
<input type="file" id="file_upload_start" name='files[]' <input type="file" id="file_upload_start" name='files[]'
data-url="<?php print_unescaped(OCP\Util::linkTo('files', 'ajax/upload.php')); ?>" /> data-url="<?php print_unescaped(OCP\Util::linkTo('files', 'ajax/upload.php')); ?>" />
<a href="#" class="svg"></a> <a href="#" class="svg icon icon-upload"></a>
</div> </div>
<?php if ($_['trash']): ?> <?php if ($_['trash']): ?>
<input id="trash" type="button" value="<?php p($l->t('Deleted files'));?>" class="button" <?php $_['trashEmpty'] ? p('disabled') : '' ?>></input> <input id="trash" type="button" value="<?php p($l->t('Deleted files'));?>" class="button" <?php $_['trashEmpty'] ? p('disabled') : '' ?> />
<?php endif; ?> <?php endif; ?>
<div id="uploadprogresswrapper"> <div id="uploadprogresswrapper">
<div id="uploadprogressbar"></div> <div id="uploadprogressbar"></div>
@ -44,7 +51,7 @@
<div id="emptycontent" <?php if (!$_['emptyContent']):?>class="hidden"<?php endif; ?>><?php p($l->t('Nothing in here. Upload something!'))?></div> <div id="emptycontent" <?php if (!$_['emptyContent']):?>class="hidden"<?php endif; ?>><?php p($l->t('Nothing in here. Upload something!'))?></div>
<input type="hidden" id="disableSharing" data-status="<?php p($_['disableSharing']); ?>"></input> <input type="hidden" id="disableSharing" data-status="<?php p($_['disableSharing']); ?>" />
<table id="filestable" data-allow-public-upload="<?php p($_['publicUploadEnabled'])?>" data-preview-x="36" data-preview-y="36"> <table id="filestable" data-allow-public-upload="<?php p($_['publicUploadEnabled'])?>" data-preview-x="36" data-preview-y="36">
<thead> <thead>

View File

@ -1,6 +1,10 @@
<div class="crumb <?php if(!count($_["breadcrumb"])) p('last');?>" data-dir=''> <div class="crumb <?php if(!count($_["breadcrumb"])) p('last');?>" data-dir=''>
<a href="<?php print_unescaped($_['baseURL']); ?>"> <a href="<?php print_unescaped($_['baseURL']); ?>">
<?php if(isset($_['rootBreadCrumb'])):
echo $_['rootBreadCrumb'];
else:?>
<img src="<?php print_unescaped(OCP\image_path('core', 'places/home.svg'));?>" class="svg" /> <img src="<?php print_unescaped(OCP\image_path('core', 'places/home.svg'));?>" class="svg" />
<?php endif;?>
</a> </a>
</div> </div>
<?php for($i=0; $i<count($_["breadcrumb"]); $i++): <?php for($i=0; $i<count($_["breadcrumb"]); $i++):

View File

@ -18,7 +18,7 @@ $totalsize = 0; ?>
data-size="<?php p($file['size']);?>" data-size="<?php p($file['size']);?>"
data-etag="<?php p($file['etag']);?>" data-etag="<?php p($file['etag']);?>"
data-permissions="<?php p($file['permissions']); ?>"> data-permissions="<?php p($file['permissions']); ?>">
<?php if($file['isPreviewAvailable']): ?> <?php if(isset($file['isPreviewAvailable']) and $file['isPreviewAvailable']): ?>
<td class="filename svg preview-icon" <td class="filename svg preview-icon"
<?php else: ?> <?php else: ?>
<td class="filename svg" <td class="filename svg"

View File

@ -38,7 +38,7 @@ class Test_OC_Files_App_Rename extends \PHPUnit_Framework_TestCase {
$l10nMock->expects($this->any()) $l10nMock->expects($this->any())
->method('t') ->method('t')
->will($this->returnArgument(0)); ->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()) $viewMock->expects($this->any())
->method('normalizePath') ->method('normalizePath')
->will($this->returnArgument(0)); ->will($this->returnArgument(0));
@ -63,6 +63,11 @@ class Test_OC_Files_App_Rename extends \PHPUnit_Framework_TestCase {
$oldname = 'Shared'; $oldname = 'Shared';
$newname = 'new_name'; $newname = 'new_name';
$this->viewMock->expects($this->at(0))
->method('file_exists')
->with('/')
->will($this->returnValue(true));
$result = $this->files->rename($dir, $oldname, $newname); $result = $this->files->rename($dir, $oldname, $newname);
$expected = array( $expected = array(
'success' => false, 'success' => false,
@ -80,6 +85,11 @@ class Test_OC_Files_App_Rename extends \PHPUnit_Framework_TestCase {
$oldname = 'Shared'; $oldname = 'Shared';
$newname = 'new_name'; $newname = 'new_name';
$this->viewMock->expects($this->at(0))
->method('file_exists')
->with('/test')
->will($this->returnValue(true));
$this->viewMock->expects($this->any()) $this->viewMock->expects($this->any())
->method('getFileInfo') ->method('getFileInfo')
->will($this->returnValue(array( ->will($this->returnValue(array(
@ -129,6 +139,11 @@ class Test_OC_Files_App_Rename extends \PHPUnit_Framework_TestCase {
$oldname = 'oldname'; $oldname = 'oldname';
$newname = 'newname'; $newname = 'newname';
$this->viewMock->expects($this->at(0))
->method('file_exists')
->with('/')
->will($this->returnValue(true));
$this->viewMock->expects($this->any()) $this->viewMock->expects($this->any())
->method('getFileInfo') ->method('getFileInfo')
->will($this->returnValue(array( ->will($this->returnValue(array(
@ -141,7 +156,6 @@ class Test_OC_Files_App_Rename extends \PHPUnit_Framework_TestCase {
'name' => 'new_name', 'name' => 'new_name',
))); )));
$result = $this->files->rename($dir, $oldname, $newname); $result = $this->files->rename($dir, $oldname, $newname);
$this->assertTrue($result['success']); $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->assertEquals(\OC_Helper::mimetypeIcon('dir'), $result['data']['icon']);
$this->assertFalse($result['data']['isPreviewAvailable']); $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']);
}
} }

View File

@ -0,0 +1,75 @@
/**
* ownCloud
*
* @author Vincent Petry
* @copyright 2014 Vincent Petry <pvince81@owncloud.com>
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
/* global OC, FileActions, FileList */
describe('FileActions tests', function() {
var $filesTable;
beforeEach(function() {
// init horrible parameters
var $body = $('body');
$body.append('<input type="hidden" id="dir" value="/subdir"></input>');
$body.append('<input type="hidden" id="permissions" value="31"></input>');
// dummy files table
$filesTable = $body.append('<table id="filestable"></table>');
});
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('.nametext .action[data-action=Rename]').length).toEqual(1);
expect($tr.find('.action.delete').length).toEqual(1);
});
it('calling display() twice correctly replaces file actions', function() {
var $tr = FileList.addFile('testName.txt', 1234, new Date(), false, false, {download_url: 'test/download/url'});
FileActions.display($tr.find('td.filename'), true);
FileActions.display($tr.find('td.filename'), true);
// actions defined after cal
expect($tr.find('.action[data-action=Download]').length).toEqual(1);
expect($tr.find('.nametext .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();
});
});

View File

@ -0,0 +1,65 @@
/**
* ownCloud
*
* @author Vincent Petry
* @copyright 2014 Vincent Petry <pvince81@owncloud.com>
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
/* global OC, FileList */
describe('FileList tests', function() {
beforeEach(function() {
// init horrible parameters
var $body = $('body');
$body.append('<input type="hidden" id="dir" value="/subdir"></input>');
$body.append('<input type="hidden" id="permissions" value="31"></input>');
// dummy files table
$body.append('<table id="filestable"></table>');
});
afterEach(function() {
$('#dir, #permissions, #filestable').remove();
});
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');
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');
});
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');
});
});

View File

@ -0,0 +1,85 @@
/**
* ownCloud
*
* @author Vincent Petry
* @copyright 2014 Vincent Petry <pvince81@owncloud.com>
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
/* global Files */
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++ ) {
var error = false;
try {
expect(Files.isFileNameValid(fileNames[i])).toEqual(true);
}
catch (e) {
error = e;
}
expect(error).toEqual(false);
}
});
it('Detects invalid file names', function() {
var fileNames = [
'',
' ',
'.',
'..',
'back\\slash',
'sl/ash',
'lt<lt',
'gt>gt',
'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]);
console.error('Invalid file name not detected:', fileNames[i]);
}
catch (e) {
threwException = true;
}
expect(threwException).toEqual(true);
}
});
});
});

View File

@ -6,6 +6,7 @@ if (OC::$CLI) {
if (count($argv) === 2) { if (count($argv) === 2) {
$file = $argv[1]; $file = $argv[1];
list(, $user) = explode('/', $file); list(, $user) = explode('/', $file);
OCP\JSON::checkUserExists($owner);
OC_Util::setupFS($user); OC_Util::setupFS($user);
$view = new \OC\Files\View(''); $view = new \OC\Files\View('');
/** /**

View File

@ -2,11 +2,15 @@
<info> <info>
<id>files_encryption</id> <id>files_encryption</id>
<name>Encryption</name> <name>Encryption</name>
<description>The new ownCloud 5 files encryption system. After the app was enabled you need to re-login to initialize your encryption keys.</description> <description>The ownCloud files encryption system provides server side-encryption. After the app was enabled you need to re-login to initialize your encryption keys.</description>
<licence>AGPL</licence> <licence>AGPL</licence>
<author>Sam Tuke, Bjoern Schiessle, Florin Peter</author> <author>Sam Tuke, Bjoern Schiessle, Florin Peter</author>
<require>4</require> <require>4</require>
<shipped>true</shipped> <shipped>true</shipped>
<documentation>
<user>http://doc.owncloud.org/server/6.0/user_manual/files/encryption.html</user>
<admin>http://doc.owncloud.org/server/6.0/admin_manual/configuration/configuration_encryption.html</admin>
</documentation>
<rememberlogin>false</rememberlogin> <rememberlogin>false</rememberlogin>
<types> <types>
<filesystem/> <filesystem/>

View File

@ -32,6 +32,8 @@ class Hooks {
// file for which we want to rename the keys after the rename operation was successful // file for which we want to rename the keys after the rename operation was successful
private static $renamedFiles = array(); 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 * @brief Startup encryption backend upon user login
@ -78,8 +80,15 @@ class Hooks {
// Check if first-run file migration has already been performed // Check if first-run file migration has already been performed
$ready = false; $ready = false;
if ($util->getMigrationStatus() === Util::MIGRATION_OPEN) { $migrationStatus = $util->getMigrationStatus();
if ($migrationStatus === Util::MIGRATION_OPEN) {
$ready = $util->beginMigration(); $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 // If migration not yet done
@ -630,4 +639,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);
}
} }

View File

@ -1,6 +1,41 @@
<?php <?php
$TRANSLATIONS = array( $TRANSLATIONS = array(
"Recovery key successfully enabled" => "Kunci pemulihan berhasil diaktifkan",
"Could not enable recovery key. Please check your recovery key password!" => "Tidak dapat mengaktifkan kunci pemulihan. Silakan periksa sandi kunci pemulihan Anda!",
"Recovery key successfully disabled" => "Kunci pemulihan berhasil dinonaktifkan",
"Could not disable recovery key. Please check your recovery key password!" => "Tidak dapat menonaktifkan kunci pemulihan. Silakan periksa sandi kunci pemulihan Anda!",
"Password successfully changed." => "Sandi berhasil diubah",
"Could not change the password. Maybe the old password was not correct." => "Tidak dapat mengubah sandi. Kemungkinan sandi lama yang dimasukkan salah.",
"Private key password successfully updated." => "Sandi kunci privat berhasil diperbarui.",
"Could not update the private key password. Maybe the old password was not correct." => "Tidak dapat memperbarui sandi kunci privat. Kemungkinan sandi lama yang Anda masukkan salah.",
"Can not decrypt this file, probably this is a shared file. Please ask the file owner to reshare the file with you." => "Tidak dapat mendekripsi berkas ini, mungkin ini adalah berkas bersama. Silakan meminta pemilik berkas ini untuk membagikan kembali dengan Anda.",
"Unknown error please check your system settings or contact your administrator" => "Kesalahan tak dikenal, silakan periksa pengaturan sistem Anda atau hubungi admin.",
"Missing requirements." => "Persyaratan yang hilang.",
"Following users are not set up for encryption:" => "Pengguna berikut belum diatur untuk enkripsi:",
"Initial encryption started... This can take some time. Please wait." => "Inisial enskripsi dijalankan... Ini dapat memakan waktu. Silakan tunggu.",
"Saving..." => "Menyimpan...", "Saving..." => "Menyimpan...",
"Encryption" => "Enkripsi" "Go directly to your " => "Langsung ke anda",
"personal settings" => "pengaturan pribadi",
"Encryption" => "Enkripsi",
"Enable recovery key (allow to recover users files in case of password loss):" => "Aktifkan kunci pemulihan (memungkinkan pengguna untuk memulihkan berkas dalam kasus kehilangan sandi):",
"Recovery key password" => "Sandi kunci pemulihan",
"Repeat Recovery key password" => "Ulangi sandi kunci Pemulihan",
"Enabled" => "Diaktifkan",
"Disabled" => "Dinonaktifkan",
"Change recovery key password:" => "Ubah sandi kunci pemulihan:",
"Old Recovery key password" => "Sandi kunci Pemulihan Lama",
"New Recovery key password" => "Sandi kunci Pemulihan Baru",
"Repeat New Recovery key password" => "Ulangi sandi kunci Pemulihan baru",
"Change Password" => "Ubah sandi",
"Your private key password no longer match your log-in password:" => "Sandi kunci privat Anda tidak lagi cocok dengan sandi masuk:",
"Set your old private key password to your current log-in password." => "Atur sandi kunci privat lama Anda sebagai sandi masuk Anda saat ini.",
" If you don't remember your old password you can ask your administrator to recover your files." => "Jika Anda tidak ingat sandi lama, Anda dapat meminta administrator Anda untuk memulihkan berkas.",
"Old log-in password" => "Sandi masuk yang lama",
"Current log-in password" => "Sandi masuk saat ini",
"Update Private Key Password" => "Perbarui Sandi Kunci Privat",
"Enable password recovery:" => "Aktifkan sandi pemulihan:",
"Enabling this option will allow you to reobtain access to your encrypted files in case of password loss" => "Mengaktifkan opsi ini memungkinkan Anda untuk mendapatkan kembali akses ke berkas terenkripsi Anda dalam kasus kehilangan sandi",
"File recovery settings updated" => "Pengaturan pemulihan berkas diperbarui",
"Could not update file recovery" => "Tidak dapat memperbarui pemulihan berkas"
); );
$PLURAL_FORMS = "nplurals=1; plural=0;"; $PLURAL_FORMS = "nplurals=1; plural=0;";

View File

@ -63,6 +63,8 @@ class Helper {
\OCP\Util::connectHook('OC_Filesystem', 'rename', 'OCA\Encryption\Hooks', 'preRename'); \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_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');
} }
/** /**

View File

@ -214,15 +214,24 @@ class Keymanager {
* *
* @param \OC_FilesystemView $view * @param \OC_FilesystemView $view
* @param string $path path of the file the key belongs to * @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 * @return bool Outcome of unlink operation
* @note $path must be relative to data/user/files. e.g. mydoc.txt NOT * @note $path must be relative to data/user/files. e.g. mydoc.txt NOT
* /data/admin/files/mydoc.txt * /data/admin/files/mydoc.txt
*/ */
public static function deleteFileKey(\OC_FilesystemView $view, $path) { public static function deleteFileKey($view, $path, $userId=null) {
$trimmed = ltrim($path, '/'); $trimmed = ltrim($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); $userId = Helper::getUser($path);
}
$util = new Util($view, $userId); $util = new Util($view, $userId);
if($util->isSystemWideMountPoint($path)) { if($util->isSystemWideMountPoint($path)) {
@ -402,7 +411,15 @@ class Keymanager {
* @param string $userId owner of the file * @param string $userId owner of the file
* @param string $filePath path to the file, relative to the owners file dir * @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); $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); $view->unlink($baseDir . $filePath);
} else { } else {
$localKeyPath = $view->getLocalFile($baseDir . $filePath); $parentDir = dirname($baseDir . $filePath);
$escapedPath = Helper::escapeGlobPattern($localKeyPath); $filename = pathinfo($filePath, PATHINFO_BASENAME);
$matches = glob($escapedPath . '*.shareKey'); foreach($view->getDirectoryContent($parentDir) as $content) {
foreach ($matches as $ma) { $path = $content['path'];
$result = unlink($ma); if (self::getFilenameFromShareKey($content['name']) === $filename) {
if (!$result) { $view->unlink('/' . $userId . '/' . $path);
\OCP\Util::writeLog('Encryption library',
'Keyfile or shareKey could not be deleted for file "' . $filePath . '"', \OCP\Util::ERROR);
} }
} }
} }
@ -523,4 +538,20 @@ class Keymanager {
return $targetPath; 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;
}
} }

View File

@ -37,6 +37,7 @@ namespace OCA\Encryption;
class Proxy extends \OC_FileProxy { class Proxy extends \OC_FileProxy {
private static $blackList = null; //mimetypes blacklisted from encryption private static $blackList = null; //mimetypes blacklisted from encryption
private static $unencryptedSizes = array(); // remember unencrypted size
/** /**
* Check if a file requires encryption * Check if a file requires encryption
@ -114,13 +115,11 @@ class Proxy extends \OC_FileProxy {
// get encrypted content // get encrypted content
$data = $view->file_get_contents($tmpPath); $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); $tmpFileInfo = $view->getFileInfo($tmpPath);
$fileInfo = $view->getFileInfo($path); if ( isset($tmpFileInfo['size']) ) {
if (is_array($fileInfo) && is_array($tmpFileInfo)) { self::$unencryptedSizes[\OC_Filesystem::normalizePath($path)] = $tmpFileInfo['size'];
$fileInfo['encrypted'] = true;
$fileInfo['unencrypted_size'] = $tmpFileInfo['size'];
$view->putFileInfo($path, $fileInfo);
} }
// remove our temp file // remove our temp file
@ -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 $path Path of file from which has been read
* @param string $data Data that has been read from file * @param string $data Data that has been read from file
@ -186,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 * @param $path
* @return bool * @return bool
@ -255,8 +231,8 @@ class Proxy extends \OC_FileProxy {
// split the path parts // split the path parts
$pathParts = explode('/', $path); $pathParts = explode('/', $path);
// FIXME: handling for /userId/cache used by webdav for chunking. The cache chunks are NOT encrypted // don't try to encrypt/decrypt cache chunks or files in the trash bin
if (isset($pathParts[2]) && $pathParts[2] === 'cache') { if (isset($pathParts[2]) && ($pathParts[2] === 'cache' || $pathParts[2] === 'files_trashbin')) {
return $result; return $result;
} }

View File

@ -2,9 +2,10 @@
/** /**
* ownCloud * ownCloud
* *
* @author Sam Tuke, Frank Karlitschek * @author Sam Tuke, Frank Karlitschek, Bjoern Schiessle
* @copyright 2012 Sam Tuke <samtuke@owncloud.com>, * @copyright 2012 Sam Tuke <samtuke@owncloud.com>,
* Frank Karlitschek <frank@owncloud.org> * Frank Karlitschek <frank@owncloud.org>,
* Bjoern Schiessle <schiessle@owncloud.com>
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
@ -56,7 +57,7 @@ class Util {
* @param $userId * @param $userId
* @param bool $client * @param bool $client
*/ */
public function __construct(\OC_FilesystemView $view, $userId, $client = false) { public function __construct($view, $userId, $client = false) {
$this->view = $view; $this->view = $view;
$this->client = $client; $this->client = $client;
@ -1360,59 +1361,32 @@ class Util {
} }
} }
/** /**
* @brief go recursively through a dir and collect all files and sub files. * @brief go recursively through a dir and collect all files and sub files.
* @param string $dir relative to the users files folder * @param string $dir relative to the users files folder
* @return array with list of files relative to the users files folder * @return array with list of files relative to the users files folder
*/ */
public function getAllFiles($dir) { public function getAllFiles($dir) {
$result = array(); $result = array();
$dirList = array($dir);
while ($dirList) {
$dir = array_pop($dirList);
$content = $this->view->getDirectoryContent(\OC\Files\Filesystem::normalizePath( $content = $this->view->getDirectoryContent(\OC\Files\Filesystem::normalizePath(
$this->userFilesDir . '/' . $dir)); $this->userFilesDir . '/' . $dir));
// handling for re shared folders
$pathSplit = explode('/', $dir);
foreach ($content as $c) { foreach ($content as $c) {
$usersPath = isset($c['usersPath']) ? $c['usersPath'] : $c['path'];
$sharedPart = $pathSplit[sizeof($pathSplit) - 1];
$targetPathSplit = array_reverse(explode('/', $c['path']));
$path = '';
// rebuild path
foreach ($targetPathSplit as $pathPart) {
if ($pathPart !== $sharedPart) {
$path = '/' . $pathPart . $path;
} else {
break;
}
}
$path = $dir . $path;
if ($c['type'] === 'dir') { if ($c['type'] === 'dir') {
$dirList[] = substr($usersPath, strlen("files"));
$result = array_merge($result, $this->getAllFiles($path));
} else { } else {
$result[] = substr($usersPath, strlen("files"));
$result[] = $path;
} }
} }
}
return $result; return $result;
} }
/** /**

View File

@ -155,7 +155,7 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
*/ */
function testSymmetricStreamEncryptShortFileContent() { function testSymmetricStreamEncryptShortFileContent() {
$filename = 'tmp-' . time() . '.test'; $filename = 'tmp-' . uniqid() . '.test';
$util = new Encryption\Util(new \OC_FilesystemView(), $this->userId); $util = new Encryption\Util(new \OC_FilesystemView(), $this->userId);
@ -214,7 +214,7 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
function testSymmetricStreamEncryptLongFileContent() { function testSymmetricStreamEncryptLongFileContent() {
// Generate a a random filename // Generate a a random filename
$filename = 'tmp-' . time() . '.test'; $filename = 'tmp-' . uniqid() . '.test';
$util = new Encryption\Util(new \OC_FilesystemView(), $this->userId); $util = new Encryption\Util(new \OC_FilesystemView(), $this->userId);
@ -297,7 +297,7 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
*/ */
function testSymmetricStreamDecryptShortFileContent() { function testSymmetricStreamDecryptShortFileContent() {
$filename = 'tmp-' . time(); $filename = 'tmp-' . uniqid();
// Save long data as encrypted file using stream wrapper // Save long data as encrypted file using stream wrapper
$cryptedFile = file_put_contents('crypt:///'. $this->userId . '/files/' . $filename, $this->dataShort); $cryptedFile = file_put_contents('crypt:///'. $this->userId . '/files/' . $filename, $this->dataShort);
@ -327,7 +327,7 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
*/ */
function testSymmetricStreamDecryptLongFileContent() { function testSymmetricStreamDecryptLongFileContent() {
$filename = 'tmp-' . time(); $filename = 'tmp-' . uniqid();
// Save long data as encrypted file using stream wrapper // Save long data as encrypted file using stream wrapper
$cryptedFile = file_put_contents('crypt:///' . $this->userId . '/files/' . $filename, $this->dataLong); $cryptedFile = file_put_contents('crypt:///' . $this->userId . '/files/' . $filename, $this->dataLong);
@ -418,7 +418,7 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
*/ */
function testRenameFile() { function testRenameFile() {
$filename = 'tmp-' . time(); $filename = 'tmp-' . uniqid();
// Save long data as encrypted file using stream wrapper // Save long data as encrypted file using stream wrapper
$cryptedFile = file_put_contents('crypt:///' . $this->userId . '/files/' . $filename, $this->dataLong); $cryptedFile = file_put_contents('crypt:///' . $this->userId . '/files/' . $filename, $this->dataLong);
@ -431,7 +431,7 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
$this->assertEquals($this->dataLong, $decrypt); $this->assertEquals($this->dataLong, $decrypt);
$newFilename = 'tmp-new-' . time(); $newFilename = 'tmp-new-' . uniqid();
$view = new \OC\Files\View('/' . $this->userId . '/files'); $view = new \OC\Files\View('/' . $this->userId . '/files');
$view->rename($filename, $newFilename); $view->rename($filename, $newFilename);
@ -449,7 +449,7 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
*/ */
function testMoveFileIntoFolder() { function testMoveFileIntoFolder() {
$filename = 'tmp-' . time(); $filename = 'tmp-' . uniqid();
// Save long data as encrypted file using stream wrapper // Save long data as encrypted file using stream wrapper
$cryptedFile = file_put_contents('crypt:///' . $this->userId . '/files/' . $filename, $this->dataLong); $cryptedFile = file_put_contents('crypt:///' . $this->userId . '/files/' . $filename, $this->dataLong);
@ -462,8 +462,8 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
$this->assertEquals($this->dataLong, $decrypt); $this->assertEquals($this->dataLong, $decrypt);
$newFolder = '/newfolder' . time(); $newFolder = '/newfolder' . uniqid();
$newFilename = 'tmp-new-' . time(); $newFilename = 'tmp-new-' . uniqid();
$view = new \OC\Files\View('/' . $this->userId . '/files'); $view = new \OC\Files\View('/' . $this->userId . '/files');
$view->mkdir($newFolder); $view->mkdir($newFolder);
$view->rename($filename, $newFolder . '/' . $newFilename); $view->rename($filename, $newFolder . '/' . $newFilename);
@ -484,8 +484,8 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
$view = new \OC\Files\View('/' . $this->userId . '/files'); $view = new \OC\Files\View('/' . $this->userId . '/files');
$filename = '/tmp-' . time(); $filename = '/tmp-' . uniqid();
$folder = '/folder' . time(); $folder = '/folder' . uniqid();
$view->mkdir($folder); $view->mkdir($folder);
@ -500,7 +500,7 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
$this->assertEquals($this->dataLong, $decrypt); $this->assertEquals($this->dataLong, $decrypt);
$newFolder = '/newfolder/subfolder' . time(); $newFolder = '/newfolder/subfolder' . uniqid();
$view->mkdir('/newfolder'); $view->mkdir('/newfolder');
$view->rename($folder, $newFolder); $view->rename($folder, $newFolder);
@ -519,7 +519,7 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
* @medium * @medium
*/ */
function testChangePassphrase() { function testChangePassphrase() {
$filename = 'tmp-' . time(); $filename = 'tmp-' . uniqid();
// Save long data as encrypted file using stream wrapper // Save long data as encrypted file using stream wrapper
$cryptedFile = file_put_contents('crypt:///' . $this->userId . '/files/' . $filename, $this->dataLong); $cryptedFile = file_put_contents('crypt:///' . $this->userId . '/files/' . $filename, $this->dataLong);
@ -557,7 +557,7 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
*/ */
function testViewFilePutAndGetContents() { function testViewFilePutAndGetContents() {
$filename = '/tmp-' . time(); $filename = '/tmp-' . uniqid();
$view = new \OC\Files\View('/' . $this->userId . '/files'); $view = new \OC\Files\View('/' . $this->userId . '/files');
// Save short data as encrypted file using stream wrapper // Save short data as encrypted file using stream wrapper
@ -590,7 +590,7 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
* @large * @large
*/ */
function testTouchExistingFile() { function testTouchExistingFile() {
$filename = '/tmp-' . time(); $filename = '/tmp-' . uniqid();
$view = new \OC\Files\View('/' . $this->userId . '/files'); $view = new \OC\Files\View('/' . $this->userId . '/files');
// Save short data as encrypted file using stream wrapper // Save short data as encrypted file using stream wrapper
@ -614,7 +614,7 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
* @medium * @medium
*/ */
function testTouchFile() { function testTouchFile() {
$filename = '/tmp-' . time(); $filename = '/tmp-' . uniqid();
$view = new \OC\Files\View('/' . $this->userId . '/files'); $view = new \OC\Files\View('/' . $this->userId . '/files');
$view->touch($filename); $view->touch($filename);
@ -638,7 +638,7 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
* @medium * @medium
*/ */
function testFopenFile() { function testFopenFile() {
$filename = '/tmp-' . time(); $filename = '/tmp-' . uniqid();
$view = new \OC\Files\View('/' . $this->userId . '/files'); $view = new \OC\Files\View('/' . $this->userId . '/files');
// Save short data as encrypted file using stream wrapper // Save short data as encrypted file using stream wrapper

View File

@ -0,0 +1,271 @@
<?php
/**
* ownCloud
*
* @author Bjoern Schiessle
* @copyright 2014 Bjoern Schiessle <schiessle@owncloud.com>
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
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-encryption-hooks-user1";
const TEST_ENCRYPTION_HOOKS_USER2 = "test-encryption-hooks-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');
}
}
}

View File

@ -136,6 +136,17 @@ class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase {
$this->assertArrayHasKey('key', $sslInfo); $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 * @medium
*/ */
@ -143,7 +154,7 @@ class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase {
$key = $this->randomKey; $key = $this->randomKey;
$file = 'unittest-' . time() . '.txt'; $file = 'unittest-' . uniqid() . '.txt';
$util = new Encryption\Util($this->view, $this->userId); $util = new Encryption\Util($this->view, $this->userId);
@ -196,7 +207,7 @@ class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase {
function testRecursiveDelShareKeys() { function testRecursiveDelShareKeys() {
// generate filename // generate filename
$filename = '/tmp-' . time() . '.txt'; $filename = '/tmp-' . uniqid() . '.txt';
// create folder structure // create folder structure
$this->view->mkdir('/'.Test_Encryption_Keymanager::TEST_USER.'/files/folder1'); $this->view->mkdir('/'.Test_Encryption_Keymanager::TEST_USER.'/files/folder1');
@ -234,3 +245,12 @@ class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase {
\OC_FileProxy::$enabled = $proxyStatus; \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);
}
}

View File

@ -80,7 +80,7 @@ class Test_Encryption_Proxy extends \PHPUnit_Framework_TestCase {
// init short data // init short data
$this->data = 'hats'; $this->data = 'hats';
$this->filename = 'enc_proxy_tests-' . time() . '.txt'; $this->filename = 'enc_proxy_tests-' . uniqid() . '.txt';
} }
@ -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');
}
}
} }

View File

@ -194,8 +194,9 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
. $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '.shareKey')); . $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '.shareKey'));
// cleanup // cleanup
$this->view->unlink( $this->view->chroot('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/');
'/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->filename); $this->view->unlink($this->filename);
$this->view->chroot('/');
// check if share key not exists // check if share key not exists
$this->assertFalse($this->view->file_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')); . $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '.shareKey'));
// cleanup // cleanup
$this->view->unlink( $this->view->chroot('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/');
'/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->filename); $this->view->unlink($this->filename);
$this->view->chroot('/');
// check if share key not exists // check if share key not exists
$this->assertFalse($this->view->file_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')); . $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '.shareKey'));
// cleanup // 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 // check if share key not exists
$this->assertFalse($this->view->file_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')); . $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '.shareKey'));
// cleanup // cleanup
$this->view->unlink( $this->view->chroot('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files');
'/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files' . $this->folder1 . $this->subfolder $this->view->unlink($this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename);
. $this->subsubfolder . '/' . $this->filename); $this->view->chroot('/');
// check if share key not exists // check if share key not exists
$this->assertFalse($this->view->file_exists( $this->assertFalse($this->view->file_exists(
@ -559,7 +563,9 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
. $this->filename . '.' . $publicShareKeyId . '.shareKey')); . $this->filename . '.' . $publicShareKeyId . '.shareKey'));
// cleanup // 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 // check if share key not exists
$this->assertFalse($this->view->file_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')); . $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER4 . '.shareKey'));
// cleanup // 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 // check if share key not exists
$this->assertFalse($this->view->file_exists( $this->assertFalse($this->view->file_exists(
@ -731,8 +739,10 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
. $this->filename . '.' . $recoveryKeyId . '.shareKey')); . $this->filename . '.' . $recoveryKeyId . '.shareKey'));
// cleanup // 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('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->folder1); $this->view->unlink($this->filename);
$this->view->unlink($this->folder1);
$this->view->chroot('/');
// check if share key for recovery not exists // check if share key for recovery not exists
$this->assertFalse($this->view->file_exists( $this->assertFalse($this->view->file_exists(
@ -828,8 +838,10 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
$this->assertEquals($this->dataShort, $retrievedCryptedFile2); $this->assertEquals($this->dataShort, $retrievedCryptedFile2);
// cleanup // cleanup
$this->view->unlink('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files/' . $this->folder1); $this->view->chroot('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files/');
$this->view->unlink('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files/' . $this->filename); $this->view->unlink($this->folder1);
$this->view->unlink($this->filename);
$this->view->chroot('/');
// check if share key for user and recovery exists // check if share key for user and recovery exists
$this->assertFalse($this->view->file_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')); . $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3 . '.shareKey'));
// cleanup // 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('/');
} }
} }

View File

@ -99,7 +99,7 @@ class Test_Encryption_Stream extends \PHPUnit_Framework_TestCase {
} }
function testStreamOptions() { function testStreamOptions() {
$filename = '/tmp-' . time(); $filename = '/tmp-' . uniqid();
$view = new \OC\Files\View('/' . $this->userId . '/files'); $view = new \OC\Files\View('/' . $this->userId . '/files');
// Save short data as encrypted file using stream wrapper // Save short data as encrypted file using stream wrapper
@ -122,7 +122,7 @@ class Test_Encryption_Stream extends \PHPUnit_Framework_TestCase {
} }
function testStreamSetBlocking() { function testStreamSetBlocking() {
$filename = '/tmp-' . time(); $filename = '/tmp-' . uniqid();
$view = new \OC\Files\View('/' . $this->userId . '/files'); $view = new \OC\Files\View('/' . $this->userId . '/files');
// Save short data as encrypted file using stream wrapper // Save short data as encrypted file using stream wrapper
@ -144,7 +144,7 @@ class Test_Encryption_Stream extends \PHPUnit_Framework_TestCase {
* @medium * @medium
*/ */
function testStreamSetTimeout() { function testStreamSetTimeout() {
$filename = '/tmp-' . time(); $filename = '/tmp-' . uniqid();
$view = new \OC\Files\View('/' . $this->userId . '/files'); $view = new \OC\Files\View('/' . $this->userId . '/files');
// Save short data as encrypted file using stream wrapper // Save short data as encrypted file using stream wrapper
@ -163,7 +163,7 @@ class Test_Encryption_Stream extends \PHPUnit_Framework_TestCase {
} }
function testStreamSetWriteBuffer() { function testStreamSetWriteBuffer() {
$filename = '/tmp-' . time(); $filename = '/tmp-' . uniqid();
$view = new \OC\Files\View('/' . $this->userId . '/files'); $view = new \OC\Files\View('/' . $this->userId . '/files');
// Save short data as encrypted file using stream wrapper // Save short data as encrypted file using stream wrapper
@ -187,9 +187,9 @@ class Test_Encryption_Stream extends \PHPUnit_Framework_TestCase {
*/ */
function testStreamFromLocalFile() { function testStreamFromLocalFile() {
$filename = '/' . $this->userId . '/files/' . 'tmp-' . time().'.txt'; $filename = '/' . $this->userId . '/files/' . 'tmp-' . uniqid().'.txt';
$tmpFilename = "/tmp/" . time() . ".txt"; $tmpFilename = "/tmp/" . uniqid() . ".txt";
// write an encrypted file // write an encrypted file
$cryptedFile = $this->view->file_put_contents($filename, $this->dataShort); $cryptedFile = $this->view->file_put_contents($filename, $this->dataShort);

View File

@ -119,7 +119,7 @@ class Test_Encryption_Trashbin extends \PHPUnit_Framework_TestCase {
function testDeleteFile() { function testDeleteFile() {
// generate filename // generate filename
$filename = 'tmp-' . time() . '.txt'; $filename = 'tmp-' . uniqid() . '.txt';
// save file with content // save file with content
$cryptedFile = file_put_contents('crypt:///' .\Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1. '/files/'. $filename, $this->dataShort); $cryptedFile = file_put_contents('crypt:///' .\Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1. '/files/'. $filename, $this->dataShort);
@ -223,7 +223,7 @@ class Test_Encryption_Trashbin extends \PHPUnit_Framework_TestCase {
function testPermanentDeleteFile() { function testPermanentDeleteFile() {
// generate filename // generate filename
$filename = 'tmp-' . time() . '.txt'; $filename = 'tmp-' . uniqid() . '.txt';
// save file with content // save file with content
$cryptedFile = file_put_contents('crypt:///' .$this->userId. '/files/' . $filename, $this->dataShort); $cryptedFile = file_put_contents('crypt:///' .$this->userId. '/files/' . $filename, $this->dataShort);

View File

@ -142,8 +142,8 @@ class Test_Encryption_Util extends \PHPUnit_Framework_TestCase {
self::loginHelper($this->userId); self::loginHelper($this->userId);
$unencryptedFile = '/tmpUnencrypted-' . time() . '.txt'; $unencryptedFile = '/tmpUnencrypted-' . uniqid() . '.txt';
$encryptedFile = '/tmpEncrypted-' . time() . '.txt'; $encryptedFile = '/tmpEncrypted-' . uniqid() . '.txt';
// Disable encryption proxy to write a unencrypted file // Disable encryption proxy to write a unencrypted file
$proxyStatus = \OC_FileProxy::$enabled; $proxyStatus = \OC_FileProxy::$enabled;
@ -254,7 +254,7 @@ class Test_Encryption_Util extends \PHPUnit_Framework_TestCase {
\OC_User::setUserId(\Test_Encryption_Util::TEST_ENCRYPTION_UTIL_USER1); \OC_User::setUserId(\Test_Encryption_Util::TEST_ENCRYPTION_UTIL_USER1);
$filename = '/tmp-' . time() . '.test'; $filename = '/tmp-' . uniqid() . '.test';
// Disable encryption proxy to prevent recursive calls // Disable encryption proxy to prevent recursive calls
$proxyStatus = \OC_FileProxy::$enabled; $proxyStatus = \OC_FileProxy::$enabled;
@ -282,7 +282,7 @@ class Test_Encryption_Util extends \PHPUnit_Framework_TestCase {
function testGetFileSize() { function testGetFileSize() {
\Test_Encryption_Util::loginHelper(\Test_Encryption_Util::TEST_ENCRYPTION_UTIL_USER1); \Test_Encryption_Util::loginHelper(\Test_Encryption_Util::TEST_ENCRYPTION_UTIL_USER1);
$filename = 'tmp-' . time(); $filename = 'tmp-' . uniqid();
$externalFilename = '/' . $this->userId . '/files/' . $filename; $externalFilename = '/' . $this->userId . '/files/' . $filename;
// Test for 0 byte files // Test for 0 byte files
@ -318,7 +318,7 @@ class Test_Encryption_Util extends \PHPUnit_Framework_TestCase {
function testEncryptAll() { function testEncryptAll() {
$filename = "/encryptAll" . time() . ".txt"; $filename = "/encryptAll" . uniqid() . ".txt";
$util = new Encryption\Util($this->view, $this->userId); $util = new Encryption\Util($this->view, $this->userId);
// disable encryption to upload a unencrypted file // disable encryption to upload a unencrypted file
@ -350,7 +350,7 @@ class Test_Encryption_Util extends \PHPUnit_Framework_TestCase {
function testDecryptAll() { function testDecryptAll() {
$filename = "/decryptAll" . time() . ".txt"; $filename = "/decryptAll" . uniqid() . ".txt";
$util = new Encryption\Util($this->view, $this->userId); $util = new Encryption\Util($this->view, $this->userId);
$this->view->file_put_contents($this->userId . '/files/' . $filename, $this->dataShort); $this->view->file_put_contents($this->userId . '/files/' . $filename, $this->dataShort);

View File

@ -113,7 +113,7 @@ class Test_Encryption_Webdav extends \PHPUnit_Framework_TestCase {
function testWebdavPUT() { function testWebdavPUT() {
// generate filename // generate filename
$filename = '/tmp-' . time() . '.txt'; $filename = '/tmp-' . uniqid() . '.txt';
// set server vars // set server vars
$_SERVER['REQUEST_METHOD'] = 'OPTIONS'; $_SERVER['REQUEST_METHOD'] = 'OPTIONS';

View File

@ -1,3 +1,5 @@
phpseclib Lead Developer: TerraFrost (Jim Wigginton) phpseclib Lead Developer: TerraFrost (Jim Wigginton)
phpseclib Developers: monnerat (Patrick Monnerat) phpseclib Developers: monnerat (Patrick Monnerat)
bantu (Andreas Fischer)
petrich (Hans-Jürgen Petrich)

View File

@ -4,9 +4,9 @@
MIT-licensed pure-PHP implementations of an arbitrary-precision integer MIT-licensed pure-PHP implementations of an arbitrary-precision integer
arithmetic library, fully PKCS#1 (v2.1) compliant RSA, DES, 3DES, RC4, Rijndael, 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) * [Browse Git](https://github.com/phpseclib/phpseclib)
* [Documentation](http://phpseclib.sourceforge.net/) * [Documentation](http://phpseclib.sourceforge.net/)
* [Support](http://www.frostjedi.com/phpbb/viewforum.php?f=46) * [Support](http://www.frostjedi.com/phpbb/viewforum.php?f=46)

View File

@ -43,6 +43,14 @@
"File": "phpseclib/", "File": "phpseclib/",
"Math": "phpseclib/", "Math": "phpseclib/",
"Net": "phpseclib/" "Net": "phpseclib/"
},
"files": [
"phpseclib/Crypt/Random.php"
]
},
"extra": {
"branch-alias": {
"dev-master": "0.3-dev"
} }
} }
} }

View File

@ -4,13 +4,13 @@
/** /**
* Pure-PHP implementation of AES. * 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 * PHP versions 4 and 5
* *
* If {@link Crypt_AES::setKeyLength() setKeyLength()} isn't called, it'll be calculated from * 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 * {@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. * 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 * Since Crypt_AES extends Crypt_Rijndael, some functions are available to be called that, in the context of AES, don't
@ -59,7 +59,6 @@
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @copyright MMVIII Jim Wigginton * @copyright MMVIII Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @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 * @link http://phpseclib.sourceforge.net
*/ */
@ -67,7 +66,7 @@
* Include Crypt_Rijndael * Include Crypt_Rijndael
*/ */
if (!class_exists('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 * @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. * Encrypt / decrypt using the Electronic Code Book mode.
* *
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29 * @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. * Encrypt / decrypt using the Code Book Chaining mode.
* *
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29 * @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. * Encrypt / decrypt using the Cipher Feedback mode.
* *
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29 * @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. * Encrypt / decrypt using the Cipher Feedback mode.
* *
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29 * @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 * Toggles the internal implementation
*/ */
define('CRYPT_AES_MODE_INTERNAL', 1); define('CRYPT_AES_MODE_INTERNAL', CRYPT_MODE_INTERNAL);
/** /**
* Toggles the mcrypt implementation * 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 { 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. * @see Crypt_Base::const_namespace
* Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
*
* @see Crypt_AES::encrypt()
* @var String * @var String
* @access private * @access private
*/ */
var $enmcrypt; var $const_namespace = 'AES';
/**
* 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
);
/** /**
* Default Constructor. * Default Constructor.
* *
* Determines whether or not the mcrypt extension should be used. $mode should only, at present, be * Determines whether or not the mcrypt extension should be used.
* CRYPT_AES_MODE_ECB or CRYPT_AES_MODE_CBC. If not explictly set, CRYPT_AES_MODE_CBC will 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 * @param optional Integer $mode
* @return Crypt_AES
* @access public * @access public
*/ */
function Crypt_AES($mode = CRYPT_AES_MODE_CBC) function Crypt_AES($mode = CRYPT_AES_MODE_CBC)
{ {
if ( !defined('CRYPT_AES_MODE') ) { parent::Crypt_Rijndael($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;
} }
/** /**
@ -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. * Since Crypt_AES extends Crypt_Rijndael, this function is, technically, available, but it doesn't do anything.
* *
* @see Crypt_Rijndael::setBlockLength()
* @access public * @access public
* @param Integer $length * @param Integer $length
*/ */
@ -336,610 +182,6 @@ class Crypt_AES extends Crypt_Rijndael {
{ {
return; 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: // vim: ts=4:sw=4:et:

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,678 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* Pure-PHP implementation of Blowfish.
*
* Uses mcrypt, if available, and an internal implementation, otherwise.
*
* PHP versions 4 and 5
*
* Useful resources are as follows:
*
* - {@link http://en.wikipedia.org/wiki/Blowfish_(cipher) Wikipedia description of Blowfish}
*
* Here's a short example of how to use this library:
* <code>
* <?php
* include('Crypt/Blowfish.php');
*
* $blowfish = new Crypt_Blowfish();
*
* $blowfish->setKey('12345678901234567890123456789012');
*
* $plaintext = str_repeat('a', 1024);
*
* echo $blowfish->decrypt($blowfish->encrypt($plaintext));
* ?>
* </code>
*
* 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 <terrafrost@php.net>
* @author Hans-Juergen Petrich <petrich@tronic-media.com>
* @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 <terrafrost@php.net>
* @author Hans-Juergen Petrich <petrich@tronic-media.com>
* @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:

File diff suppressed because it is too large Load Diff

View File

@ -52,7 +52,6 @@
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @copyright MMVII Jim Wigginton * @copyright MMVII Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @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 * @link http://phpseclib.sourceforge.net
*/ */
@ -83,6 +82,15 @@ define('CRYPT_HASH_MODE_HASH', 3);
* @package Crypt_Hash * @package Crypt_Hash
*/ */
class 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) * Byte-length of compression blocks / key (Internal HMAC)
* *
@ -168,13 +176,26 @@ class Crypt_Hash {
* Keys can be of any length. * Keys can be of any length.
* *
* @access public * @access public
* @param String $key * @param optional String $key
*/ */
function setKey($key = false) function setKey($key = false)
{ {
$this->key = $key; $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. * Sets the hash function.
* *
@ -183,7 +204,7 @@ class Crypt_Hash {
*/ */
function setHash($hash) function setHash($hash)
{ {
$hash = strtolower($hash); $this->hashParam = $hash = strtolower($hash);
switch ($hash) { switch ($hash) {
case 'md5-96': case 'md5-96':
case 'sha1-96': case 'sha1-96':
@ -350,7 +371,7 @@ class Crypt_Hash {
* Wrapper for MD5 * Wrapper for MD5
* *
* @access private * @access private
* @param String $text * @param String $m
*/ */
function _md5($m) function _md5($m)
{ {
@ -361,7 +382,7 @@ class Crypt_Hash {
* Wrapper for SHA1 * Wrapper for SHA1
* *
* @access private * @access private
* @param String $text * @param String $m
*/ */
function _sha1($m) function _sha1($m)
{ {
@ -374,7 +395,7 @@ class Crypt_Hash {
* See {@link http://tools.ietf.org/html/rfc1319 RFC1319}. * See {@link http://tools.ietf.org/html/rfc1319 RFC1319}.
* *
* @access private * @access private
* @param String $text * @param String $m
*/ */
function _md2($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}. * 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 * @access private
* @param String $text * @param String $m
*/ */
function _sha256($m) function _sha256($m)
{ {
@ -555,7 +576,7 @@ class Crypt_Hash {
* Pure-PHP implementation of SHA384 and SHA512 * Pure-PHP implementation of SHA384 and SHA512
* *
* @access private * @access private
* @param String $text * @param String $m
*/ */
function _sha512($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 * _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. * possibility of overflow exists, care has to be taken. Math_BigInteger() could be used but this should be faster.
* *
* @param String $string * @param Integer $...
* @param optional Integer $index * @return Integer
* @return String
* @see _sha256() * @see _sha256()
* @access private * @access private
*/ */

View File

@ -0,0 +1,656 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* Pure-PHP implementation of RC2.
*
* Uses mcrypt, if available, and an internal implementation, otherwise.
*
* PHP versions 4 and 5
*
* Useful resources are as follows:
*
* - {@link http://tools.ietf.org/html/rfc2268}
*
* Here's a short example of how to use this library:
* <code>
* <?php
* include('Crypt/RC2.php');
*
* $rc2 = new Crypt_RC2();
*
* $rc2->setKey('abcdefgh');
*
* $plaintext = str_repeat('a', 1024);
*
* echo $rc2->decrypt($rc2->encrypt($plaintext));
* ?>
* </code>
*
* 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 <pm@datasphere.ch>
* @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:

View File

@ -14,7 +14,7 @@
* - {@link http://en.wikipedia.org/wiki/RC4 - Wikipedia: RC4} * - {@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 * 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: * Here's a short example of how to use this library:
* <code> * <code>
@ -58,10 +58,18 @@
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @copyright MMVII Jim Wigginton * @copyright MMVII Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @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 * @link http://phpseclib.sourceforge.net
*/ */
/**
* Include Crypt_Base
*
* Base cipher class
*/
if (!class_exists('Crypt_Base')) {
require_once('Base.php');
}
/**#@+ /**#@+
* @access private * @access private
* @see Crypt_RC4::Crypt_RC4() * @see Crypt_RC4::Crypt_RC4()
@ -69,11 +77,11 @@
/** /**
* Toggles the internal implementation * Toggles the internal implementation
*/ */
define('CRYPT_RC4_MODE_INTERNAL', 1); define('CRYPT_RC4_MODE_INTERNAL', CRYPT_MODE_INTERNAL);
/** /**
* Toggles the mcrypt implementation * 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 * @access public
* @package Crypt_RC4 * @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 * The Key
* *
@ -103,190 +161,26 @@ class Crypt_RC4 {
var $key = "\0"; var $key = "\0";
/** /**
* The Key Stream for encryption * The Key Stream for decryption and encryption
*
* If CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT, this will be equal to the mcrypt object
* *
* @see Crypt_RC4::setKey() * @see Crypt_RC4::setKey()
* @var Array * @var Array
* @access private * @access private
*/ */
var $encryptStream = false; var $stream;
/**
* 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;
/** /**
* Default Constructor. * Default Constructor.
* *
* Determines whether or not the mcrypt extension should be used. * Determines whether or not the mcrypt extension should be used.
* *
* @see Crypt_Base::Crypt_Base()
* @return Crypt_RC4 * @return Crypt_RC4
* @access public * @access public
*/ */
function Crypt_RC4() function Crypt_RC4()
{ {
if ( !defined('CRYPT_RC4_MODE') ) { parent::Crypt_Base(CRYPT_MODE_STREAM);
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));
} }
/** /**
@ -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. * Encrypts a message.
* *
* @see Crypt_Base::decrypt()
* @see Crypt_RC4::_crypt() * @see Crypt_RC4::_crypt()
* @access public * @access public
* @param String $plaintext * @param String $plaintext
* @return String $ciphertext
*/ */
function encrypt($plaintext) function encrypt($plaintext)
{ {
if ($this->engine == CRYPT_MODE_MCRYPT) {
return parent::encrypt($plaintext);
}
return $this->_crypt($plaintext, CRYPT_RC4_ENCRYPT); return $this->_crypt($plaintext, CRYPT_RC4_ENCRYPT);
} }
@ -330,15 +244,51 @@ class Crypt_RC4 {
* $this->decrypt($this->encrypt($plaintext)) == $this->encrypt($this->encrypt($plaintext)). * $this->decrypt($this->encrypt($plaintext)) == $this->encrypt($this->encrypt($plaintext)).
* Atleast if the continuous buffer is disabled. * Atleast if the continuous buffer is disabled.
* *
* @see Crypt_Base::encrypt()
* @see Crypt_RC4::_crypt() * @see Crypt_RC4::_crypt()
* @access public * @access public
* @param String $ciphertext * @param String $ciphertext
* @return String $plaintext
*/ */
function decrypt($ciphertext) function decrypt($ciphertext)
{ {
if ($this->engine == CRYPT_MODE_MCRYPT) {
return parent::decrypt($ciphertext);
}
return $this->_crypt($ciphertext, CRYPT_RC4_DECRYPT); 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. * Encrypts or decrypts a message.
* *
@ -347,171 +297,39 @@ class Crypt_RC4 {
* @access private * @access private
* @param String $text * @param String $text
* @param Integer $mode * @param Integer $mode
* @return String $text
*/ */
function _crypt($text, $mode) function _crypt($text, $mode)
{ {
if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) { if ($this->changed) {
$keyStream = $mode == CRYPT_RC4_ENCRYPT ? 'encryptStream' : 'decryptStream'; $this->_setup();
$this->changed = false;
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);
} }
$stream = &$this->stream[$mode];
if ($this->continuousBuffer) { if ($this->continuousBuffer) {
switch ($mode) { $i = &$stream[0];
case CRYPT_RC4_ENCRYPT: $j = &$stream[1];
$this->encryptStream = $keyStream; $keyStream = &$stream[2];
$this->encryptIndex = array($i, $j); } else {
break; $i = $stream[0];
case CRYPT_RC4_DECRYPT: $j = $stream[1];
$this->decryptStream = $keyStream; $keyStream = $stream[2];
$this->decryptIndex = array($i, $j);
}
} }
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];
$keyStream[$i] = $ksj;
$keyStream[$j] = $ksi;
$text[$k] = chr(ord($text[$k]) ^ $keyStream[($ksj + $ksi) & 255]);
} }
/** return $text;
* 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:
*
* <code>
* echo $rc4->encrypt(substr($plaintext, 0, 8));
* echo $rc4->encrypt(substr($plaintext, 8, 8));
* </code>
* <code>
* echo $rc4->encrypt($plaintext);
* </code>
*
* The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates
* another, as demonstrated with the following:
*
* <code>
* $rc4->encrypt(substr($plaintext, 0, 8));
* echo $rc4->decrypt($des->encrypt(substr($plaintext, 8, 8)));
* </code>
* <code>
* echo $rc4->decrypt($des->encrypt(substr($plaintext, 8, 8)));
* </code>
*
* 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, '');
}
$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);
} }
} }

View File

@ -65,17 +65,9 @@
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @copyright MMIX Jim Wigginton * @copyright MMIX Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @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 * @link http://phpseclib.sourceforge.net
*/ */
/**
* Include Math_BigInteger
*/
if (!class_exists('Math_BigInteger')) {
require_once('Math/BigInteger.php');
}
/** /**
* Include Crypt_Random * 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 // 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 // call function_exists() a second time to stop the require_once from being called outside
// of the auto loader // of the auto loader
if (!function_exists('crypt_random_string') && !class_exists('Crypt_Random') && !function_exists('crypt_random_string')) { if (!function_exists('crypt_random_string')) {
require_once('Crypt/Random.php'); require_once('Random.php');
} }
/** /**
* Include Crypt_Hash * Include Crypt_Hash
*/ */
if (!class_exists('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'); define('CRYPT_RSA_OPENSSL_CONFIG', dirname(__FILE__) . '/../openssl.cnf');
/**#@+ /**#@+
* @access public * @access public
* @see Crypt_RSA::createKey() * @see Crypt_RSA::createKey()
@ -449,6 +440,14 @@ class Crypt_RSA {
*/ */
var $configFile; var $configFile;
/**
* Public key comment field.
*
* @var String
* @access private
*/
var $comment = 'phpseclib-generated-key';
/** /**
* The constructor * The constructor
* *
@ -461,20 +460,52 @@ class Crypt_RSA {
*/ */
function Crypt_RSA() function Crypt_RSA()
{ {
if (!class_exists('Math_BigInteger')) {
require_once('Math/BigInteger.php');
}
$this->configFile = CRYPT_RSA_OPENSSL_CONFIG; $this->configFile = CRYPT_RSA_OPENSSL_CONFIG;
if ( !defined('CRYPT_RSA_MODE') ) { if ( !defined('CRYPT_RSA_MODE') ) {
// 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) { switch (true) {
case extension_loaded('openssl') && version_compare(PHP_VERSION, '4.2.0', '>='): case !isset($versions['Header']):
case !isset($versions['Library']):
case $versions['Header'] == $versions['Library']:
define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_OPENSSL); define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_OPENSSL);
break; break;
default: default:
define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL); define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL);
define('MATH_BIGINTEGER_OPENSSL_DISABLE', true);
} }
break;
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->zero = new Math_BigInteger();
@ -642,12 +673,12 @@ class Crypt_RSA {
$exponents[$i] = $e->modInverse($temp); $exponents[$i] = $e->modInverse($temp);
} }
list($lcm) = $lcm['top']->divide($lcm['bottom']); list($temp) = $lcm['top']->divide($lcm['bottom']);
$gcd = $lcm->gcd($e); $gcd = $temp->gcd($e);
$i0 = 1; $i0 = 1;
} while (!$gcd->equals($this->one)); } while (!$gcd->equals($this->one));
$d = $e->modInverse($lcm); $d = $e->modInverse($temp);
$coefficients[2] = $primes[2]->modInverse($primes[1]); $coefficients[2] = $primes[2]->modInverse($primes[1]);
@ -720,16 +751,16 @@ class Crypt_RSA {
$key = "PuTTY-User-Key-File-2: ssh-rsa\r\nEncryption: "; $key = "PuTTY-User-Key-File-2: ssh-rsa\r\nEncryption: ";
$encryption = (!empty($this->password) || is_string($this->password)) ? 'aes256-cbc' : 'none'; $encryption = (!empty($this->password) || is_string($this->password)) ? 'aes256-cbc' : 'none';
$key.= $encryption; $key.= $encryption;
$key.= "\r\nComment: " . CRYPT_RSA_COMMENT . "\r\n"; $key.= "\r\nComment: " . $this->comment . "\r\n";
$public = pack('Na*Na*Na*', $public = pack('Na*Na*Na*',
strlen('ssh-rsa'), 'ssh-rsa', strlen($raw['publicExponent']), $raw['publicExponent'], strlen($raw['modulus']), $raw['modulus'] strlen('ssh-rsa'), 'ssh-rsa', strlen($raw['publicExponent']), $raw['publicExponent'], strlen($raw['modulus']), $raw['modulus']
); );
$source = pack('Na*Na*Na*Na*', $source = pack('Na*Na*Na*Na*',
strlen('ssh-rsa'), 'ssh-rsa', strlen($encryption), $encryption, 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); $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); $key.= chunk_split($public, 64);
$private = pack('Na*Na*Na*Na*', $private = pack('Na*Na*Na*Na*',
strlen($raw['privateExponent']), $raw['privateExponent'], strlen($raw['prime1']), $raw['prime1'], strlen($raw['privateExponent']), $raw['privateExponent'], strlen($raw['prime1']), $raw['prime1'],
@ -760,7 +791,7 @@ class Crypt_RSA {
} }
$private = base64_encode($private); $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); $key.= chunk_split($private, 64);
if (!class_exists('Crypt_Hash')) { if (!class_exists('Crypt_Hash')) {
require_once('Crypt/Hash.php'); require_once('Crypt/Hash.php');
@ -853,7 +884,7 @@ class Crypt_RSA {
// mpint e // mpint e
// mpint n // mpint n
$RSAPublicKey = pack('Na*Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($publicExponent), $publicExponent, strlen($modulus), $modulus); $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; return $RSAPublicKey;
default: // eg. CRYPT_RSA_PUBLIC_FORMAT_PKCS1_RAW or CRYPT_RSA_PUBLIC_FORMAT_PKCS1 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)) { if (preg_match('#DEK-Info: (.+),(.+)#', $key, $matches)) {
$iv = pack('H*', trim($matches[2])); $iv = pack('H*', trim($matches[2]));
$symkey = pack('H*', md5($this->password . substr($iv, 0, 8))); // symkey is short for symmetric key $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_replace('#.+(\r|\n|\r\n)\1|[\r\n]|-.+-| #s', '', $key);
$ciphertext = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $ciphertext) ? base64_decode($ciphertext) : false; $ciphertext = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $ciphertext) ? base64_decode($ciphertext) : false;
if ($ciphertext === false) { if ($ciphertext === false) {
$ciphertext = $key; $ciphertext = $key;
} }
switch ($matches[1]) { 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': case 'AES-128-CBC':
if (!class_exists('Crypt_AES')) { if (!class_exists('Crypt_AES')) {
require_once('Crypt/AES.php'); require_once('Crypt/AES.php');
@ -984,6 +1021,7 @@ class Crypt_RSA {
if (!class_exists('Crypt_TripleDES')) { if (!class_exists('Crypt_TripleDES')) {
require_once('Crypt/TripleDES.php'); require_once('Crypt/TripleDES.php');
} }
$symkey = substr($symkey, 0, 24);
$crypto = new Crypt_TripleDES(); $crypto = new Crypt_TripleDES();
break; break;
case 'DES-CBC': case 'DES-CBC':
@ -1121,11 +1159,15 @@ class Crypt_RSA {
return $components; return $components;
case CRYPT_RSA_PUBLIC_FORMAT_OPENSSH: 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) { if ($key === false) {
return false; return false;
} }
$comment = isset($parts[2]) ? $parts[2] : false;
$cleanup = substr($key, 0, 11) == "\0\0\0\7ssh-rsa"; $cleanup = substr($key, 0, 11) == "\0\0\0\7ssh-rsa";
if (strlen($key) <= 4) { if (strlen($key) <= 4) {
@ -1147,12 +1189,14 @@ class Crypt_RSA {
$realModulus = new Math_BigInteger($this->_string_shift($key, $length), -256); $realModulus = new Math_BigInteger($this->_string_shift($key, $length), -256);
return strlen($key) ? false : array( return strlen($key) ? false : array(
'modulus' => $realModulus, 'modulus' => $realModulus,
'publicExponent' => $modulus 'publicExponent' => $modulus,
'comment' => $comment
); );
} else { } else {
return strlen($key) ? false : array( return strlen($key) ? false : array(
'modulus' => $modulus, 'modulus' => $modulus,
'publicExponent' => $publicExponent 'publicExponent' => $publicExponent,
'comment' => $comment
); );
} }
// http://www.w3.org/TR/xmldsig-core/#sec-RSAKeyValue // http://www.w3.org/TR/xmldsig-core/#sec-RSAKeyValue
@ -1180,6 +1224,7 @@ class Crypt_RSA {
return false; return false;
} }
$encryption = trim(preg_replace('#Encryption: (.+)#', '$1', $key[1])); $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])); $publicLength = trim(preg_replace('#Public-Lines: (\d+)#', '$1', $key[3]));
$public = base64_decode(implode('', array_map('trim', array_slice($key, 4, $publicLength)))); $public = base64_decode(implode('', array_map('trim', array_slice($key, 4, $publicLength))));
@ -1297,9 +1342,6 @@ class Crypt_RSA {
break; break;
case 'D': case 'D':
$this->current = &$this->components['privateExponent']; $this->current = &$this->components['privateExponent'];
break;
default:
unset($this->current);
} }
$this->current = ''; $this->current = '';
} }
@ -1315,11 +1357,10 @@ class Crypt_RSA {
*/ */
function _stop_element_handler($parser, $name) function _stop_element_handler($parser, $name)
{ {
//$name = strtoupper($name); if (isset($this->current)) {
if ($name == 'RSAKEYVALUE') {
return;
}
$this->current = new Math_BigInteger(base64_decode($this->current), 256); $this->current = new Math_BigInteger(base64_decode($this->current), 256);
unset($this->current);
}
} }
/** /**
@ -1350,6 +1391,53 @@ class Crypt_RSA {
*/ */
function loadKey($key, $type = false) 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) { if ($type === false) {
$types = array( $types = array(
CRYPT_RSA_PUBLIC_FORMAT_RAW, CRYPT_RSA_PUBLIC_FORMAT_RAW,
@ -1373,6 +1461,9 @@ class Crypt_RSA {
return false; return false;
} }
if (isset($components['comment']) && $components['comment'] !== false) {
$this->comment = $components['comment'];
}
$this->modulus = $components['modulus']; $this->modulus = $components['modulus'];
$this->k = strlen($this->modulus->toBytes()); $this->k = strlen($this->modulus->toBytes());
$this->exponent = isset($components['privateExponent']) ? $components['privateExponent'] : $components['publicExponent']; $this->exponent = isset($components['privateExponent']) ? $components['privateExponent'] : $components['publicExponent'];
@ -1428,6 +1519,11 @@ class Crypt_RSA {
*/ */
function setPublicKey($key = false, $type = false) 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)) { if ($key === false && !empty($this->modulus)) {
$this->publicExponent = $this->exponent; $this->publicExponent = $this->exponent;
return true; return true;
@ -1552,6 +1648,18 @@ class Crypt_RSA {
return $key !== false ? $key : ''; 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 * Generates the smallest and largest numbers requiring $bits bits
* *
@ -1582,7 +1690,7 @@ class Crypt_RSA {
* DER-decode the length * DER-decode the length
* *
* DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See * 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 * @access private
* @param String $string * @param String $string
@ -1603,7 +1711,7 @@ class Crypt_RSA {
* DER-encode the length * DER-encode the length
* *
* DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See * 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 * @access private
* @param Integer $length * @param Integer $length
@ -1872,7 +1980,7 @@ class Crypt_RSA {
* *
* Protects against a particular type of timing attack described. * 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, Dont 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! * Thanks for the heads up singpolyma!
* *
@ -2135,6 +2243,7 @@ class Crypt_RSA {
} }
// EME-PKCS1-v1_5 encoding // EME-PKCS1-v1_5 encoding
$psLen = $this->k - $mLen - 3; $psLen = $this->k - $mLen - 3;
$ps = ''; $ps = '';
while (strlen($ps) != $psLen) { while (strlen($ps) != $psLen) {
@ -2142,7 +2251,14 @@ class Crypt_RSA {
$temp = str_replace("\x00", '', $temp); $temp = str_replace("\x00", '', $temp);
$ps.= $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 // RSA encryption
$m = $this->_os2ip($em); $m = $this->_os2ip($em);
@ -2515,6 +2631,28 @@ class Crypt_RSA {
$this->signatureMode = $mode; $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 * Encryption
* *

View File

@ -38,10 +38,16 @@
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @copyright MMVII Jim Wigginton * @copyright MMVII Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @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 * @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. * Generate a random string.
* *
@ -53,9 +59,9 @@
* @return String * @return String
* @access public * @access public
*/ */
function crypt_random_string($length) { 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') { 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. // 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 // ie. class_alias is a function that was introduced in PHP 5.3
if (function_exists('mcrypt_create_iv') && function_exists('class_alias')) { if (function_exists('mcrypt_create_iv') && function_exists('class_alias')) {
@ -143,7 +149,7 @@ function crypt_random_string($length) {
serialize($_POST) . serialize($_POST) .
serialize($_GET) . serialize($_GET) .
serialize($_COOKIE) . serialize($_COOKIE) .
serialize($_GLOBAL) . serialize($GLOBALS) .
serialize($_SESSION) . serialize($_SESSION) .
serialize($_OLD_SESSION) serialize($_OLD_SESSION)
)); ));

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,924 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* Pure-PHP implementation of Twofish.
*
* Uses mcrypt, if available, and an internal implementation, otherwise.
*
* PHP versions 4 and 5
*
* Useful resources are as follows:
*
* - {@link http://en.wikipedia.org/wiki/Twofish Wikipedia description of Twofish}
*
* Here's a short example of how to use this library:
* <code>
* <?php
* include('Crypt/Twofish.php');
*
* $twofish = new Crypt_Twofish();
*
* $twofish->setKey('12345678901234567890123456789012');
*
* $plaintext = str_repeat('a', 1024);
*
* echo $twofish->decrypt($twofish->encrypt($plaintext));
* ?>
* </code>
*
* 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 <terrafrost@php.net>
* @author Hans-Juergen Petrich <petrich@tronic-media.com>
* @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 <terrafrost@php.net>
* @author Hans-Juergen Petrich <petrich@tronic-media.com>
* @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:

View File

@ -34,8 +34,7 @@
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @copyright MMXII Jim Wigginton * @copyright MMXII Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version $Id$ * @link http://phpseclib.sourceforge.net
* @link htp://phpseclib.sourceforge.net
*/ */
/** /**
@ -298,12 +297,12 @@ class File_ANSI {
} }
// http://ascii-table.com/ansi-escape-sequences-vt-100.php // http://ascii-table.com/ansi-escape-sequences-vt-100.php
switch ($this->ansi) { switch ($this->ansi) {
case "\x1B[H": case "\x1B[H": // Move cursor to upper left corner
$this->old_x = $this->x; $this->old_x = $this->x;
$this->old_y = $this->y; $this->old_y = $this->y;
$this->x = $this->y = 0; $this->x = $this->y = 0;
break; 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->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, '')); $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);
array_shift($this->history_attrs); 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); $this->screen[$this->y] = substr($this->screen[$this->y], 0, $this->x);
array_splice($this->attrs[$this->y], $this->x + 1); array_splice($this->attrs[$this->y], $this->x + 1);
break; 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[?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; break;
default: default:
switch (true) { 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_x = $this->x;
$this->old_y = $this->y; $this->old_y = $this->y;
$this->x = $match[2] - 1; $this->x = $match[2] - 1;
$this->y = $match[1] - 1; $this->y = $match[1] - 1;
break; 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; $this->old_x = $this->x;
$x = $match[1] - 1; $x = $match[1] - 1;
break; break;
case preg_match('#\x1B\[(\d+);(\d+)r#', $this->ansi, $match): // Set top and bottom lines of a window case preg_match('#\x1B\[(\d+);(\d+)r#', $this->ansi, $match): // Set top and bottom lines of a window
break; 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]); $mods = explode(';', $match[1]);
foreach ($mods as $mod) { foreach ($mods as $mod) {
switch ($mod) { switch ($mod) {
case 0: case 0: // Turn off character attributes
$this->attrs[$this->y][$this->x] = ''; $this->attrs[$this->y][$this->x] = '';
if ($this->bold) $this->attrs[$this->y][$this->x].= '</b>'; if ($this->bold) $this->attrs[$this->y][$this->x].= '</b>';
if ($this->underline) $this->attrs[$this->y][$this->x].= '</underline>'; if ($this->underline) $this->attrs[$this->y][$this->x].= '</u>';
if ($this->blink) $this->attrs[$this->y][$this->x].= '</blink>'; if ($this->blink) $this->attrs[$this->y][$this->x].= '</blink>';
if ($this->color) $this->attrs[$this->y][$this->x].= '</span>'; if ($this->color) $this->attrs[$this->y][$this->x].= '</span>';
@ -355,25 +363,25 @@ class File_ANSI {
$this->bold = $this->underline = $this->blink = $this->color = $this->reverse = false; $this->bold = $this->underline = $this->blink = $this->color = $this->reverse = false;
break; break;
case 1: case 1: // Turn bold mode on
if (!$this->bold) { if (!$this->bold) {
$this->attrs[$this->y][$this->x] = '<b>'; $this->attrs[$this->y][$this->x] = '<b>';
$this->bold = true; $this->bold = true;
} }
break; break;
case 4: case 4: // Turn underline mode on
if (!$this->underline) { if (!$this->underline) {
$this->attrs[$this->y][$this->x] = '<u>'; $this->attrs[$this->y][$this->x] = '<u>';
$this->underline = true; $this->underline = true;
} }
break; break;
case 5: case 5: // Turn blinking mode on
if (!$this->blink) { if (!$this->blink) {
$this->attrs[$this->y][$this->x] = '<blink>'; $this->attrs[$this->y][$this->x] = '<blink>';
$this->blink = true; $this->blink = true;
} }
break; break;
case 7: case 7: // Turn reverse video on
$this->reverse = !$this->reverse; $this->reverse = !$this->reverse;
$temp = $this->background; $temp = $this->background;
$this->background = $this->foreground; $this->background = $this->foreground;
@ -384,7 +392,7 @@ class File_ANSI {
} }
$this->color = true; $this->color = true;
break; break;
default: default: // set colors
//$front = $this->reverse ? &$this->background : &$this->foreground; //$front = $this->reverse ? &$this->background : &$this->foreground;
$front = &$this->{ $this->reverse ? 'background' : 'foreground' }; $front = &$this->{ $this->reverse ? 'background' : 'foreground' };
//$back = $this->reverse ? &$this->foreground : &$this->background; //$back = $this->reverse ? &$this->foreground : &$this->background;
@ -424,7 +432,7 @@ class File_ANSI {
} }
break; break;
default: default:
echo "{$this->ansi} unsupported\r\n"; user_error("{$this->ansi} unsupported\r\n");
} }
} }
$this->ansi = ''; $this->ansi = '';
@ -436,25 +444,7 @@ class File_ANSI {
$this->x = 0; $this->x = 0;
break; break;
case "\n": case "\n":
//if ($this->y < $this->max_y) { $this->_newLine();
// $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++;
break; break;
case "\x0F": // shift case "\x0F": // shift
break; 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 * Returns the current screen without preformating
* *

View File

@ -37,17 +37,9 @@
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @copyright MMXII Jim Wigginton * @copyright MMXII Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version $Id$
* @link http://phpseclib.sourceforge.net * @link http://phpseclib.sourceforge.net
*/ */
/**
* Include Math_BigInteger
*/
if (!class_exists('Math_BigInteger')) {
require_once('Math/BigInteger.php');
}
/**#@+ /**#@+
* Tag Classes * Tag Classes
* *
@ -249,6 +241,22 @@ class File_ASN1 {
FILE_ASN1_TYPE_VISIBLE_STRING => 1, 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 * Parse BER-encoding
* *
@ -304,12 +312,12 @@ class File_ASN1 {
} while ( $loop ); } 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)); $length = ord($this->_string_shift($encoded));
$start++; $start++;
if ( $length == 0x80 ) { // indefinite length 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 // "[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 ) { //if ( !$constructed ) {
// return false; // return false;
//} //}
@ -319,11 +327,15 @@ class File_ASN1 {
// support it up to four. // support it up to four.
$length&= 0x7F; $length&= 0x7F;
$temp = $this->_string_shift($encoded, $length); $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; $start+= $length;
extract(unpack('Nlength', substr(str_pad($temp, 4, chr(0), STR_PAD_LEFT), -4))); 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) { if (!$type && !$length) {
return $decoded; return $decoded;
} }
@ -349,6 +361,7 @@ class File_ASN1 {
'content' => $constructed ? $this->_decode_ber($content, $start) : $content, 'content' => $constructed ? $this->_decode_ber($content, $start) : $content,
'length' => $length + $start - $current['start'] 'length' => $length + $start - $current['start']
) + $current; ) + $current;
$start+= $length;
continue 2; continue 2;
} }
@ -357,7 +370,7 @@ class File_ASN1 {
// decode UNIVERSAL tags // decode UNIVERSAL tags
switch ($tag) { switch ($tag) {
case FILE_ASN1_TYPE_BOOLEAN: 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) { //if (strlen($content) != 1) {
// return false; // return false;
//} //}
@ -410,7 +423,7 @@ class File_ASN1 {
} }
break; break;
case FILE_ASN1_TYPE_NULL: 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)) { //if (strlen($content)) {
// return false; // return false;
//} //}
@ -441,7 +454,7 @@ class File_ASN1 {
/* Each character string type shall be encoded as if it had been declared: /* Each character string type shall be encoded as if it had been declared:
[UNIVERSAL x] IMPLICIT OCTET STRING [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, Per that, we're not going to do any validation. If there are any illegal characters in the string,
we don't really care */ 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. * 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 $decoded
* @param Array $mapping * @param Array $mapping
* @param Array $special
* @return Array * @return Array
* @access public * @access public
*/ */
function asn1map($decoded, $mapping) function asn1map($decoded, $mapping, $special = array())
{ {
if (isset($mapping['explicit'])) { if (isset($mapping['explicit'])) {
$decoded = $decoded['content'][0]; $decoded = $decoded['content'][0];
@ -506,7 +522,7 @@ class File_ASN1 {
} }
$inmap = $this->ANYmap[$intype]; $inmap = $this->ANYmap[$intype];
if (is_string($inmap)) { 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; break;
case $mapping['type'] == FILE_ASN1_TYPE_CHOICE: case $mapping['type'] == FILE_ASN1_TYPE_CHOICE:
@ -514,15 +530,18 @@ class File_ASN1 {
switch (true) { switch (true) {
case isset($option['constant']) && $option['constant'] == $decoded['constant']: case isset($option['constant']) && $option['constant'] == $decoded['constant']:
case !isset($option['constant']) && $option['type'] == $decoded['type']: case !isset($option['constant']) && $option['type'] == $decoded['type']:
$value = $this->asn1map($decoded, $option); $value = $this->asn1map($decoded, $option, $special);
break; break;
case !isset($option['constant']) && $option['type'] == FILE_ASN1_TYPE_CHOICE: case !isset($option['constant']) && $option['type'] == FILE_ASN1_TYPE_CHOICE:
$v = $this->asn1map($decoded, $option); $v = $this->asn1map($decoded, $option, $special);
if (isset($v)) { if (isset($v)) {
$value = $v; $value = $v;
} }
} }
if (isset($value)) { if (isset($value)) {
if (isset($special[$key])) {
$value = call_user_func($special[$key], $value);
}
return array($key => $value); return array($key => $value);
} }
} }
@ -547,7 +566,7 @@ class File_ASN1 {
if (isset($mapping['min']) && isset($mapping['max'])) { if (isset($mapping['min']) && isset($mapping['max'])) {
$child = $mapping['children']; $child = $mapping['children'];
foreach ($decoded['content'] as $content) { foreach ($decoded['content'] as $content) {
if (($map[] = $this->asn1map($content, $child)) === NULL) { if (($map[] = $this->asn1map($content, $child, $special)) === NULL) {
return NULL; return NULL;
} }
} }
@ -591,12 +610,15 @@ class File_ASN1 {
if ($maymatch) { if ($maymatch) {
// Attempt submapping. // Attempt submapping.
$candidate = $this->asn1map($temp, $child); $candidate = $this->asn1map($temp, $child, $special);
$maymatch = $candidate !== NULL; $maymatch = $candidate !== NULL;
} }
if ($maymatch) { if ($maymatch) {
// Got the match: use it. // Got the match: use it.
if (isset($special[$key])) {
$candidate = call_user_func($special[$key], $candidate);
}
$map[$key] = $candidate; $map[$key] = $candidate;
$i++; $i++;
} elseif (isset($child['default'])) { } elseif (isset($child['default'])) {
@ -617,7 +639,7 @@ class File_ASN1 {
if (isset($mapping['min']) && isset($mapping['max'])) { if (isset($mapping['min']) && isset($mapping['max'])) {
$child = $mapping['children']; $child = $mapping['children'];
foreach ($decoded['content'] as $content) { foreach ($decoded['content'] as $content) {
if (($map[] = $this->asn1map($content, $child)) === NULL) { if (($map[] = $this->asn1map($content, $child, $special)) === NULL) {
return NULL; return NULL;
} }
} }
@ -660,7 +682,7 @@ class File_ASN1 {
if ($maymatch) { if ($maymatch) {
// Attempt submapping. // Attempt submapping.
$candidate = $this->asn1map($temp, $child); $candidate = $this->asn1map($temp, $child, $special);
$maymatch = $candidate !== NULL; $maymatch = $candidate !== NULL;
} }
@ -669,6 +691,9 @@ class File_ASN1 {
} }
// Got the match: use it. // Got the match: use it.
if (isset($special[$key])) {
$candidate = call_user_func($special[$key], $candidate);
}
$map[$key] = $candidate; $map[$key] = $candidate;
break; break;
} }
@ -761,18 +786,30 @@ class File_ASN1 {
* DER-encodes an ASN.1 semantic mapping ($mapping). Some libraries would probably call this function * DER-encodes an ASN.1 semantic mapping ($mapping). Some libraries would probably call this function
* an ASN.1 compiler. * an ASN.1 compiler.
* *
* "Special" mappings can be applied via $special.
*
* @param String $source * @param String $source
* @param String $mapping * @param String $mapping
* @param Integer $idx * @param Integer $idx
* @return String * @return String
* @access public * @access public
*/ */
function encodeDER($source, $mapping) function encodeDER($source, $mapping, $special = array())
{ {
$this->location = 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) * ASN.1 Encode (Helper function)
* *
@ -782,7 +819,7 @@ class File_ASN1 {
* @return String * @return String
* @access private * @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') { if (is_object($source) && strtolower(get_class($source)) == 'file_asn1_element') {
return $source->element; return $source->element;
@ -794,6 +831,9 @@ class File_ASN1 {
} }
if (isset($idx)) { if (isset($idx)) {
if (isset($special[$idx])) {
$source = call_user_func($special[$idx], $source);
}
$this->location[] = $idx; $this->location[] = $idx;
} }
@ -810,7 +850,7 @@ class File_ASN1 {
$child = $mapping['children']; $child = $mapping['children'];
foreach ($source as $content) { foreach ($source as $content) {
$temp = $this->_encode_der($content, $child); $temp = $this->_encode_der($content, $child, NULL, $special);
if ($temp === false) { if ($temp === false) {
return false; return false;
} }
@ -827,7 +867,7 @@ class File_ASN1 {
continue; continue;
} }
$temp = $this->_encode_der($source[$key], $child, $key); $temp = $this->_encode_der($source[$key], $child, $key, $special);
if ($temp === false) { if ($temp === false) {
return false; return false;
} }
@ -868,7 +908,7 @@ class File_ASN1 {
continue; continue;
} }
$temp = $this->_encode_der($source[$key], $child, $key); $temp = $this->_encode_der($source[$key], $child, $key, $special);
if ($temp === false) { if ($temp === false) {
return false; return false;
} }
@ -914,6 +954,9 @@ class File_ASN1 {
$value = new Math_BigInteger($value); $value = new Math_BigInteger($value);
$value = $value->toBytes(true); $value = $value->toBytes(true);
} }
if (!strlen($value)) {
$value = chr(0);
}
break; break;
case FILE_ASN1_TYPE_UTC_TIME: case FILE_ASN1_TYPE_UTC_TIME:
case FILE_ASN1_TYPE_GENERALIZED_TIME: case FILE_ASN1_TYPE_GENERALIZED_TIME:
@ -987,19 +1030,19 @@ class File_ASN1 {
switch (true) { switch (true) {
case !isset($source): 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_int($source):
case is_object($source) && strtolower(get_class($source)) == 'math_biginteger': 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): 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): 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: case is_array($source) && count($source) == 1:
$typename = implode('', array_keys($source)); $typename = implode('', array_keys($source));
$outtype = array_search($typename, $this->ANYmap, true); $outtype = array_search($typename, $this->ANYmap, true);
if ($outtype !== false) { 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)); user_error('No filters defined for ' . implode('/', $loc));
return false; return false;
} }
return $this->_encode_der($source, $filters + $mapping); return $this->_encode_der($source, $filters + $mapping, NULL, $special);
case FILE_ASN1_TYPE_NULL: case FILE_ASN1_TYPE_NULL:
$value = ''; $value = '';
break; break;
@ -1055,7 +1098,7 @@ class File_ASN1 {
* DER-encode the length * DER-encode the length
* *
* DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See * 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 * @access private
* @param Integer $length * @param Integer $length

View File

@ -40,22 +40,22 @@
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @copyright MMXII Jim Wigginton * @copyright MMXII Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version $Id$ * @link http://phpseclib.sourceforge.net
* @link htp://phpseclib.sourceforge.net
*/ */
/** /**
* Include File_ASN1 * Include File_ASN1
*/ */
if (!class_exists('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 * 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 * @access public
* @see File_X509::validateSignature()
*/ */
define('FILE_X509_VALIDATE_SIGNATURE_BY_CA', 1); define('FILE_X509_VALIDATE_SIGNATURE_BY_CA', 1);
@ -306,6 +306,10 @@ class File_X509 {
*/ */
function File_X509() function File_X509()
{ {
if (!class_exists('Math_BigInteger')) {
require_once('Math/BigInteger.php');
}
// Explicitly Tagged Module, 1988 Syntax // Explicitly Tagged Module, 1988 Syntax
// http://tools.ietf.org/html/rfc5280#appendix-A.1 // http://tools.ietf.org/html/rfc5280#appendix-A.1
@ -1436,18 +1440,7 @@ class File_X509 {
$asn1 = new File_ASN1(); $asn1 = new File_ASN1();
/* $cert = $this->_extractBER($cert);
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;
}
if ($cert === false) { if ($cert === false) {
$this->currentCert = false; $this->currentCert = false;
@ -1569,7 +1562,7 @@ class File_X509 {
corresponding to the extension type identified by extnID */ corresponding to the extension type identified by extnID */
$map = $this->_getMapping($id); $map = $this->_getMapping($id);
if (!is_bool($map)) { 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; $value = $mapped === false ? $decoded[0] : $mapped;
if ($id == 'id-ce-certificatePolicies') { if ($id == 'id-ce-certificatePolicies') {
@ -1651,7 +1644,7 @@ class File_X509 {
unset($extensions[$i]); unset($extensions[$i]);
} }
} else { } else {
$temp = $asn1->encodeDER($value, $map); $temp = $asn1->encodeDER($value, $map, array('iPAddress' => array($this, '_encodeIP')));
$value = base64_encode($temp); $value = base64_encode($temp);
} }
} }
@ -2001,16 +1994,19 @@ class File_X509 {
* Works on X.509 certs, CSR's and CRL's. * 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 * 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}. * 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 * @access public
* @return Mixed * @return Mixed
*/ */
function validateSignature($options = 0) function validateSignature($caonly = true)
{ {
if (!is_array($this->currentCert) || !isset($this->signatureSubject)) { if (!is_array($this->currentCert) || !isset($this->signatureSubject)) {
return 0; return NULL;
} }
/* TODO: /* 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; return false;
} }
} elseif (!isset($signingCert) || ($options & FILE_X509_VALIDATE_SIGNATURE_BY_CA)) { } elseif (!isset($signingCert) || $caonly) {
return false; return false;
} }
return $this->_validateSignature( 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 * "Normalizes" a Distinguished Name property
* *
@ -2207,7 +2233,7 @@ class File_X509 {
case 'commonname': case 'commonname':
case 'cn': case 'cn':
return 'id-at-commonName'; return 'id-at-commonName';
case 'id-at-stateorprovinceName': case 'id-at-stateorprovincename':
case 'stateorprovincename': case 'stateorprovincename':
case 'state': case 'state':
case 'province': case 'province':
@ -2630,9 +2656,9 @@ class File_X509 {
case !isset($this->currentCert) || !is_array($this->currentCert): case !isset($this->currentCert) || !is_array($this->currentCert):
break; break;
case isset($this->currentCert['tbsCertificate']): 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']): 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; return false;
@ -2656,7 +2682,7 @@ class File_X509 {
case isset($this->currentCert['tbsCertificate']): case isset($this->currentCert['tbsCertificate']):
return $this->getDNProp($propName, $this->currentCert['tbsCertificate']['subject'], $withType); return $this->getDNProp($propName, $this->currentCert['tbsCertificate']['subject'], $withType);
case isset($this->currentCert['certificationRequestInfo']): 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; return false;
@ -2718,6 +2744,7 @@ class File_X509 {
*/ */
function setPublicKey($key) function setPublicKey($key)
{ {
$key->setPublicKey();
$this->publicKey = $key; $this->publicKey = $key;
} }
@ -2804,11 +2831,7 @@ class File_X509 {
$asn1 = new File_ASN1(); $asn1 = new File_ASN1();
$temp = preg_replace('#^(?:[^-].+[\r\n]+)+|-.+-|[\r\n]| #', '', $csr); $csr = $this->_extractBER($csr);
$temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? base64_decode($temp) : false;
if ($temp != false) {
$csr = $temp;
}
$orig = $csr; $orig = $csr;
if ($csr === false) { if ($csr === false) {
@ -2917,51 +2940,51 @@ class File_X509 {
* @access public * @access public
* @return Mixed * @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->currentCert);
unset($this->currentKeyIdentifier); unset($this->currentKeyIdentifier);
unset($this->signatureSubject); unset($this->signatureSubject);
$this->currentCert = $csr; $this->currentCert = $spkac;
return $csr; return $spkac;
} }
// see http://www.w3.org/html/wg/drafts/html/master/forms.html#signedpublickeyandchallenge // see http://www.w3.org/html/wg/drafts/html/master/forms.html#signedpublickeyandchallenge
$asn1 = new File_ASN1(); $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; $temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? base64_decode($temp) : false;
if ($temp != false) { if ($temp != false) {
$csr = $temp; $spkac = $temp;
} }
$orig = $csr; $orig = $spkac;
if ($csr === false) { if ($spkac === false) {
$this->currentCert = false; $this->currentCert = false;
return false; return false;
} }
$asn1->loadOIDs($this->oids); $asn1->loadOIDs($this->oids);
$decoded = $asn1->decodeBER($csr); $decoded = $asn1->decodeBER($spkac);
if (empty($decoded)) { if (empty($decoded)) {
$this->currentCert = false; $this->currentCert = false;
return 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; $this->currentCert = false;
return false; return false;
} }
$this->signatureSubject = substr($orig, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']); $this->signatureSubject = substr($orig, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']);
$algorithm = &$csr['publicKeyAndChallenge']['spki']['algorithm']['algorithm']; $algorithm = &$spkac['publicKeyAndChallenge']['spki']['algorithm']['algorithm'];
$key = &$csr['publicKeyAndChallenge']['spki']['subjectPublicKey']; $key = &$spkac['publicKeyAndChallenge']['spki']['subjectPublicKey'];
$key = $this->_reformatKey($algorithm, $key); $key = $this->_reformatKey($algorithm, $key);
switch ($algorithm) { switch ($algorithm) {
@ -2978,9 +3001,9 @@ class File_X509 {
} }
$this->currentKeyIdentifier = NULL; $this->currentKeyIdentifier = NULL;
$this->currentCert = $csr; $this->currentCert = $spkac;
return $csr; return $spkac;
} }
/** /**
@ -3000,11 +3023,7 @@ class File_X509 {
$asn1 = new File_ASN1(); $asn1 = new File_ASN1();
$temp = preg_replace('#^(?:[^-].+[\r\n]+)+|-.+-|[\r\n]| #', '', $crl); $crl = $this->_extractBER($crl);
$temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? base64_decode($temp) : false;
if ($temp != false) {
$crl = $temp;
}
$orig = $crl; $orig = $crl;
if ($crl === false) { if ($crl === false) {
@ -3209,9 +3228,29 @@ class File_X509 {
$this->setExtension('id-ce-subjectKeyIdentifier', $subject->currentKeyIdentifier); $this->setExtension('id-ce-subjectKeyIdentifier', $subject->currentKeyIdentifier);
} }
$altName = array();
if (isset($subject->domains) && count($subject->domains) > 1) { if (isset($subject->domains) && count($subject->domains) > 1) {
$this->setExtension('id-ce-subjectAltName', $altName = array_map(array('File_X509', '_dnsName'), $subject->domains);
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) { if ($this->caFlag) {
@ -4012,12 +4051,29 @@ class File_X509 {
case !is_object($key): case !is_object($key):
return false; return false;
case strtolower(get_class($key)) == 'file_asn1_element': case strtolower(get_class($key)) == 'file_asn1_element':
// Assume the element is a bitstring-packed key.
$asn1 = new File_ASN1(); $asn1 = new File_ASN1();
$decoded = $asn1->decodeBER($cert); $decoded = $asn1->decodeBER($key->element);
if (empty($decoded)) { if (empty($decoded)) {
return false; 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; break;
case strtolower(get_class($key)) == 'file_x509': case strtolower(get_class($key)) == 'file_x509':
if (isset($key->publicKey)) { if (isset($key->publicKey)) {
@ -4036,9 +4092,7 @@ class File_X509 {
} }
// If in PEM format, convert to binary. // If in PEM format, convert to binary.
if (preg_match('#^-----BEGIN #', $key)) { $key = $this->_extractBER($key);
$key = base64_decode(preg_replace('#-.+-|[\r\n]#', '', $key));
}
// Now we have the key string: compute its sha-1 sum. // Now we have the key string: compute its sha-1 sum.
if (!class_exists('Crypt_Hash')) { if (!class_exists('Crypt_Hash')) {
@ -4094,6 +4148,23 @@ class File_X509 {
$this->setDNProp('id-at-commonName', $this->domains[0]); $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 * Helper function to build domain array
* *
@ -4106,6 +4177,20 @@ class File_X509 {
return array('dNSName' => $domain); 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. * Get the index of a revoked certificate.
* *
@ -4320,4 +4405,31 @@ class File_X509 {
return false; 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;
}
} }

View File

@ -70,7 +70,6 @@
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @copyright MMVI Jim Wigginton * @copyright MMVI Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @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 * @link http://pear.php.net/package/Math_BigInteger
*/ */
@ -162,16 +161,6 @@ define('MATH_BIGINTEGER_MODE_BCMATH', 2);
define('MATH_BIGINTEGER_MODE_GMP', 3); 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 * Karatsuba Cutoff
* *
@ -232,7 +221,7 @@ class Math_BigInteger {
var $bitmask = false; 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 * 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, * 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; 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 * 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. * two's compliment. The sole exception to this is -10, which is treated the same as 10 is.
* *
* Here's an example: * Here's an example:
* <code> * <code>
* <?php * &lt;?php
* include('Math/BigInteger.php'); * include('Math/BigInteger.php');
* *
* $a = new Math_BigInteger('0x32', 16); // 50 in base-16 * $a = new Math_BigInteger('0x32', 16); // 50 in base-16
* *
* echo $a->toString(); // outputs 50 * echo $a->toString(); // outputs 50
* ?> * ?&gt;
* </code> * </code>
* *
* @param optional $x base-10 number or base-$base number if $base set. * @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')) { if (function_exists('openssl_public_encrypt') && !defined('MATH_BIGINTEGER_OPENSSL_DISABLE') && !defined('MATH_BIGINTEGER_OPENSSL_ENABLED')) {
// 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); 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 ) { 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) // converts a base-2**8 (big endian / msb) number to base-2**26 (little endian / lsb)
default: default:
while (strlen($x)) { 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; break;
case 10: case 10:
case -10: case -10:
$x = preg_replace('#^(-?[0-9]*).*#', '$1', $x); // (?<!^)(?:-).*: find any -'s that aren't at the beginning and then any characters that follow that
// (?<=^|-)0*: find any 0's that are preceded by the start of the string or by a - (ie. octals)
// [^-0-9].*: find any non-numeric characters and then any characters that follow that
$x = preg_replace('#(?<!^)(?:-).*|(?<=^|-)0*|[^-0-9].*#', '', $x);
switch ( MATH_BIGINTEGER_MODE ) { switch ( MATH_BIGINTEGER_MODE ) {
case MATH_BIGINTEGER_MODE_GMP: case MATH_BIGINTEGER_MODE_GMP:
@ -399,26 +448,24 @@ class Math_BigInteger {
case MATH_BIGINTEGER_MODE_BCMATH: case MATH_BIGINTEGER_MODE_BCMATH:
// explicitly casting $x to a string is necessary, here, since doing $x[0] on -1 yields different // explicitly casting $x to a string is necessary, here, since doing $x[0] on -1 yields different
// results then doing it on '-1' does (modInverse does $x[0]) // results then doing it on '-1' does (modInverse does $x[0])
$this->value = (string) $x; $this->value = $x === '-' ? '0' : (string) $x;
break; break;
default: default:
$temp = new Math_BigInteger(); $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 = new Math_BigInteger();
$multiplier->value = array(10000000); $multiplier->value = array(MATH_BIGINTEGER_MAX10);
if ($x[0] == '-') { if ($x[0] == '-') {
$this->is_negative = true; $this->is_negative = true;
$x = substr($x, 1); $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)) { while (strlen($x)) {
$temp = $temp->multiply($multiplier); $temp = $temp->multiply($multiplier);
$temp = $temp->add(new Math_BigInteger($this->_int2bytes(substr($x, 0, 7)), 256)); $temp = $temp->add(new Math_BigInteger($this->_int2bytes(substr($x, 0, MATH_BIGINTEGER_MAX10_LEN)), 256));
$x = substr($x, 7); $x = substr($x, MATH_BIGINTEGER_MAX10_LEN);
} }
$this->value = $temp->value; $this->value = $temp->value;
@ -543,7 +590,7 @@ class Math_BigInteger {
$temp = $this->copy(); $temp = $this->copy();
for ($i = count($temp->value) - 2; $i >= 0; --$i) { 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); $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; $temp->is_negative = false;
$divisor = new Math_BigInteger(); $divisor = new Math_BigInteger();
$divisor->value = array(10000000); // eg. 10**7 $divisor->value = array(MATH_BIGINTEGER_MAX10);
$result = ''; $result = '';
while (count($temp->value)) { while (count($temp->value)) {
list($temp, $mod) = $temp->divide($divisor); 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'); $result = ltrim($result, '0');
if (empty($result)) { if (empty($result)) {
@ -874,25 +921,25 @@ class Math_BigInteger {
$carry = 0; $carry = 0;
for ($i = 0, $j = 1; $j < $size; $i+=2, $j+=2) { 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; $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_DIGIT52; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1 $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_DIGIT52 : $sum; $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; $value[$j] = $temp;
} }
if ($j == $size) { // ie. if $y_size is odd if ($j == $size) { // ie. if $y_size is odd
$sum = $x_value[$i] + $y_value[$i] + $carry; $sum = $x_value[$i] + $y_value[$i] + $carry;
$carry = $sum >= 0x4000000; $carry = $sum >= MATH_BIGINTEGER_BASE_FULL;
$value[$i] = $carry ? $sum - 0x4000000 : $sum; $value[$i] = $carry ? $sum - MATH_BIGINTEGER_BASE_FULL : $sum;
++$i; // ie. let $i = $j since we've just done $value[$i] ++$i; // ie. let $i = $j since we've just done $value[$i]
} }
if ($carry) { if ($carry) {
for (; $value[$i] == 0x3FFFFFF; ++$i) { for (; $value[$i] == MATH_BIGINTEGER_MAX_DIGIT; ++$i) {
$value[$i] = 0; $value[$i] = 0;
} }
++$value[$i]; ++$value[$i];
@ -1010,26 +1057,26 @@ class Math_BigInteger {
$carry = 0; $carry = 0;
for ($i = 0, $j = 1; $j < $y_size; $i+=2, $j+=2) { 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 $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; $x_value[$j] = $temp;
} }
if ($j == $y_size) { // ie. if $y_size is odd if ($j == $y_size) { // ie. if $y_size is odd
$sum = $x_value[$i] - $y_value[$i] - $carry; $sum = $x_value[$i] - $y_value[$i] - $carry;
$carry = $sum < 0; $carry = $sum < 0;
$x_value[$i] = $carry ? $sum + 0x4000000 : $sum; $x_value[$i] = $carry ? $sum + MATH_BIGINTEGER_BASE_FULL : $sum;
++$i; ++$i;
} }
if ($carry) { if ($carry) {
for (; !$x_value[$i]; ++$i) { for (; !$x_value[$i]; ++$i) {
$x_value[$i] = 0x3FFFFFF; $x_value[$i] = MATH_BIGINTEGER_MAX_DIGIT;
} }
--$x_value[$i]; --$x_value[$i];
} }
@ -1162,8 +1209,8 @@ class Math_BigInteger {
for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0 for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0
$temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0 $temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0
$carry = (int) ($temp / 0x4000000); $carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL);
$product_value[$j] = (int) ($temp - 0x4000000 * $carry); $product_value[$j] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
} }
$product_value[$j] = $carry; $product_value[$j] = $carry;
@ -1175,8 +1222,8 @@ class Math_BigInteger {
for ($j = 0, $k = $i; $j < $x_length; ++$j, ++$k) { for ($j = 0, $k = $i; $j < $x_length; ++$j, ++$k) {
$temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry; $temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry;
$carry = (int) ($temp / 0x4000000); $carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL);
$product_value[$k] = (int) ($temp - 0x4000000 * $carry); $product_value[$k] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
} }
$product_value[$k] = $carry; $product_value[$k] = $carry;
@ -1263,14 +1310,14 @@ class Math_BigInteger {
$i2 = $i << 1; $i2 = $i << 1;
$temp = $square_value[$i2] + $value[$i] * $value[$i]; $temp = $square_value[$i2] + $value[$i] * $value[$i];
$carry = (int) ($temp / 0x4000000); $carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL);
$square_value[$i2] = (int) ($temp - 0x4000000 * $carry); $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. // 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) { for ($j = $i + 1, $k = $i2 + 1; $j <= $max_index; ++$j, ++$k) {
$temp = $square_value[$k] + 2 * $value[$j] * $value[$i] + $carry; $temp = $square_value[$k] + 2 * $value[$j] * $value[$i] + $carry;
$carry = (int) ($temp / 0x4000000); $carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL);
$square_value[$k] = (int) ($temp - 0x4000000 * $carry); $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 // 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 // normalize $x and $y as described in HAC 14.23 / 14.24
$msb = $y->value[count($y->value) - 1]; $msb = $y->value[count($y->value) - 1];
for ($shift = 0; !($msb & 0x2000000); ++$shift) { for ($shift = 0; !($msb & MATH_BIGINTEGER_MSB); ++$shift) {
$msb <<= 1; $msb <<= 1;
} }
$x->_lshift($shift); $x->_lshift($shift);
@ -1465,10 +1512,10 @@ class Math_BigInteger {
$q_index = $i - $y_max - 1; $q_index = $i - $y_max - 1;
if ($x_window[0] == $y_window[0]) { if ($x_window[0] == $y_window[0]) {
$quotient_value[$q_index] = 0x3FFFFFF; $quotient_value[$q_index] = MATH_BIGINTEGER_MAX_DIGIT;
} else { } else {
$quotient_value[$q_index] = (int) ( $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] $y_window[0]
); );
@ -1536,7 +1583,7 @@ class Math_BigInteger {
$result = array(); $result = array();
for ($i = count($dividend) - 1; $i >= 0; --$i) { 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); $result[$i] = (int) ($temp / $divisor);
$carry = (int) ($temp - $divisor * $result[$i]); $carry = (int) ($temp - $divisor * $result[$i]);
} }
@ -1754,7 +1801,7 @@ class Math_BigInteger {
$e_length = count($e_value) - 1; $e_length = count($e_value) - 1;
$e_bits = decbin($e_value[$e_length]); $e_bits = decbin($e_value[$e_length]);
for ($i = $e_length - 1; $i >= 0; --$i) { 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); $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) { 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 = $this->_array_repeat(0, $n_length + 1);
$corrector_value[] = 1; $corrector_value[] = 1;
$result = $this->_add($result, false, $corrector, false); $result = $this->_add($result, false, $corrector_value, false);
$result = $result[MATH_BIGINTEGER_VALUE]; $result = $result[MATH_BIGINTEGER_VALUE];
} }
@ -2112,6 +2159,7 @@ class Math_BigInteger {
* @param Boolean $x_negative * @param Boolean $x_negative
* @param Array $y_value * @param Array $y_value
* @param Boolean $y_negative * @param Boolean $y_negative
* @param Integer $stop
* @return Array * @return Array
* @access private * @access private
*/ */
@ -2148,8 +2196,8 @@ class Math_BigInteger {
for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0, $k = $i for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0, $k = $i
$temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0 $temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0
$carry = (int) ($temp / 0x4000000); $carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL);
$product_value[$j] = (int) ($temp - 0x4000000 * $carry); $product_value[$j] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
} }
if ($j < $stop) { if ($j < $stop) {
@ -2164,8 +2212,8 @@ class Math_BigInteger {
for ($j = 0, $k = $i; $j < $x_length && $k < $stop; ++$j, ++$k) { for ($j = 0, $k = $i; $j < $x_length && $k < $stop; ++$j, ++$k) {
$temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry; $temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry;
$carry = (int) ($temp / 0x4000000); $carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL);
$product_value[$k] = (int) ($temp - 0x4000000 * $carry); $product_value[$k] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
} }
if ($k < $stop) { if ($k < $stop) {
@ -2213,7 +2261,7 @@ class Math_BigInteger {
for ($i = 0; $i < $k; ++$i) { for ($i = 0; $i < $k; ++$i) {
$temp = $result[MATH_BIGINTEGER_VALUE][$i] * $cache[MATH_BIGINTEGER_DATA][$key]; $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 = $this->_regularMultiply(array($temp), $n);
$temp = array_merge($this->_array_repeat(0, $i), $temp); $temp = array_merge($this->_array_repeat(0, $i), $temp);
$result = $this->_add($result[MATH_BIGINTEGER_VALUE], false, $temp, false); $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)); $a = array(MATH_BIGINTEGER_VALUE => $this->_array_repeat(0, $n + 1));
for ($i = 0; $i < $n; ++$i) { for ($i = 0; $i < $n; ++$i) {
$temp = $a[MATH_BIGINTEGER_VALUE][0] + $x[$i] * $y[0]; $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 = $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); $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 = $this->_add($a[MATH_BIGINTEGER_VALUE], false, $temp[MATH_BIGINTEGER_VALUE], false);
$a[MATH_BIGINTEGER_VALUE] = array_slice($a[MATH_BIGINTEGER_VALUE], 1); $a[MATH_BIGINTEGER_VALUE] = array_slice($a[MATH_BIGINTEGER_VALUE], 1);
@ -2325,15 +2373,15 @@ class Math_BigInteger {
* @param Array $x * @param Array $x
* @return Integer * @return Integer
*/ */
function _modInverse67108864($x) // 2**26 == 67108864 function _modInverse67108864($x) // 2**26 == 67,108,864
{ {
$x = -$x[0]; $x = -$x[0];
$result = $x & 0x3; // x**-1 mod 2**2 $result = $x & 0x3; // x**-1 mod 2**2
$result = ($result * (2 - $x * $result)) & 0xF; // x**-1 mod 2**4 $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 & 0xFF) * $result)) & 0xFF; // x**-1 mod 2**8
$result = ($result * ((2 - ($x & 0xFFFF) * $result) & 0xFFFF)) & 0xFFFF; // x**-1 mod 2**16 $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 $result = fmod($result * (2 - fmod($x * $result, MATH_BIGINTEGER_BASE_FULL)), MATH_BIGINTEGER_BASE_FULL); // x**-1 mod 2**26
return $result & 0x3FFFFFF; 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 * 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 * 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: * Here's an example:
* <code> * <code>
@ -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). * Note how the same comparison operator is used. If you want to test for equality, use $x->equals($y).
* *
* @param Math_BigInteger $x * @param Math_BigInteger $y
* @return Integer < 0 if $this is less than $x; > 0 if $this is greater than $x, and 0 if they are equal. * @return Integer < 0 if $this is less than $y; > 0 if $this is greater than $y, and 0 if they are equal.
* @access public * @access public
* @see equals() * @see equals()
* @internal Could return $this->subtract($x), but that's not as fast as what we do do. * @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 * Some bitwise operations give different results depending on the precision being used. Examples include left
* shift, not, and rotates. * shift, not, and rotates.
* *
* @param Math_BigInteger $x * @param Integer $bits
* @access public * @access public
* @return Math_BigInteger
*/ */
function setPrecision($bits) function setPrecision($bits)
{ {
@ -2736,7 +2783,7 @@ class Math_BigInteger {
$result->value = array_slice($result->value, 0, $length); $result->value = array_slice($result->value, 0, $length);
for ($i = 0; $i < $length; ++$i) { 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); return $this->_normalize($result);
@ -2772,11 +2819,11 @@ class Math_BigInteger {
$length = max(count($this->value), count($x->value)); $length = max(count($this->value), count($x->value));
$result = $this->copy(); $result = $this->copy();
$result->value = array_pad($result->value, 0, $length); $result->value = array_pad($result->value, $length, 0);
$x->value = array_pad($x->value, 0, $length); $x->value = array_pad($x->value, $length, 0);
for ($i = 0; $i < $length; ++$i) { 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); return $this->_normalize($result);
@ -2812,11 +2859,11 @@ class Math_BigInteger {
$length = max(count($this->value), count($x->value)); $length = max(count($this->value), count($x->value));
$result = $this->copy(); $result = $this->copy();
$result->value = array_pad($result->value, 0, $length); $result->value = array_pad($result->value, $length, 0);
$x->value = array_pad($x->value, 0, $length); $x->value = array_pad($x->value, $length, 0);
for ($i = 0; $i < $length; ++$i) { 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); 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 * Generate a random number
* *
@ -3033,48 +3111,45 @@ class Math_BigInteger {
$min = $temp; $min = $temp;
} }
$generator = $this->generator; static $one;
if (!isset($one)) {
$max = $max->subtract($min); $one = new Math_BigInteger(1);
$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; $max = $max->subtract($min->subtract($one));
for ($i = 0; $i < $blocks; ++$i) { $size = strlen(ltrim($max->toBytes(), chr(0)));
// mt_rand(-2147483648, 0x7FFFFFFF) always produces -2147483648 on some systems
$random.= pack('n', mt_rand(0, 0xFFFF));
}
}
$fragment = new Math_BigInteger($random, 256); /*
$leading = $fragment->compare(new Math_BigInteger(substr($max, 1), 256)) > 0 ? doing $random % $max doesn't work because some numbers will be more likely to occur than others.
ord($max[0]) - 1 : ord($max[0]); 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.
if (!$crypt_random) { creating a whole new random number until you find one that is within the range doesn't work
$msb = chr(mt_rand(0, $leading)); because, for sufficiently small ranges, the likelihood that you'd get a number within that range
} else { would be pretty small. eg. with $random's max being 255 and if your $max being 1 the probability
$cutoff = floor(0xFF / $leading) * $leading; would be pretty high that $random would be greater than $max.
while (true) {
$msb = ord(crypt_random_string(1));
if ($msb <= $cutoff) {
$msb%= $leading;
break;
}
}
$msb = chr($msb);
}
$random = new Math_BigInteger($msb . $random, 256); 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);
}
list(, $random) = $random->divide($max);
return $this->_normalize($random->add($min)); return $this->_normalize($random->add($min));
} }
@ -3094,22 +3169,6 @@ class Math_BigInteger {
*/ */
function randomPrime($min = false, $max = false, $timeout = false) function randomPrime($min = false, $max = false, $timeout = false)
{ {
$compare = $max->compare($min);
if (!$compare) {
return $min;
} else if ($compare < 0) {
// if $min is bigger then $max, swap $min and $max
$temp = $max;
$max = $min;
$min = $temp;
}
// gmp_nextprime() requires PHP 5 >= 5.2.0 per <http://php.net/gmp-nextprime>.
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) { if ($min === false) {
$min = new Math_BigInteger(0); $min = new Math_BigInteger(0);
} }
@ -3118,21 +3177,15 @@ class Math_BigInteger {
$max = new Math_BigInteger(0x7FFFFFFF); $max = new Math_BigInteger(0x7FFFFFFF);
} }
$x = $this->random($min, $max); $compare = $max->compare($min);
$x->value = gmp_nextprime($x->value); if (!$compare) {
return $min->isPrime() ? $min : false;
if ($x->compare($max) <= 0) { } else if ($compare < 0) {
return $x; // if $min is bigger then $max, swap $min and $max
} $temp = $max;
$max = $min;
$x->value = gmp_nextprime($min->value); $min = $temp;
if ($x->compare($max) <= 0) {
return $x;
}
return false;
} }
static $one, $two; static $one, $two;
@ -3144,6 +3197,23 @@ class Math_BigInteger {
$start = time(); $start = time();
$x = $this->random($min, $max); $x = $this->random($min, $max);
// gmp_nextprime() requires PHP 5 >= 5.2.0 per <http://php.net/gmp-nextprime>.
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)) { if ($x->equals($two)) {
return $x; return $x;
} }
@ -3375,16 +3445,16 @@ class Math_BigInteger {
return; return;
} }
$num_digits = (int) ($shift / 26); $num_digits = (int) ($shift / MATH_BIGINTEGER_BASE);
$shift %= 26; $shift %= MATH_BIGINTEGER_BASE;
$shift = 1 << $shift; $shift = 1 << $shift;
$carry = 0; $carry = 0;
for ($i = 0; $i < count($this->value); ++$i) { for ($i = 0; $i < count($this->value); ++$i) {
$temp = $this->value[$i] * $shift + $carry; $temp = $this->value[$i] * $shift + $carry;
$carry = (int) ($temp / 0x4000000); $carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL);
$this->value[$i] = (int) ($temp - $carry * 0x4000000); $this->value[$i] = (int) ($temp - $carry * MATH_BIGINTEGER_BASE_FULL);
} }
if ( $carry ) { if ( $carry ) {
@ -3410,9 +3480,9 @@ class Math_BigInteger {
return; return;
} }
$num_digits = (int) ($shift / 26); $num_digits = (int) ($shift / MATH_BIGINTEGER_BASE);
$shift %= 26; $shift %= MATH_BIGINTEGER_BASE;
$carry_shift = 26 - $shift; $carry_shift = MATH_BIGINTEGER_BASE - $shift;
$carry_mask = (1 << $shift) - 1; $carry_mask = (1 << $shift) - 1;
if ( $num_digits ) { if ( $num_digits ) {
@ -3485,6 +3555,7 @@ class Math_BigInteger {
* *
* Removes leading zeros * Removes leading zeros
* *
* @param Array $value
* @return Math_BigInteger * @return Math_BigInteger
* @access private * @access private
*/ */

View File

@ -0,0 +1,362 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* Pure-PHP implementation of SCP.
*
* PHP versions 4 and 5
*
* The API for this library is modeled after the API from PHP's {@link http://php.net/book.ftp FTP extension}.
*
* Here's a short example of how to use this library:
* <code>
* <?php
* include('Net/SCP.php');
* include('Net/SSH2.php');
*
* $ssh = new Net_SSH2('www.domain.tld');
* if (!$ssh->login('username', 'password')) {
* exit('bad login');
* }
* $scp = new Net_SCP($ssh);
* $scp->put('abcd', str_repeat('x', 1024*1024));
* ?>
* </code>
*
* 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 <terrafrost@php.net>
* @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 <terrafrost@php.net>
* @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('#(?<perms>[^ ]+) (?<size>\d+) (?<name>.+)#', 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();
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,771 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* SFTP Stream Wrapper
*
* Creates an sftp:// protocol handler that can be used with, for example, fopen(), dir(), etc.
*
* PHP version 5
*
* 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_SFTP_Stream
* @author Jim Wigginton <terrafrost@php.net>
* @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 <terrafrost@php.net>
* @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 <http://php.net/streamwrapper.rmdir>, however,
* <http://php.net/rmdir> 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 <http://php.net/fflush>. 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');
}

View File

@ -62,56 +62,9 @@
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @copyright MMVII Jim Wigginton * @copyright MMVII Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @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 * @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 * Encryption Methods
* *
@ -495,6 +448,19 @@ class Net_SSH1 {
*/ */
function Net_SSH1($host, $port = 22, $timeout = 10, $cipher = NET_SSH1_CIPHER_3DES) 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( $this->protocol_flags = array(
1 => 'NET_SSH1_MSG_DISCONNECT', 1 => 'NET_SSH1_MSG_DISCONNECT',
2 => 'NET_SSH1_SMSG_PUBLIC_KEY', 2 => 'NET_SSH1_SMSG_PUBLIC_KEY',
@ -636,18 +602,27 @@ class Net_SSH1 {
// $this->crypto = new Crypt_Null(); // $this->crypto = new Crypt_Null();
// break; // break;
case NET_SSH1_CIPHER_DES: case NET_SSH1_CIPHER_DES:
if (!class_exists('Crypt_DES')) {
require_once('Crypt/DES.php');
}
$this->crypto = new Crypt_DES(); $this->crypto = new Crypt_DES();
$this->crypto->disablePadding(); $this->crypto->disablePadding();
$this->crypto->enableContinuousBuffer(); $this->crypto->enableContinuousBuffer();
$this->crypto->setKey(substr($session_key, 0, 8)); $this->crypto->setKey(substr($session_key, 0, 8));
break; break;
case NET_SSH1_CIPHER_3DES: 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 = new Crypt_TripleDES(CRYPT_DES_MODE_3CBC);
$this->crypto->disablePadding(); $this->crypto->disablePadding();
$this->crypto->enableContinuousBuffer(); $this->crypto->enableContinuousBuffer();
$this->crypto->setKey(substr($session_key, 0, 24)); $this->crypto->setKey(substr($session_key, 0, 24));
break; break;
//case NET_SSH1_CIPHER_RC4: //case NET_SSH1_CIPHER_RC4:
// if (!class_exists('Crypt_RC4')) {
// require_once('Crypt/RC4.php');
// }
// $this->crypto = new Crypt_RC4(); // $this->crypto = new Crypt_RC4();
// $this->crypto->enableContinuousBuffer(); // $this->crypto->enableContinuousBuffer();
// $this->crypto->setKey(substr($session_key, 0, 16)); // $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. * 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 * 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 * {@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, * 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. * there's not going to be much recourse.

File diff suppressed because it is too large Load Diff

View File

@ -130,7 +130,7 @@ class smb {
// this put env is necessary to read the output of smbclient correctly // this put env is necessary to read the output of smbclient correctly
$old_locale = getenv('LC_ALL'); $old_locale = getenv('LC_ALL');
putenv('LC_ALL=en_US.UTF-8'); putenv('LC_ALL=en_US.UTF-8');
$output = popen (SMB4PHP_SMBCLIENT." -N {$auth} {$options} {$port} {$options} {$params} 2>/dev/null", 'r'); $output = popen ('TZ=UTC '.SMB4PHP_SMBCLIENT." -N {$auth} {$options} {$port} {$options} {$params} 2>/dev/null", 'r');
$gotInfo = false; $gotInfo = false;
$info = array (); $info = array ();
$info['info']= array (); $info['info']= array ();

View File

@ -9,6 +9,7 @@
OC::$CLASSPATH['OC\Files\Storage\StreamWrapper'] = 'files_external/lib/streamwrapper.php'; OC::$CLASSPATH['OC\Files\Storage\StreamWrapper'] = 'files_external/lib/streamwrapper.php';
OC::$CLASSPATH['OC\Files\Storage\FTP'] = 'files_external/lib/ftp.php'; OC::$CLASSPATH['OC\Files\Storage\FTP'] = 'files_external/lib/ftp.php';
OC::$CLASSPATH['OC\Files\Storage\DAV'] = 'files_external/lib/webdav.php'; OC::$CLASSPATH['OC\Files\Storage\DAV'] = 'files_external/lib/webdav.php';
OC::$CLASSPATH['OC\Files\Storage\OwnCloud'] = 'files_external/lib/owncloud.php';
OC::$CLASSPATH['OC\Files\Storage\Google'] = 'files_external/lib/google.php'; OC::$CLASSPATH['OC\Files\Storage\Google'] = 'files_external/lib/google.php';
OC::$CLASSPATH['OC\Files\Storage\Swift'] = 'files_external/lib/swift.php'; OC::$CLASSPATH['OC\Files\Storage\Swift'] = 'files_external/lib/swift.php';
OC::$CLASSPATH['OC\Files\Storage\SMB'] = 'files_external/lib/smb.php'; OC::$CLASSPATH['OC\Files\Storage\SMB'] = 'files_external/lib/smb.php';

View File

@ -12,8 +12,8 @@ span.error {
background: #ce3702; background: #ce3702;
} }
td.mountPoint, td.backend { width:10em; } td.mountPoint, td.backend { width:160px; }
td.remove>img { visibility:hidden; padding-top:0.8em; } td.remove>img { visibility:hidden; padding-top:13px; }
tr:hover>td.remove>img { visibility:visible; cursor:pointer; } tr:hover>td.remove>img { visibility:visible; cursor:pointer; }
#addMountPoint>td { border:none; } #addMountPoint>td { border:none; }
#addMountPoint>td.applicable { visibility:hidden; } #addMountPoint>td.applicable { visibility:hidden; }

View File

@ -23,9 +23,12 @@ $(document).ready(function() {
$(token).val(result.access_token); $(token).val(result.access_token);
$(token_secret).val(result.access_token_secret); $(token_secret).val(result.access_token_secret);
$(configured).val('true'); $(configured).val('true');
OC.MountConfig.saveStorage(tr); OC.MountConfig.saveStorage(tr, function(status) {
if (status) {
$(tr).find('.configuration input').attr('disabled', 'disabled'); $(tr).find('.configuration input').attr('disabled', 'disabled');
$(tr).find('.configuration').append('<span id="access" style="padding-left:0.5em;">'+t('files_external', 'Access granted')+'</span>'); $(tr).find('.configuration').append('<span id="access" style="padding-left:0.5em;">'+t('files_external', 'Access granted')+'</span>');
}
});
} else { } else {
OC.dialogs.alert(result.data.message, t('files_external', 'Error configuring Dropbox storage')); OC.dialogs.alert(result.data.message, t('files_external', 'Error configuring Dropbox storage'));
} }
@ -77,7 +80,6 @@ $(document).ready(function() {
var tr = $(this).parent().parent(); var tr = $(this).parent().parent();
var app_key = $(this).parent().find('[data-parameter="app_key"]').val(); var app_key = $(this).parent().find('[data-parameter="app_key"]').val();
var app_secret = $(this).parent().find('[data-parameter="app_secret"]').val(); var app_secret = $(this).parent().find('[data-parameter="app_secret"]').val();
var statusSpan = $(tr).find('.status span');
if (app_key != '' && app_secret != '') { if (app_key != '' && app_secret != '') {
var tr = $(this).parent().parent(); var tr = $(this).parent().parent();
var configured = $(this).parent().find('[data-parameter="configured"]'); var configured = $(this).parent().find('[data-parameter="configured"]');
@ -88,10 +90,9 @@ $(document).ready(function() {
$(configured).val('false'); $(configured).val('false');
$(token).val(result.data.request_token); $(token).val(result.data.request_token);
$(token_secret).val(result.data.request_token_secret); $(token_secret).val(result.data.request_token_secret);
OC.MountConfig.saveStorage(tr); OC.MountConfig.saveStorage(tr, function() {
statusSpan.removeClass();
statusSpan.addClass('waiting');
window.location = result.data.url; window.location = result.data.url;
});
} else { } else {
OC.dialogs.alert(result.data.message, t('files_external', 'Error configuring Dropbox storage')); OC.dialogs.alert(result.data.message, t('files_external', 'Error configuring Dropbox storage'));
} }

View File

@ -32,11 +32,14 @@ $(document).ready(function() {
if (result && result.status == 'success') { if (result && result.status == 'success') {
$(token).val(result.data.token); $(token).val(result.data.token);
$(configured).val('true'); $(configured).val('true');
OC.MountConfig.saveStorage(tr); OC.MountConfig.saveStorage(tr, function(status) {
if (status) {
$(tr).find('.configuration input').attr('disabled', 'disabled'); $(tr).find('.configuration input').attr('disabled', 'disabled');
$(tr).find('.configuration').append($('<span/>') $(tr).find('.configuration').append($('<span/>')
.attr('id', 'access') .attr('id', 'access')
.text(t('files_external', 'Access granted'))); .text(t('files_external', 'Access granted')));
}
});
} else { } else {
OC.dialogs.alert(result.data.message, OC.dialogs.alert(result.data.message,
t('files_external', 'Error configuring Google Drive storage') t('files_external', 'Error configuring Google Drive storage')
@ -99,7 +102,6 @@ $(document).ready(function() {
var configured = $(this).parent().find('[data-parameter="configured"]'); var configured = $(this).parent().find('[data-parameter="configured"]');
var client_id = $(this).parent().find('[data-parameter="client_id"]').val(); var client_id = $(this).parent().find('[data-parameter="client_id"]').val();
var client_secret = $(this).parent().find('[data-parameter="client_secret"]').val(); var client_secret = $(this).parent().find('[data-parameter="client_secret"]').val();
var statusSpan = $(tr).find('.status span');
if (client_id != '' && client_secret != '') { if (client_id != '' && client_secret != '') {
var token = $(this).parent().find('[data-parameter="token"]'); var token = $(this).parent().find('[data-parameter="token"]');
$.post(OC.filePath('files_external', 'ajax', 'google.php'), $.post(OC.filePath('files_external', 'ajax', 'google.php'),
@ -112,10 +114,9 @@ $(document).ready(function() {
if (result && result.status == 'success') { if (result && result.status == 'success') {
$(configured).val('false'); $(configured).val('false');
$(token).val('false'); $(token).val('false');
OC.MountConfig.saveStorage(tr); OC.MountConfig.saveStorage(tr, function(status) {
statusSpan.removeClass();
statusSpan.addClass('waiting');
window.location = result.data.url; window.location = result.data.url;
});
} else { } else {
OC.dialogs.alert(result.data.message, OC.dialogs.alert(result.data.message,
t('files_external', 'Error configuring Google Drive storage') t('files_external', 'Error configuring Google Drive storage')

View File

@ -12,7 +12,7 @@ function updateStatus(statusEl, result){
} }
OC.MountConfig={ OC.MountConfig={
saveStorage:function(tr) { saveStorage:function(tr, callback) {
var mountPoint = $(tr).find('.mountPoint input').val(); var mountPoint = $(tr).find('.mountPoint input').val();
if (mountPoint == '') { if (mountPoint == '') {
return false; return false;
@ -84,9 +84,15 @@ OC.MountConfig={
}, },
success: function(result) { success: function(result) {
status = updateStatus(statusSpan, result); status = updateStatus(statusSpan, result);
if (callback) {
callback(status);
}
}, },
error: function(result){ error: function(result){
status = updateStatus(statusSpan, result); status = updateStatus(statusSpan, result);
if (callback) {
callback(status);
}
} }
}); });
}); });
@ -137,9 +143,15 @@ OC.MountConfig={
}, },
success: function(result) { success: function(result) {
status = updateStatus(statusSpan, result); status = updateStatus(statusSpan, result);
if (callback) {
callback(status);
}
}, },
error: function(result){ error: function(result){
status = updateStatus(statusSpan, result); status = updateStatus(statusSpan, result);
if (callback) {
callback(status);
}
} }
}); });
} }

View File

@ -1,6 +0,0 @@
<?php
$TRANSLATIONS = array(
"Options" => "Опции",
"Delete" => "Удалить"
);
$PLURAL_FORMS = "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);";

View File

@ -61,7 +61,7 @@ class OC_Mount_Config {
'configuration' => array( 'configuration' => array(
'configured' => '#configured', 'configured' => '#configured',
'app_key' => 'App key', 'app_key' => 'App key',
'app_secret' => 'App secret', 'app_secret' => '*App secret',
'token' => '#token', 'token' => '#token',
'token_secret' => '#token_secret'), 'token_secret' => '#token_secret'),
'custom' => 'dropbox'); 'custom' => 'dropbox');
@ -80,7 +80,7 @@ class OC_Mount_Config {
'configuration' => array( 'configuration' => array(
'configured' => '#configured', 'configured' => '#configured',
'client_id' => 'Client ID', 'client_id' => 'Client ID',
'client_secret' => 'Client secret', 'client_secret' => '*Client secret',
'token' => '#token'), 'token' => '#token'),
'custom' => 'google'); 'custom' => 'google');
@ -114,14 +114,24 @@ class OC_Mount_Config {
} }
} }
if(OC_Mount_Config::checkcurl()) $backends['\OC\Files\Storage\DAV']=array( if(OC_Mount_Config::checkcurl()){
'backend' => 'ownCloud / WebDAV', $backends['\OC\Files\Storage\DAV']=array(
'backend' => 'WebDAV',
'configuration' => array( 'configuration' => array(
'host' => 'URL', 'host' => 'URL',
'user' => 'Username', 'user' => 'Username',
'password' => '*Password', 'password' => '*Password',
'root' => '&Root', 'root' => '&Root',
'secure' => '!Secure https://')); 'secure' => '!Secure https://'));
$backends['\OC\Files\Storage\OwnCloud']=array(
'backend' => 'ownCloud',
'configuration' => array(
'host' => 'URL',
'user' => 'Username',
'password' => '*Password',
'root' => '&Remote subfolder',
'secure' => '!Secure https://'));
}
$backends['\OC\Files\Storage\SFTP']=array( $backends['\OC\Files\Storage\SFTP']=array(
'backend' => 'SFTP', 'backend' => 'SFTP',
@ -382,8 +392,7 @@ class OC_Mount_Config {
* @return array * @return array
*/ */
public static function getCertificates() { public static function getCertificates() {
$view = \OCP\Files::getStorage('files_external'); $path=OC_User::getHome(OC_User::getUser()) . '/files_external/uploads/';
$path=\OCP\Config::getSystemValue('datadirectory').$view->getAbsolutePath("").'uploads/';
\OCP\Util::writeLog('files_external', 'checking path '.$path, \OCP\Util::INFO); \OCP\Util::writeLog('files_external', 'checking path '.$path, \OCP\Util::INFO);
if ( ! is_dir($path)) { if ( ! is_dir($path)) {
//path might not exist (e.g. non-standard OC_User::getHome() value) //path might not exist (e.g. non-standard OC_User::getHome() value)
@ -405,8 +414,7 @@ class OC_Mount_Config {
* creates certificate bundle * creates certificate bundle
*/ */
public static function createCertificateBundle() { public static function createCertificateBundle() {
$view = \OCP\Files::getStorage("files_external"); $path=OC_User::getHome(OC_User::getUser()) . '/files_external';
$path = \OCP\Config::getSystemValue('datadirectory').$view->getAbsolutePath("");
$certs = OC_Mount_Config::getCertificates(); $certs = OC_Mount_Config::getCertificates();
$fh_certs = fopen($path."/rootcerts.crt", 'w'); $fh_certs = fopen($path."/rootcerts.crt", 'w');

View File

@ -0,0 +1,51 @@
<?php
/**
* Copyright (c) 2013 Vincent Petry <pvince81@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
namespace OC\Files\Storage;
/**
* ownCloud backend for external storage based on DAV backend.
*
* The ownCloud URL consists of three parts:
* http://%host/%context/remote.php/webdav/%root
*
*/
class OwnCloud extends \OC\Files\Storage\DAV{
const OC_URL_SUFFIX = 'remote.php/webdav';
public function __construct($params) {
// extract context path from host if specified
// (owncloud install path on host)
$host = $params['host'];
$contextPath = '';
$hostSlashPos = strpos($host, '/');
if ($hostSlashPos !== false){
$contextPath = substr($host, $hostSlashPos);
$host = substr($host, 0, $hostSlashPos);
}
if (substr($contextPath , 1) !== '/'){
$contextPath .= '/';
}
if (isset($params['root'])){
$root = $params['root'];
if (substr($root, 1) !== '/'){
$root = '/' . $root;
}
}
else{
$root = '/';
}
$params['host'] = $host;
$params['root'] = $contextPath . self::OC_URL_SUFFIX . $root;
parent::__construct($params);
}
}

View File

@ -10,6 +10,7 @@ namespace OC\Files\Storage;
set_include_path(get_include_path() . PATH_SEPARATOR . set_include_path(get_include_path() . PATH_SEPARATOR .
\OC_App::getAppPath('files_external') . '/3rdparty/phpseclib/phpseclib'); \OC_App::getAppPath('files_external') . '/3rdparty/phpseclib/phpseclib');
require 'Net/SFTP.php'; require 'Net/SFTP.php';
require 'Net/SFTP/Stream.php';
class SFTP extends \OC\Files\Storage\Common { class SFTP extends \OC\Files\Storage\Common {
private $host; private $host;
@ -205,16 +206,6 @@ class SFTP extends \OC\Files\Storage\Common {
if ( !$this->file_exists($path)) { if ( !$this->file_exists($path)) {
return false; 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 'w':
case 'wb': case 'wb':
case 'a': case 'a':
@ -227,38 +218,14 @@ class SFTP extends \OC\Files\Storage\Common {
case 'x+': case 'x+':
case 'c': case 'c':
case 'c+': case 'c+':
if (strrpos($path, '.')!==false) { // FIXME: make client login lazy to prevent it when using fopen()
$ext=substr($path, strrpos($path, '.')); return fopen($this->constructUrl($path), $mode);
} 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);
} }
} catch (\Exception $e) { } catch (\Exception $e) {
} }
return false; return false;
} }
public function writeBack($tmpFile) {
if (array_key_exists($tmpFile, self::$tempFiles)) {
$this->uploadFile($tmpFile, self::$tempFiles[$tmpFile]);
unlink($tmpFile);
unset(self::$tempFiles[$tmpFile]);
}
}
public function touch($path, $mtime=null) { public function touch($path, $mtime=null) {
try { try {
if (!is_null($mtime)) { if (!is_null($mtime)) {
@ -309,4 +276,9 @@ class SFTP extends \OC\Files\Storage\Common {
return false; return false;
} }
} }
public function constructUrl($path) {
$url = 'sftp://'.$this->user.':'.$this->password.'@'.$this->host.$this->root.$path;
return $url;
}
} }

View File

@ -14,6 +14,7 @@ class DAV extends \OC\Files\Storage\Common{
private $host; private $host;
private $secure; private $secure;
private $root; private $root;
private $certPath;
private $ready; private $ready;
/** /**
* @var \Sabre_DAV_Client * @var \Sabre_DAV_Client
@ -40,6 +41,12 @@ class DAV extends \OC\Files\Storage\Common{
} else { } else {
$this->secure = false; $this->secure = false;
} }
if ($this->secure === true) {
$certPath=\OC_User::getHome(\OC_User::getUser()) . '/files_external/rootcerts.crt';
if (file_exists($certPath)) {
$this->certPath=$certPath;
}
}
$this->root=isset($params['root'])?$params['root']:'/'; $this->root=isset($params['root'])?$params['root']:'/';
if ( ! $this->root || $this->root[0]!='/') { if ( ! $this->root || $this->root[0]!='/') {
$this->root='/'.$this->root; $this->root='/'.$this->root;
@ -66,12 +73,8 @@ class DAV extends \OC\Files\Storage\Common{
$this->client = new \Sabre_DAV_Client($settings); $this->client = new \Sabre_DAV_Client($settings);
$caview = \OCP\Files::getStorage('files_external'); if ($this->secure === true && $this->certPath) {
if ($caview) { $this->client->addTrustedCertificates($this->certPath);
$certPath=\OCP\Config::getSystemValue('datadirectory').$caview->getAbsolutePath("").'rootcerts.crt';
if (file_exists($certPath)) {
$this->client->addTrustedCertificates($certPath);
}
} }
} }
@ -79,7 +82,7 @@ class DAV extends \OC\Files\Storage\Common{
return 'webdav::' . $this->user . '@' . $this->host . '/' . $this->root; return 'webdav::' . $this->user . '@' . $this->host . '/' . $this->root;
} }
private function createBaseUri() { protected function createBaseUri() {
$baseUri='http'; $baseUri='http';
if ($this->secure) { if ($this->secure) {
$baseUri.='s'; $baseUri.='s';
@ -166,6 +169,13 @@ class DAV extends \OC\Files\Storage\Common{
curl_setopt($curl, CURLOPT_URL, $this->createBaseUri().str_replace(' ', '%20', $path)); curl_setopt($curl, CURLOPT_URL, $this->createBaseUri().str_replace(' ', '%20', $path));
curl_setopt($curl, CURLOPT_FILE, $fp); curl_setopt($curl, CURLOPT_FILE, $fp);
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
if ($this->secure === true) {
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);
if($this->certPath){
curl_setopt($curl, CURLOPT_CAINFO, $this->certPath);
}
}
curl_exec ($curl); curl_exec ($curl);
curl_close ($curl); curl_close ($curl);
@ -214,7 +224,7 @@ class DAV extends \OC\Files\Storage\Common{
if (isset($response['{DAV:}quota-available-bytes'])) { if (isset($response['{DAV:}quota-available-bytes'])) {
return (int)$response['{DAV:}quota-available-bytes']; return (int)$response['{DAV:}quota-available-bytes'];
} else { } else {
return 0; return \OC\Files\SPACE_UNKNOWN;
} }
} catch(\Exception $e) { } catch(\Exception $e) {
return \OC\Files\SPACE_UNKNOWN; return \OC\Files\SPACE_UNKNOWN;
@ -254,6 +264,13 @@ class DAV extends \OC\Files\Storage\Common{
curl_setopt($curl, CURLOPT_INFILE, $source); // file pointer curl_setopt($curl, CURLOPT_INFILE, $source); // file pointer
curl_setopt($curl, CURLOPT_INFILESIZE, filesize($path)); curl_setopt($curl, CURLOPT_INFILESIZE, filesize($path));
curl_setopt($curl, CURLOPT_PUT, true); curl_setopt($curl, CURLOPT_PUT, true);
if ($this->secure === true) {
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);
if($this->certPath){
curl_setopt($curl, CURLOPT_CAINFO, $this->certPath);
}
}
curl_exec ($curl); curl_exec ($curl);
curl_close ($curl); curl_close ($curl);
} }
@ -331,3 +348,4 @@ class DAV extends \OC\Files\Storage\Common{
} }
} }
} }

View File

@ -23,6 +23,13 @@ return array(
'password'=>'test', 'password'=>'test',
'root'=>'/owncloud/files/webdav.php', 'root'=>'/owncloud/files/webdav.php',
), ),
'owncloud'=>array(
'run'=>true,
'host'=>'localhost/owncloud',
'user'=>'test',
'password'=>'test',
'root'=>'',
),
'google'=>array( 'google'=>array(
'run'=> false, 'run'=> false,
'configured' => 'true', 'configured' => 'true',

View File

@ -0,0 +1,31 @@
<?php
/**
* Copyright (c) 2013 Vincent Petry <pvince81@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
namespace Test\Files\Storage;
class OwnCloud extends Storage {
private $config;
public function setUp() {
$id = uniqid();
$this->config = include('files_external/tests/config.php');
if ( ! is_array($this->config) or ! isset($this->config['owncloud']) or ! $this->config['owncloud']['run']) {
$this->markTestSkipped('ownCloud backend not configured');
}
$this->config['owncloud']['root'] .= '/' . $id; //make sure we have an new empty folder to work in
$this->instance = new \OC\Files\Storage\OwnCloud($this->config['owncloud']);
$this->instance->mkdir('/');
}
public function tearDown() {
if ($this->instance) {
$this->instance->rmdir('/');
}
}
}

View File

@ -39,6 +39,7 @@ if(!isset($linkedItem['uid_owner']) || !isset($linkedItem['file_source'])) {
$rootLinkItem = OCP\Share::resolveReShare($linkedItem); $rootLinkItem = OCP\Share::resolveReShare($linkedItem);
$userId = $rootLinkItem['uid_owner']; $userId = $rootLinkItem['uid_owner'];
OCP\JSON::checkUserExists($rootLinkItem['uid_owner']);
\OC_Util::setupFS($userId); \OC_Util::setupFS($userId);
\OC\Files\Filesystem::initMountPoints($userId); \OC\Files\Filesystem::initMountPoints($userId);
$view = new \OC\Files\View('/' . $userId . '/files'); $view = new \OC\Files\View('/' . $userId . '/files');

View File

@ -44,6 +44,7 @@ if (version_compare($installedVersion, '0.3', '<')) {
$shareType = OCP\Share::SHARE_TYPE_USER; $shareType = OCP\Share::SHARE_TYPE_USER;
$shareWith = $row['uid_shared_with']; $shareWith = $row['uid_shared_with'];
} }
OCP\JSON::checkUserExists($row['uid_owner']);
OC_User::setUserId($row['uid_owner']); OC_User::setUserId($row['uid_owner']);
//we need to setup the filesystem for the user, otherwise OC_FileSystem::getRoot will fail and break //we need to setup the filesystem for the user, otherwise OC_FileSystem::getRoot will fail and break
OC_Util::setupFS($row['uid_owner']); OC_Util::setupFS($row['uid_owner']);

View File

@ -11,16 +11,13 @@
margin: 6px; margin: 6px;
} }
input[type="submit"]{ input[type='submit'] {
width: 45px; width: 45px;
height: 45px; height: 45px;
margin: 6px; 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; position: absolute;
top: 0px; top: 0px;
} }

View File

@ -0,0 +1,49 @@
@media only screen and (max-width: 600px) {
/* make header scroll up for single shares, more view of content on small screens */
#header.share-file {
position: absolute !important;
}
/* hide size and date columns */
table th#headerSize,
table td.filesize,
table th#headerDate,
table td.date {
display: none;
}
/* restrict length of displayed filename to prevent overflow */
table td.filename .nametext {
max-width: 75% !important;
}
/* on mobile, show single shared image at full width without margin */
#imgframe {
width: 100%;
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 {
-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;
}
}

View File

@ -3,7 +3,7 @@ body {
} }
#header { #header {
background: #1d2d44 url('%webroot%/core/img/noise.png') repeat; background-color: #1d2d44;
height:32px; height:32px;
left:0; left:0;
line-height:32px; line-height:32px;
@ -14,39 +14,17 @@ body {
padding:7px; padding:7px;
} }
#details {
color:#fff;
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;
}
.header-right { .header-right {
padding: 0; padding: 0;
height: 32px; height: 32px;
} }
#public_upload { #details {
margin-left: 0.3em; color:#fff;
} -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=50)";
filter: alpha(opacity=50);
#public_upload img, opacity: .5;
#download img { padding-right: 5px;
padding-left:.1em;
padding-right:.3em;
vertical-align:text-bottom;
} }
#controls { #controls {
@ -61,7 +39,7 @@ body {
#noPreview { #noPreview {
display:none; display:none;
padding-top:5em; padding-top:80px;
} }
footer { footer {
@ -71,9 +49,8 @@ footer {
p.info { p.info {
color: #777; color: #777;
text-align: center; text-align: center;
width: 22em;
margin: 0 auto; margin: 0 auto;
padding: 20px; padding: 20px 0;
} }
p.info a { p.info a {
@ -83,8 +60,8 @@ p.info a {
#imgframe { #imgframe {
height:75%; height:75%;
padding-bottom:2em; padding-bottom:32px;
padding-top:2em; padding-top:32px;
width:80%; width:80%;
margin:0 auto; margin:0 auto;
} }
@ -94,9 +71,13 @@ p.info a {
max-width:100%; max-width:100%;
} }
thead{ /* some margin for the file type icon */
background-color: white; #imgframe .publicpreview {
padding-left:0 !important; /* fixes multiselect bar offset on shared page */ margin-top: 10%;
}
thead {
padding-left: 0 !important; /* fixes multiselect bar offset on shared page */
} }
#data-upload-form { #data-upload-form {
@ -110,41 +91,20 @@ thead{
margin: 0; margin: 0;
} }
#file_upload_start { .directDownload,
-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 { .directLink {
margin-bottom: 20px; margin-bottom: 20px;
} }
.directLink label { .directDownload .button img {
vertical-align: text-bottom;
}
.directLink label {
font-weight: normal; font-weight: normal;
} -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=50)";
.directLink input { filter: alpha(opacity=50);
margin-left: 10px; opacity: .5;
}
.directLink input {
margin-left: 5px;
width: 300px; width: 300px;
} }

View File

@ -9,43 +9,32 @@ function fileDownloadPath(dir, file) {
$(document).ready(function() { $(document).ready(function() {
$('#data-upload-form').tipsy({gravity:'ne', fade:true});
if (typeof FileActions !== 'undefined') { if (typeof FileActions !== 'undefined') {
var mimetype = $('#mimetype').val(); var mimetype = $('#mimetype').val();
// Show file preview if previewer is available, images are already handled by the template // Show file preview if previewer is available, images are already handled by the template
if (mimetype.substr(0, mimetype.indexOf('/')) != 'image' && $('.publicpreview').length === 0) { if (mimetype.substr(0, mimetype.indexOf('/')) != 'image' && $('.publicpreview').length === 0) {
// Trigger default action if not download TODO // Trigger default action if not download TODO
var action = FileActions.getDefault(mimetype, 'file', OC.PERMISSION_READ); var action = FileActions.getDefault(mimetype, 'file', OC.PERMISSION_READ);
if (typeof action === 'undefined') { 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 {
action($('#filename').val()); action($('#filename').val());
} }
} }
FileActions.register('dir', 'Open', OC.PERMISSION_READ, '', function(filename) { FileActions.register('dir', 'Open', OC.PERMISSION_READ, '', function(filename) {
var tr = $('tr').filterAttr('data-file', filename); var tr = FileList.findFileEl(filename);
if (tr.length > 0) { if (tr.length > 0) {
window.location = $(tr).find('a.name').attr('href'); window.location = $(tr).find('a.name').attr('href');
} }
}); });
FileActions.register('file', 'Download', OC.PERMISSION_READ, '', function(filename) {
var tr = $('tr').filterAttr('data-file', 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) { if (tr.length > 0) {
window.location = $(tr).find('a.name').attr('href'); return $(tr).find('a.name').attr('href') + '&download';
} }
}); return null;
FileActions.register('dir', 'Download', OC.PERMISSION_READ, '', function(filename) { };
var tr = $('tr').filterAttr('data-file', filename);
if (tr.length > 0) {
window.location = $(tr).find('a.name').attr('href')+'&download';
}
});
} }
var file_upload_start = $('#file_upload_start'); var file_upload_start = $('#file_upload_start');
@ -58,15 +47,9 @@ $(document).ready(function() {
}; };
}); });
// Add Uploadprogress Wrapper to controls bar $(document).on('click', '#directLink', function() {
$('#controls').append($('#additional_controls div#uploadprogresswrapper')); $(this).focus();
$(this).select();
// Cancel upload trigger
$('#cancel_upload_button').click(function() {
OC.Upload.cancelUploads();
procesSelection();
}); });
$('#directLink').focus();
}); });

View File

@ -22,7 +22,7 @@ $(document).ready(function() {
} else { } else {
var item = $('#dir').val() + '/' + filename; var item = $('#dir').val() + '/' + filename;
} }
var tr = $('tr').filterAttr('data-file', filename); var tr = FileList.findFileEl(filename);
if ($(tr).data('type') == 'dir') { if ($(tr).data('type') == 'dir') {
var itemType = 'folder'; var itemType = 'folder';
} else { } else {

View File

@ -1,19 +1,19 @@
<?php <?php
$TRANSLATIONS = array( $TRANSLATIONS = array(
"This share is password-protected" => "Αυτός ο κοινόχρηστος φάκελος προστατεύεται με κωδικό", "This share is password-protected" => "Αυτός ο κοινόχρηστος φάκελος προστατεύεται με κωδικό",
"The password is wrong. Try again." => "Εσφαλμένο συνθηματικό. Προσπαθήστε ξανά.", "The password is wrong. Try again." => "Εσφαλμένος κωδικός πρόσβασης. Προσπαθήστε ξανά.",
"Password" => "Συνθηματικό", "Password" => "Κωδικός πρόσβασης",
"Sorry, this link doesnt seem to work anymore." => "Συγγνώμη, αυτός ο σύνδεσμος μοιάζει να μην ισχύει πια.", "Sorry, this link doesnt seem to work anymore." => "Συγγνώμη, αυτός ο σύνδεσμος μοιάζει να μην ισχύει πια.",
"Reasons might be:" => "Οι λόγοι μπορεί να είναι:", "Reasons might be:" => "Οι λόγοι μπορεί να είναι:",
"the item was removed" => "το αντικείμενο απομακρύνθηκε", "the item was removed" => "το αντικείμενο απομακρύνθηκε",
"the link expired" => "ο σύνδεσμος έληξε", "the link expired" => "ο σύνδεσμος έληξε",
"sharing is disabled" => "ο διαμοιρασμός απενεργοποιήθηκε", "sharing is disabled" => "ο διαμοιρασμός απενεργοποιήθηκε",
"For more info, please ask the person who sent this link." => "Για περισσότερες πληροφορίες, παρακαλώ ρωτήστε το άτομο που σας έστειλε αυτόν τον σύνδεσμο.", "For more info, please ask the person who sent this link." => "Για περισσότερες πληροφορίες, παρακαλώ ρωτήστε το άτομο που σας έστειλε αυτόν τον σύνδεσμο.",
"%s shared the folder %s with you" => "%s μοιράστηκε τον φάκελο %s μαζί σας", "%s shared the folder %s with you" => "Ο %s μοιράστηκε τον φάκελο %s μαζί σας",
"%s shared the file %s with you" => "%s μοιράστηκε το αρχείο %s μαζί σας", "%s shared the file %s with you" => "Ο %s μοιράστηκε το αρχείο %s μαζί σας",
"Download" => "Λήψη", "Download" => "Λήψη",
"Upload" => "Μεταφόρτωση", "Upload" => "Μεταφόρτωση",
"Cancel upload" => "Ακύρωση αποστολής", "Cancel upload" => "Ακύρωση μεταφόρτωσης",
"No preview available for" => "Δεν υπάρχει διαθέσιμη προεπισκόπηση για", "No preview available for" => "Δεν υπάρχει διαθέσιμη προεπισκόπηση για",
"Direct link" => "Άμεσος σύνδεσμος" "Direct link" => "Άμεσος σύνδεσμος"
); );

View File

@ -1,11 +1,20 @@
<?php <?php
$TRANSLATIONS = array( $TRANSLATIONS = array(
"This share is password-protected" => "Berbagi ini dilindungi sandi",
"The password is wrong. Try again." => "Sandi salah. Coba lagi",
"Password" => "Sandi", "Password" => "Sandi",
"Sorry, this link doesnt seem to work anymore." => "Maaf, tautan ini tampaknya tidak berfungsi lagi.",
"Reasons might be:" => "Alasan mungkin:",
"the item was removed" => "item telah dihapus",
"the link expired" => "tautan telah kadaluarsa",
"sharing is disabled" => "berbagi dinonaktifkan",
"For more info, please ask the person who sent this link." => "Untuk info lebih lanjut, silakan tanyakan orang yang mengirim tautan ini.",
"%s shared the folder %s with you" => "%s membagikan folder %s dengan Anda", "%s shared the folder %s with you" => "%s membagikan folder %s dengan Anda",
"%s shared the file %s with you" => "%s membagikan file %s dengan Anda", "%s shared the file %s with you" => "%s membagikan berkas %s dengan Anda",
"Download" => "Unduh", "Download" => "Unduh",
"Upload" => "Unggah", "Upload" => "Unggah",
"Cancel upload" => "Batal pengunggahan", "Cancel upload" => "Batal unggah",
"No preview available for" => "Tidak ada pratinjau tersedia untuk" "No preview available for" => "Tidak ada pratinjau yang tersedia untuk",
"Direct link" => "Tautan langsung"
); );
$PLURAL_FORMS = "nplurals=1; plural=0;"; $PLURAL_FORMS = "nplurals=1; plural=0;";

View File

@ -1,8 +0,0 @@
<?php
$TRANSLATIONS = array(
"Password" => "Пароль",
"Download" => "Загрузка",
"Upload" => "Загрузка",
"Cancel upload" => "Отмена загрузки"
);
$PLURAL_FORMS = "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);";

View File

@ -162,7 +162,7 @@ class Api {
$view = new \OC\Files\View('/'.\OCP\User::getUser().'/files'); $view = new \OC\Files\View('/'.\OCP\User::getUser().'/files');
if(!$view->is_dir($path)) { 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); $content = $view->getDirectoryContent($path);
@ -178,8 +178,7 @@ class Api {
$share['received_from_displayname'] = \OCP\User::getDisplayName($receivedFrom['uid_owner']); $share['received_from_displayname'] = \OCP\User::getDisplayName($receivedFrom['uid_owner']);
} }
if ($share) { if ($share) {
$share['filename'] = $file['name']; $result = array_merge($result, $share);
$result[] = $share;
} }
} }
@ -220,10 +219,8 @@ class Api {
$shareWith = isset($_POST['password']) ? $_POST['password'] : null; $shareWith = isset($_POST['password']) ? $_POST['password'] : null;
//check public link share //check public link share
$publicUploadEnabled = \OC_Appconfig::getValue('core', 'shareapi_allow_public_upload', 'yes'); $publicUploadEnabled = \OC_Appconfig::getValue('core', 'shareapi_allow_public_upload', 'yes');
$encryptionEnabled = \OC_App::isEnabled('files_encryption'); if(isset($_POST['publicUpload']) && $publicUploadEnabled !== 'yes') {
if(isset($_POST['publicUpload']) && return new \OC_OCS_Result(null, 403, "public upload disabled by the administrator");
($encryptionEnabled || $publicUploadEnabled !== 'yes')) {
return new \OC_OCS_Result(null, 404, "public upload disabled by the administrator");
} }
$publicUpload = isset($_POST['publicUpload']) ? $_POST['publicUpload'] : 'false'; $publicUpload = isset($_POST['publicUpload']) ? $_POST['publicUpload'] : 'false';
// read, create, update (7) if public upload is enabled or // read, create, update (7) if public upload is enabled or
@ -231,7 +228,7 @@ class Api {
$permissions = $publicUpload === 'true' ? 7 : 1; $permissions = $publicUpload === 'true' ? 7 : 1;
break; break;
default: default:
return new \OC_OCS_Result(null, 404, "unknown share type"); return new \OC_OCS_Result(null, 400, "unknown share type");
} }
try { try {
@ -243,7 +240,7 @@ class Api {
$permissions $permissions
); );
} catch (\Exception $e) { } catch (\Exception $e) {
return new \OC_OCS_Result(null, 404, $e->getMessage()); return new \OC_OCS_Result(null, 403, $e->getMessage());
} }
if ($token) { if ($token) {
@ -321,11 +318,8 @@ class Api {
$permissions = isset($params['_put']['permissions']) ? (int)$params['_put']['permissions'] : null; $permissions = isset($params['_put']['permissions']) ? (int)$params['_put']['permissions'] : null;
$publicUploadStatus = \OC_Appconfig::getValue('core', 'shareapi_allow_public_upload', 'yes'); $publicUploadStatus = \OC_Appconfig::getValue('core', 'shareapi_allow_public_upload', 'yes');
$encryptionEnabled = \OC_App::isEnabled('files_encryption'); $publicUploadEnabled = ($publicUploadStatus === 'yes') ? true : false;
$publicUploadEnabled = false;
if(!$encryptionEnabled && $publicUploadStatus === 'yes') {
$publicUploadEnabled = true;
}
// only change permissions for public shares if public upload is enabled // 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) // and we want to set permissions to 1 (read only) or 7 (allow upload)
@ -363,9 +357,8 @@ class Api {
private static function updatePublicUpload($share, $params) { private static function updatePublicUpload($share, $params) {
$publicUploadEnabled = \OC_Appconfig::getValue('core', 'shareapi_allow_public_upload', 'yes'); $publicUploadEnabled = \OC_Appconfig::getValue('core', 'shareapi_allow_public_upload', 'yes');
$encryptionEnabled = \OC_App::isEnabled('files_encryption'); if($publicUploadEnabled !== 'yes') {
if($encryptionEnabled || $publicUploadEnabled !== 'yes') { return new \OC_OCS_Result(null, 403, "public upload disabled by the administrator");
return new \OC_OCS_Result(null, 404, "public upload disabled by the administrator");
} }
if ($share['item_type'] !== 'folder' || if ($share['item_type'] !== 'folder' ||

View File

@ -92,12 +92,11 @@ class Shared_Cache extends Cache {
} else { } else {
$query = \OC_DB::prepare( $query = \OC_DB::prepare(
'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`,' 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`,'
.' `size`, `mtime`, `encrypted`' .' `size`, `mtime`, `encrypted`, `unencrypted_size`'
.' FROM `*PREFIX*filecache` WHERE `fileid` = ?'); .' FROM `*PREFIX*filecache` WHERE `fileid` = ?');
$result = $query->execute(array($file)); $result = $query->execute(array($file));
$data = $result->fetchRow(); $data = $result->fetchRow();
$data['fileid'] = (int)$data['fileid']; $data['fileid'] = (int)$data['fileid'];
$data['size'] = (int)$data['size'];
$data['mtime'] = (int)$data['mtime']; $data['mtime'] = (int)$data['mtime'];
$data['storage_mtime'] = (int)$data['storage_mtime']; $data['storage_mtime'] = (int)$data['storage_mtime'];
$data['encrypted'] = (bool)$data['encrypted']; $data['encrypted'] = (bool)$data['encrypted'];
@ -106,6 +105,12 @@ class Shared_Cache extends Cache {
if ($data['storage_mtime'] === 0) { if ($data['storage_mtime'] === 0) {
$data['storage_mtime'] = $data['mtime']; $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 $data;
} }
return false; return false;
@ -127,7 +132,18 @@ class Shared_Cache extends Cache {
return $files; return $files;
} else { } else {
if ($cache = $this->getSourceCache($folder)) { 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; return false;
@ -248,17 +264,38 @@ class Shared_Cache extends Cache {
* @return array * @return array
*/ */
public function searchByMime($mimetype) { public function searchByMime($mimetype) {
$mimepart = null;
if (strpos($mimetype, '/')) { if (strpos($mimetype, '/') === false) {
$where = '`mimetype` = ? AND '; $mimepart = $mimetype;
} else { $mimetype = null;
$where = '`mimepart` = ? AND ';
} }
$value = $this->getMimetypeId($mimetype); // note: searchWithWhere is currently broken as it doesn't
// recurse into subdirs nor returns the correct
return $this->searchWithWhere($where, $value); // 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;
} }
/** /**
@ -302,6 +339,12 @@ class Shared_Cache extends Cache {
} }
$row['mimetype'] = $this->getMimetype($row['mimetype']); $row['mimetype'] = $this->getMimetype($row['mimetype']);
$row['mimepart'] = $this->getMimetype($row['mimepart']); $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; $files[] = $row;
} }
} }

View File

@ -91,10 +91,17 @@ class OC_Share_Backend_File implements OCP\Share_Backend_File_Dependent {
$file['name'] = basename($item['file_target']); $file['name'] = basename($item['file_target']);
$file['mimetype'] = $item['mimetype']; $file['mimetype'] = $item['mimetype'];
$file['mimepart'] = $item['mimepart']; $file['mimepart'] = $item['mimepart'];
$file['size'] = $item['size'];
$file['mtime'] = $item['mtime']; $file['mtime'] = $item['mtime'];
$file['encrypted'] = $item['encrypted']; $file['encrypted'] = $item['encrypted'];
$file['etag'] = $item['etag']; $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; $files[] = $file;
} }
return $files; return $files;
@ -172,7 +179,7 @@ class OC_Share_Backend_File implements OCP\Share_Backend_File_Dependent {
$source['fileOwner'] = $fileOwner; $source['fileOwner'] = $fileOwner;
return $source; return $source;
} }
\OCP\Util::writeLog('files_sharing', 'File source not found for: '.$target, \OCP\Util::ERROR); \OCP\Util::writeLog('files_sharing', 'File source not found for: '.$target, \OCP\Util::DEBUG);
return false; return false;
} }

Some files were not shown because too many files have changed in this diff Show More