Файловый менеджер - Редактировать - /home/wuectly/www/03cbe/File.php.tar
Назад
home/wuectly/www/libraries/src/Filesystem/File.php 0000604 00000037010 15245572101 0016272 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2006 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Filesystem; defined('JPATH_PLATFORM') or die; use Joomla\CMS\Factory; use Joomla\CMS\Log\Log; use Joomla\CMS\Language\Text; use Joomla\CMS\Filesystem\Path; use Joomla\CMS\Filesystem\Wrapper\PathWrapper; use Joomla\CMS\Filesystem\Wrapper\FolderWrapper; use Joomla\CMS\Client\ClientHelper; use Joomla\CMS\Client\FtpClient; /** * A File handling class * * @since 1.7.0 */ class File { /** * Gets the extension of a file name * * @param string $file The file name * * @return string The file extension * * @since 1.7.0 */ public static function getExt($file) { // String manipulation should be faster than pathinfo() on newer PHP versions. $dot = strrpos($file, '.'); if ($dot === false) { return ''; } $ext = substr($file, $dot + 1); // Extension cannot contain slashes. if (strpos($ext, '/') !== false || (DIRECTORY_SEPARATOR === '\\' && strpos($ext, '\\') !== false)) { return ''; } return $ext; } /** * Strips the last extension off of a file name * * @param string $file The file name * * @return string The file name without the extension * * @since 1.7.0 */ public static function stripExt($file) { return preg_replace('#\.[^.]*$#', '', $file); } /** * Makes file name safe to use * * @param string $file The name of the file [not full path] * * @return string The sanitised string * * @since 1.7.0 */ public static function makeSafe($file) { // Remove any trailing dots, as those aren't ever valid file names. $file = rtrim($file, '.'); $regex = array('#(\.){2,}#', '#[^A-Za-z0-9\.\_\- ]#', '#^\.#'); return trim(preg_replace($regex, '', $file)); } /** * Copies a file * * @param string $src The path to the source file * @param string $dest The path to the destination file * @param string $path An optional base path to prefix to the file names * @param boolean $useStreams True to use streams * * @return boolean True on success * * @since 1.7.0 */ public static function copy($src, $dest, $path = null, $useStreams = false) { $pathObject = new PathWrapper; // Prepend a base path if it exists if ($path) { $src = $pathObject->clean($path . '/' . $src); $dest = $pathObject->clean($path . '/' . $dest); } // Check src path if (!is_readable($src)) { Log::add(Text::sprintf('JLIB_FILESYSTEM_ERROR_JFILE_FIND_COPY', $src), Log::WARNING, 'jerror'); return false; } if ($useStreams) { $stream = Factory::getStream(); if (!$stream->copy($src, $dest)) { Log::add(Text::sprintf('JLIB_FILESYSTEM_ERROR_JFILE_STREAMS', $src, $dest, $stream->getError()), Log::WARNING, 'jerror'); return false; } return true; } else { $FTPOptions = ClientHelper::getCredentials('ftp'); if ($FTPOptions['enabled'] == 1) { // Connect the FTP client $ftp = FtpClient::getInstance($FTPOptions['host'], $FTPOptions['port'], array(), $FTPOptions['user'], $FTPOptions['pass']); // If the parent folder doesn't exist we must create it if (!file_exists(dirname($dest))) { $folderObject = new FolderWrapper; $folderObject->create(dirname($dest)); } // Translate the destination path for the FTP account $dest = $pathObject->clean(str_replace(JPATH_ROOT, $FTPOptions['root'], $dest), '/'); if (!$ftp->store($src, $dest)) { // FTP connector throws an error return false; } $ret = true; } else { if (!@ copy($src, $dest)) { Log::add(Text::sprintf('JLIB_FILESYSTEM_ERROR_COPY_FAILED_ERR01', $src, $dest), Log::WARNING, 'jerror'); return false; } $ret = true; } return $ret; } } /** * Delete a file or array of files * * @param mixed $file The file name or an array of file names * * @return boolean True on success * * @since 1.7.0 */ public static function delete($file) { $FTPOptions = ClientHelper::getCredentials('ftp'); $pathObject = new PathWrapper; if (is_array($file)) { $files = $file; } else { $files[] = $file; } // Do NOT use ftp if it is not enabled if ($FTPOptions['enabled'] == 1) { // Connect the FTP client $ftp = FtpClient::getInstance($FTPOptions['host'], $FTPOptions['port'], array(), $FTPOptions['user'], $FTPOptions['pass']); } foreach ($files as $file) { $file = $pathObject->clean($file); if (!is_file($file)) { continue; } // Try making the file writable first. If it's read-only, it can't be deleted // on Windows, even if the parent folder is writable @chmod($file, 0777); // In case of restricted permissions we zap it one way or the other // as long as the owner is either the webserver or the ftp if (@unlink($file)) { // Do nothing } elseif ($FTPOptions['enabled'] == 1) { $file = $pathObject->clean(str_replace(JPATH_ROOT, $FTPOptions['root'], $file), '/'); if (!$ftp->delete($file)) { // FTP connector throws an error return false; } } else { $filename = basename($file); Log::add(Text::sprintf('JLIB_FILESYSTEM_DELETE_FAILED', $filename), Log::WARNING, 'jerror'); return false; } } return true; } /** * Moves a file * * @param string $src The path to the source file * @param string $dest The path to the destination file * @param string $path An optional base path to prefix to the file names * @param boolean $useStreams True to use streams * * @return boolean True on success * * @since 1.7.0 */ public static function move($src, $dest, $path = '', $useStreams = false) { $pathObject = new PathWrapper; if ($path) { $src = $pathObject->clean($path . '/' . $src); $dest = $pathObject->clean($path . '/' . $dest); } // Check src path if (!is_readable($src)) { Log::add(Text::_('JLIB_FILESYSTEM_CANNOT_FIND_SOURCE_FILE'), Log::WARNING, 'jerror'); return false; } if ($useStreams) { $stream = Factory::getStream(); if (!$stream->move($src, $dest)) { Log::add(Text::sprintf('JLIB_FILESYSTEM_ERROR_JFILE_MOVE_STREAMS', $stream->getError()), Log::WARNING, 'jerror'); return false; } return true; } else { $FTPOptions = ClientHelper::getCredentials('ftp'); if ($FTPOptions['enabled'] == 1) { // Connect the FTP client $ftp = FtpClient::getInstance($FTPOptions['host'], $FTPOptions['port'], array(), $FTPOptions['user'], $FTPOptions['pass']); // Translate path for the FTP account $src = $pathObject->clean(str_replace(JPATH_ROOT, $FTPOptions['root'], $src), '/'); $dest = $pathObject->clean(str_replace(JPATH_ROOT, $FTPOptions['root'], $dest), '/'); // Use FTP rename to simulate move if (!$ftp->rename($src, $dest)) { Log::add(Text::_('JLIB_FILESYSTEM_ERROR_RENAME_FILE'), Log::WARNING, 'jerror'); return false; } } else { if (!@ rename($src, $dest)) { Log::add(Text::_('JLIB_FILESYSTEM_ERROR_RENAME_FILE'), Log::WARNING, 'jerror'); return false; } } return true; } } /** * Read the contents of a file * * @param string $filename The full file path * @param boolean $incpath Use include path * @param integer $amount Amount of file to read * @param integer $chunksize Size of chunks to read * @param integer $offset Offset of the file * * @return mixed Returns file contents or boolean False if failed * * @since 1.7.0 * @deprecated 4.0 - Use the native file_get_contents() instead. */ public static function read($filename, $incpath = false, $amount = 0, $chunksize = 8192, $offset = 0) { Log::add(__METHOD__ . ' is deprecated. Use native file_get_contents() syntax.', Log::WARNING, 'deprecated'); $data = null; if ($amount && $chunksize > $amount) { $chunksize = $amount; } if (false === $fh = fopen($filename, 'rb', $incpath)) { Log::add(Text::sprintf('JLIB_FILESYSTEM_ERROR_READ_UNABLE_TO_OPEN_FILE', $filename), Log::WARNING, 'jerror'); return false; } clearstatcache(); if ($offset) { fseek($fh, $offset); } if ($fsize = @ filesize($filename)) { if ($amount && $fsize > $amount) { $data = fread($fh, $amount); } else { $data = fread($fh, $fsize); } } else { $data = ''; /* * While it's: * 1: Not the end of the file AND * 2a: No Max Amount set OR * 2b: The length of the data is less than the max amount we want */ while (!feof($fh) && (!$amount || strlen($data) < $amount)) { $data .= fread($fh, $chunksize); } } fclose($fh); return $data; } /** * Write contents to a file * * @param string $file The full file path * @param string $buffer The buffer to write * @param boolean $useStreams Use streams * * @return boolean True on success * * @since 1.7.0 */ public static function write($file, $buffer, $useStreams = false) { @set_time_limit(ini_get('max_execution_time')); // If the destination directory doesn't exist we need to create it if (!file_exists(dirname($file))) { $folderObject = new FolderWrapper; if ($folderObject->create(dirname($file)) == false) { return false; } } if ($useStreams) { $stream = Factory::getStream(); // Beef up the chunk size to a meg $stream->set('chunksize', (1024 * 1024)); if (!$stream->writeFile($file, $buffer)) { Log::add(Text::sprintf('JLIB_FILESYSTEM_ERROR_WRITE_STREAMS', $file, $stream->getError()), Log::WARNING, 'jerror'); return false; } return true; } else { $FTPOptions = ClientHelper::getCredentials('ftp'); $pathObject = new PathWrapper; if ($FTPOptions['enabled'] == 1) { // Connect the FTP client $ftp = FtpClient::getInstance($FTPOptions['host'], $FTPOptions['port'], array(), $FTPOptions['user'], $FTPOptions['pass']); // Translate path for the FTP account and use FTP write buffer to file $file = $pathObject->clean(str_replace(JPATH_ROOT, $FTPOptions['root'], $file), '/'); $ret = $ftp->write($file, $buffer); } else { $file = $pathObject->clean($file); $ret = is_int(file_put_contents($file, $buffer)) ? true : false; } return $ret; } } /** * Append contents to a file * * @param string $file The full file path * @param string $buffer The buffer to write * @param boolean $useStreams Use streams * * @return boolean True on success * * @since 3.6.0 */ public static function append($file, $buffer, $useStreams = false) { @set_time_limit(ini_get('max_execution_time')); // If the file doesn't exist, just write instead of append if (!file_exists($file)) { return self::write($file, $buffer, $useStreams); } if ($useStreams) { $stream = Factory::getStream(); // Beef up the chunk size to a meg $stream->set('chunksize', (1024 * 1024)); if ($stream->open($file, 'ab') && $stream->write($buffer) && $stream->close()) { return true; } Log::add(Text::sprintf('JLIB_FILESYSTEM_ERROR_WRITE_STREAMS', $file, $stream->getError()), Log::WARNING, 'jerror'); return false; } else { // Initialise variables. $FTPOptions = ClientHelper::getCredentials('ftp'); if ($FTPOptions['enabled'] == 1) { // Connect the FTP client $ftp = FtpClient::getInstance($FTPOptions['host'], $FTPOptions['port'], array(), $FTPOptions['user'], $FTPOptions['pass']); // Translate path for the FTP account and use FTP write buffer to file $file = Path::clean(str_replace(JPATH_ROOT, $FTPOptions['root'], $file), '/'); $ret = $ftp->append($file, $buffer); } else { $file = Path::clean($file); $ret = is_int(file_put_contents($file, $buffer, FILE_APPEND)); } return $ret; } } /** * Moves an uploaded file to a destination folder * * @param string $src The name of the php (temporary) uploaded file * @param string $dest The path (including filename) to move the uploaded file to * @param boolean $useStreams True to use streams * @param boolean $allowUnsafe Allow the upload of unsafe files * @param boolean $safeFileOptions Options to \JFilterInput::isSafeFile * * @return boolean True on success * * @since 1.7.0 */ public static function upload($src, $dest, $useStreams = false, $allowUnsafe = false, $safeFileOptions = array()) { if (!$allowUnsafe) { $descriptor = array( 'tmp_name' => $src, 'name' => basename($dest), 'type' => '', 'error' => '', 'size' => '', ); $isSafe = \JFilterInput::isSafeFile($descriptor, $safeFileOptions); if (!$isSafe) { Log::add(Text::sprintf('JLIB_FILESYSTEM_ERROR_WARNFS_ERR03', $dest), Log::WARNING, 'jerror'); return false; } } // Ensure that the path is valid and clean $pathObject = new PathWrapper; $dest = $pathObject->clean($dest); // Create the destination directory if it does not exist $baseDir = dirname($dest); if (!file_exists($baseDir)) { $folderObject = new FolderWrapper; $folderObject->create($baseDir); } if ($useStreams) { $stream = Factory::getStream(); if (!$stream->upload($src, $dest)) { Log::add(Text::sprintf('JLIB_FILESYSTEM_ERROR_UPLOAD', $stream->getError()), Log::WARNING, 'jerror'); return false; } return true; } else { $FTPOptions = ClientHelper::getCredentials('ftp'); $ret = false; if ($FTPOptions['enabled'] == 1) { // Connect the FTP client $ftp = FtpClient::getInstance($FTPOptions['host'], $FTPOptions['port'], array(), $FTPOptions['user'], $FTPOptions['pass']); // Translate path for the FTP account $dest = $pathObject->clean(str_replace(JPATH_ROOT, $FTPOptions['root'], $dest), '/'); // Copy the file to the destination directory if (is_uploaded_file($src) && $ftp->store($src, $dest)) { unlink($src); $ret = true; } else { Log::add(Text::sprintf('JLIB_FILESYSTEM_ERROR_WARNFS_ERR04', $src, $dest), Log::WARNING, 'jerror'); } } else { if (is_writeable($baseDir) && move_uploaded_file($src, $dest)) { // Short circuit to prevent file permission errors if ($pathObject->setPermissions($dest)) { $ret = true; } else { Log::add(Text::_('JLIB_FILESYSTEM_ERROR_WARNFS_ERR01'), Log::WARNING, 'jerror'); } } else { Log::add(Text::sprintf('JLIB_FILESYSTEM_ERROR_WARNFS_ERR04', $src, $dest), Log::WARNING, 'jerror'); } } return $ret; } } /** * Wrapper for the standard file_exists function * * @param string $file File path * * @return boolean True if path is a file * * @since 1.7.0 */ public static function exists($file) { $pathObject = new PathWrapper; return is_file($pathObject->clean($file)); } /** * Returns the name, without any path. * * @param string $file File path * * @return string filename * * @since 1.7.0 * @deprecated 4.0 - Use basename() instead. */ public static function getName($file) { Log::add(__METHOD__ . ' is deprecated. Use native basename() syntax.', Log::WARNING, 'deprecated'); // Convert back slashes to forward slashes $file = str_replace('\\', '/', $file); $slash = strrpos($file, '/'); if ($slash !== false) { return substr($file, $slash + 1); } else { return $file; } } } home/wuectly/www/libraries/regularlabs/src/File.php 0000604 00000027333 15245607103 0016461 0 ustar 00 <?php /** * @package Regular Labs Library * @version 21.4.10972 * * @author Peter van Westen <info@regularlabs.com> * @link http://www.regularlabs.com * @copyright Copyright © 2021 Regular Labs All Rights Reserved * @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL */ namespace RegularLabs\Library; defined('_JEXEC') or die; use Joomla\CMS\Client\ClientHelper as JClientHelper; use Joomla\CMS\Client\FtpClient as JFtpClient; use Joomla\CMS\Factory as JFactory; use Joomla\CMS\Filesystem\Folder as JFolder; use Joomla\CMS\Filesystem\Path as JPath; use Joomla\CMS\Language\Text as JText; use Joomla\CMS\Log\Log as JLog; use Joomla\CMS\Uri\Uri as JUri; /** * Class File * @package RegularLabs\Library */ class File { /** * Find a matching media file in the different possible extension media folders for given type * * @param string $type (css/js/...) * @param string $file * * @return bool|string */ public static function getMediaFile($type, $file) { // If http is present in filename if (strpos($file, 'http') === 0 || strpos($file, '//') === 0) { return $file; } $files = []; // Detect debug mode if (JFactory::getConfig()->get('debug') || JFactory::getApplication()->input->get('debug')) { $files[] = str_replace(['.min.', '-min.'], '.', $file); } $files[] = $file; /* * Loop on 1 or 2 files and break on first find. * Add the content of the MD5SUM file located in the same folder to url to ensure cache browser refresh * This MD5SUM file must represent the signature of the folder content */ foreach ($files as $check_file) { $file_found = self::findMediaFileByFile($check_file, $type); if ( ! $file_found) { continue; } return $file_found; } return false; } /** * Find a matching media file in the different possible extension media folders for given type * * @param string $file * @param string $type (css/js/...) * * @return bool|string */ private static function findMediaFileByFile($file, $type) { $template = JFactory::getApplication()->getTemplate(); // If the file is in the template folder $file_found = self::getFileUrl('/templates/' . $template . '/' . $type . '/' . $file); if ($file_found) { return $file_found; } // Try to deal with system files in the media folder if (strpos($file, '/') === false) { $file_found = self::getFileUrl('/media/system/' . $type . '/' . $file); if ( ! $file_found) { return false; } return $file_found; } $paths = []; // If the file contains any /: it can be in a media extension subfolder // Divide the file extracting the extension as the first part before / list($extension, $file) = explode('/', $file, 2); $paths[] = '/media/' . $extension . '/' . $type; $paths[] = '/templates/' . $template . '/' . $type . '/system'; $paths[] = '/media/system/' . $type; foreach ($paths as $path) { $file_found = self::getFileUrl($path . '/' . $file); if ( ! $file_found) { continue; } return $file_found; } return false; } /** * Get the url for the file * * @param string $path * * @return bool|string */ private static function getFileUrl($path) { if ( ! file_exists(JPATH_ROOT . $path)) { return false; } return JUri::root(true) . $path; } /** * Delete a file or array of files * * @param mixed $file The file name or an array of file names * @param boolean $show_messages Whether or not to show error messages * @param int $min_age_in_minutes Minimum last modified age in minutes * * @return boolean True on success * * @since 11.1 */ public static function delete($file, $show_messages = false, $min_age_in_minutes = 0) { $FTPOptions = JClientHelper::getCredentials('ftp'); $pathObject = new JPath; $files = is_array($file) ? $file : [$file]; if ($FTPOptions['enabled'] == 1) { // Connect the FTP client $ftp = JFtpClient::getInstance($FTPOptions['host'], $FTPOptions['port'], [], $FTPOptions['user'], $FTPOptions['pass']); } foreach ($files as $file) { $file = $pathObject->clean($file); if ( ! is_file($file)) { continue; } if ($min_age_in_minutes && floor((time() - filemtime($file)) / 60) < $min_age_in_minutes) { continue; } // Try making the file writable first. If it's read-only, it can't be deleted // on Windows, even if the parent folder is writable @chmod($file, 0777); if ($FTPOptions['enabled'] == 1) { $file = $pathObject->clean(str_replace(JPATH_ROOT, $FTPOptions['root'], $file), '/'); if ( ! $ftp->delete($file)) { // FTP connector throws an error return false; } } // Try the unlink twice in case something was blocking it on first try if ( ! @unlink($file) && ! @unlink($file)) { $show_messages && JLog::add(JText::sprintf('JLIB_FILESYSTEM_DELETE_FAILED', basename($file)), JLog::WARNING, 'jerror'); return false; } } return true; } /** * Delete a folder. * * @param string $path The path to the folder to delete. * @param boolean $show_messages Whether or not to show error messages * @param int $min_age_in_minutes Minimum last modified age in minutes * * @return boolean True on success. */ public static function deleteFolder($path, $show_messages = false, $min_age_in_minutes = 0) { @set_time_limit(ini_get('max_execution_time')); $pathObject = new JPath; if ( ! $path) { $show_messages && JLog::add(__METHOD__ . ': ' . JText::_('JLIB_FILESYSTEM_ERROR_DELETE_BASE_DIRECTORY'), JLog::WARNING, 'jerror'); return false; } // Check to make sure the path valid and clean $path = $pathObject->clean($path); if ( ! is_dir($path)) { $show_messages && JLog::add(JText::sprintf('JLIB_FILESYSTEM_ERROR_PATH_IS_NOT_A_FOLDER', $path), JLog::WARNING, 'jerror'); return false; } // Remove all the files in folder if they exist; disable all filtering $files = JFolder::files($path, '.', false, true, [], []); if ( ! empty($files)) { if (self::delete($files, $show_messages, $min_age_in_minutes) !== true) { // JFile::delete throws an error return false; } } // Remove sub-folders of folder; disable all filtering $folders = JFolder::folders($path, '.', false, true, [], []); foreach ($folders as $folder) { if (is_link($folder)) { // Don't descend into linked directories, just delete the link. if (self::delete($folder, $show_messages, $min_age_in_minutes) !== true) { return false; } continue; } if ( ! self::deleteFolder($folder, $show_messages, $min_age_in_minutes)) { return false; } } // Skip if folder is not empty yet if ( ! empty(JFolder::files($path, '.', false, true, [], [])) || ! empty(JFolder::folders($path, '.', false, true, [], []))) { return true; } if (@rmdir($path)) { return true; } $FTPOptions = JClientHelper::getCredentials('ftp'); if ($FTPOptions['enabled'] == 1) { // Connect the FTP client $ftp = JFtpClient::getInstance($FTPOptions['host'], $FTPOptions['port'], [], $FTPOptions['user'], $FTPOptions['pass']); // Translate path and delete $path = $pathObject->clean(str_replace(JPATH_ROOT, $FTPOptions['root'], $path), '/'); // FTP connector throws an error return $ftp->delete($path); } if ( ! @rmdir($path)) { $show_messages && JLog::add(JText::sprintf('JLIB_FILESYSTEM_ERROR_FOLDER_DELETE', $path), JLog::WARNING, 'jerror'); return false; } return true; } public static function trimFolder($folder) { return trim(str_replace(['\\', '//'], '/', $folder), '/'); } public static function isInternal($url) { return ! self::isExternal($url); } public static function isExternal($url) { if (strpos($url, '://') === false) { return false; } // hostname: give preference to SERVER_NAME, because this includes subdomains $hostname = ($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : $_SERVER['HTTP_HOST']; return ! (strpos(RegEx::replace('^.*?://', '', $url), $hostname) === 0); } // some/url/to/a/file.ext // > some/url/to/a public static function getDirName($url) { $url = StringHelper::normalize($url); return rtrim(dirname($url), '/'); } // some/url/to/a/file.ext // > file.ext public static function getBaseName($url, $lowercase = false) { $url = StringHelper::normalize($url); $basename = ltrim(basename($url), '/'); $parts = explode('?', $basename); $basename = $parts[0]; if ($lowercase) { $basename = strtolower($basename); } return $basename; } // some/url/to/a/file.ext // > file public static function getFileName($url, $lowercase = false) { $url = StringHelper::normalize($url); $info = pathinfo($url); $filename = isset($info['filename']) ? $info['filename'] : $url; if ($lowercase) { $filename = strtolower($filename); } return $filename; } // some/url/to/a/file.ext // > ext public static function getExtension($url) { $info = pathinfo($url); if ( ! isset($info['extension'])) { return ''; } $ext = explode('?', $info['extension']); return strtolower($ext[0]); } public static function isImage($url) { return self::isMedia($url, self::getFileTypes('images')); } public static function isVideo($url) { return self::isMedia($url, self::getFileTypes('videos')); } public static function isExternalVideo($url) { return (strpos($url, 'youtu.be') !== false || strpos($url, 'youtube.com') !== false || strpos($url, 'vimeo.com') !== false ); } public static function isDocument($url) { return self::isMedia($url, self::getFileTypes('documents')); } public static function isMedia($url, $filetypes = []) { $filetype = self::getExtension($url); if ( ! $filetype) { return false; } if ( ! is_array($filetypes)) { $filetypes = [$filetypes]; } if (count($filetypes) == 1 && strpos($filetypes[0], ',') !== false) { $filetypes = ArrayHelper::toArray($filetypes[0]); } $filetypes = ! empty($filetypes) ? $filetypes : self::getFileTypes(); return in_array($filetype, $filetypes); } public static function getFileTypes($type = 'images') { switch ($type) { case 'image': case 'images': return [ 'bmp', 'flif', 'gif', 'jpe', 'jpeg', 'jpg', 'png', 'tiff', 'eps', ]; case 'audio': return [ 'aif', 'aiff', 'mp3', 'wav', ]; case 'video': case 'videos': return [ '3g2', '3gp', 'avi', 'divx', 'f4v', 'flv', 'm4v', 'mov', 'mp4', 'mpe', 'mpeg', 'mpg', 'ogv', 'swf', 'webm', 'wmv', ]; case 'document': case 'documents': return [ 'doc', 'docm', 'docx', 'dotm', 'dotx', 'odb', 'odc', 'odf', 'odg', 'odi', 'odm', 'odp', 'ods', 'odt', 'onepkg', 'onetmp', 'onetoc', 'onetoc2', 'otg', 'oth', 'otp', 'ots', 'ott', 'oxt', 'pdf', 'potm', 'potx', 'ppam', 'pps', 'ppsm', 'ppsx', 'ppt', 'pptm', 'pptx', 'rtf', 'sldm', 'sldx', 'thmx', 'xla', 'xlam', 'xlc', 'xld', 'xll', 'xlm', 'xls', 'xlsb', 'xlsm', 'xlsx', 'xlt', 'xltm', 'xltx', 'xlw', ]; case 'other': case 'others': return [ 'css', 'csv', 'js', 'json', 'tar', 'txt', 'xml', 'zip', ]; default: case 'all': return array_merge( self::getFileTypes('images'), self::getFileTypes('audio'), self::getFileTypes('videos'), self::getFileTypes('documents'), self::getFileTypes('other') ); } } } home/wuectly/www/libraries/vendor/joomla/filesystem/src/File.php 0000604 00000015417 15245653313 0021124 0 ustar 00 <?php /** * Part of the Joomla Framework Filesystem Package * * @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE */ namespace Joomla\Filesystem; use Joomla\Filesystem\Exception\FilesystemException; /** * A File handling class * * @since 1.0 */ class File { /** * Strips the last extension off of a file name * * @param string $file The file name * * @return string The file name without the extension * * @since 1.0 */ public static function stripExt($file) { return preg_replace('#\.[^.]*$#', '', $file); } /** * Makes the file name safe to use * * @param string $file The name of the file [not full path] * @param array $stripChars Array of regex (by default will remove any leading periods) * * @return string The sanitised string * * @since 1.0 */ public static function makeSafe($file, array $stripChars = array('#^\.#')) { $regex = array_merge(array('#(\.){2,}#', '#[^A-Za-z0-9\.\_\- ]#'), $stripChars); $file = preg_replace($regex, '', $file); // Remove any trailing dots, as those aren't ever valid file names. $file = rtrim($file, '.'); return $file; } /** * Copies a file * * @param string $src The path to the source file * @param string $dest The path to the destination file * @param string $path An optional base path to prefix to the file names * @param boolean $useStreams True to use streams * * @return boolean True on success * * @since 1.0 * @throws FilesystemException * @throws \UnexpectedValueException */ public static function copy($src, $dest, $path = null, $useStreams = false) { // Prepend a base path if it exists if ($path) { $src = Path::clean($path . '/' . $src); $dest = Path::clean($path . '/' . $dest); } // Check src path if (!is_readable($src)) { throw new \UnexpectedValueException( sprintf( "%s: Cannot find or read file: %s", __METHOD__, Path::removeRoot($src) ) ); } if ($useStreams) { $stream = Stream::getStream(); if (!$stream->copy($src, $dest, null, false)) { throw new FilesystemException(sprintf('%1$s(%2$s, %3$s): %4$s', __METHOD__, $src, $dest, $stream->getError())); } return true; } if (!@ copy($src, $dest)) { throw new FilesystemException(__METHOD__ . ': Copy failed.'); } return true; } /** * Delete a file or array of files * * @param mixed $file The file name or an array of file names * * @return boolean True on success * * @since 1.0 * @throws FilesystemException */ public static function delete($file) { $files = (array) $file; foreach ($files as $file) { $file = Path::clean($file); $filename = basename($file); if (!Path::canChmod($file)) { throw new FilesystemException(__METHOD__ . ': Failed deleting inaccessible file ' . $filename); } // Try making the file writable first. If it's read-only, it can't be deleted // on Windows, even if the parent folder is writable @chmod($file, 0777); // In case of restricted permissions we zap it one way or the other // as long as the owner is either the webserver or the ftp if (!@ unlink($file)) { throw new FilesystemException(__METHOD__ . ': Failed deleting ' . $filename); } } return true; } /** * Moves a file * * @param string $src The path to the source file * @param string $dest The path to the destination file * @param string $path An optional base path to prefix to the file names * @param boolean $useStreams True to use streams * * @return boolean True on success * * @since 1.0 * @throws FilesystemException */ public static function move($src, $dest, $path = '', $useStreams = false) { if ($path) { $src = Path::clean($path . '/' . $src); $dest = Path::clean($path . '/' . $dest); } // Check src path if (!is_readable($src)) { return 'Cannot find source file.'; } if ($useStreams) { $stream = Stream::getStream(); if (!$stream->move($src, $dest, null, false)) { throw new FilesystemException(__METHOD__ . ': ' . $stream->getError()); } return true; } if (!@ rename($src, $dest)) { throw new FilesystemException(__METHOD__ . ': Rename failed.'); } return true; } /** * Write contents to a file * * @param string $file The full file path * @param string $buffer The buffer to write * @param boolean $useStreams Use streams * @param boolean $appendToFile Append to the file and not overwrite it. * * @return boolean True on success * * @since 1.0 */ public static function write($file, &$buffer, $useStreams = false, $appendToFile = false) { @set_time_limit(ini_get('max_execution_time')); // If the destination directory doesn't exist we need to create it if (!file_exists(\dirname($file))) { Folder::create(\dirname($file)); } if ($useStreams) { $stream = Stream::getStream(); // Beef up the chunk size to a meg $stream->set('chunksize', (1024 * 1024)); $stream->writeFile($file, $buffer, $appendToFile); return true; } $file = Path::clean($file); // Set the required flag to only append to the file and not overwrite it if ($appendToFile === true) { return \is_int(file_put_contents($file, $buffer, \FILE_APPEND)); } return \is_int(file_put_contents($file, $buffer)); } /** * Moves an uploaded file to a destination folder * * @param string $src The name of the php (temporary) uploaded file * @param string $dest The path (including filename) to move the uploaded file to * @param boolean $useStreams True to use streams * * @return boolean True on success * * @since 1.0 * @throws FilesystemException */ public static function upload($src, $dest, $useStreams = false) { // Ensure that the path is valid and clean $dest = Path::clean($dest); // Create the destination directory if it does not exist $baseDir = \dirname($dest); if (!is_dir($baseDir)) { Folder::create($baseDir); } if ($useStreams) { $stream = Stream::getStream(); if (!$stream->upload($src, $dest, null, false)) { throw new FilesystemException(sprintf('%1$s(%2$s, %3$s): %4$s', __METHOD__, $src, $dest, $stream->getError())); } return true; } if (is_writable($baseDir) && move_uploaded_file($src, $dest)) { // Short circuit to prevent file permission errors if (Path::setPermissions($dest)) { return true; } throw new FilesystemException(__METHOD__ . ': Failed to change file permissions.'); } throw new FilesystemException(__METHOD__ . ': Failed to move file.'); } } home/wuectly/www/libraries/vendor/paragonie/sodium_compat/src/File.php 0000604 00000147501 15245670444 0022273 0 ustar 00 <?php if (class_exists('ParagonIE_Sodium_File', false)) { return; } /** * Class ParagonIE_Sodium_File */ class ParagonIE_Sodium_File extends ParagonIE_Sodium_Core_Util { /* PHP's default buffer size is 8192 for fread()/fwrite(). */ const BUFFER_SIZE = 8192; /** * Box a file (rather than a string). Uses less memory than * ParagonIE_Sodium_Compat::crypto_box(), but produces * the same result. * * @param string $inputFile Absolute path to a file on the filesystem * @param string $outputFile Absolute path to a file on the filesystem * @param string $nonce Number to be used only once * @param string $keyPair ECDH secret key and ECDH public key concatenated * * @return bool * @throws SodiumException * @throws TypeError */ public static function box($inputFile, $outputFile, $nonce, $keyPair) { /* Type checks: */ if (!is_string($inputFile)) { throw new TypeError('Argument 1 must be a string, ' . gettype($inputFile) . ' given.'); } if (!is_string($outputFile)) { throw new TypeError('Argument 2 must be a string, ' . gettype($outputFile) . ' given.'); } if (!is_string($nonce)) { throw new TypeError('Argument 3 must be a string, ' . gettype($nonce) . ' given.'); } /* Input validation: */ if (!is_string($keyPair)) { throw new TypeError('Argument 4 must be a string, ' . gettype($keyPair) . ' given.'); } if (self::strlen($nonce) !== ParagonIE_Sodium_Compat::CRYPTO_BOX_NONCEBYTES) { throw new TypeError('Argument 3 must be CRYPTO_BOX_NONCEBYTES bytes'); } if (self::strlen($keyPair) !== ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES) { throw new TypeError('Argument 4 must be CRYPTO_BOX_KEYPAIRBYTES bytes'); } /** @var int $size */ $size = filesize($inputFile); if (!is_int($size)) { throw new SodiumException('Could not obtain the file size'); } /** @var resource $ifp */ $ifp = fopen($inputFile, 'rb'); if (!is_resource($ifp)) { throw new SodiumException('Could not open input file for reading'); } /** @var resource $ofp */ $ofp = fopen($outputFile, 'wb'); if (!is_resource($ofp)) { fclose($ifp); throw new SodiumException('Could not open output file for writing'); } $res = self::box_encrypt($ifp, $ofp, $size, $nonce, $keyPair); fclose($ifp); fclose($ofp); return $res; } /** * Open a boxed file (rather than a string). Uses less memory than * ParagonIE_Sodium_Compat::crypto_box_open(), but produces * the same result. * * Warning: Does not protect against TOCTOU attacks. You should * just load the file into memory and use crypto_box_open() if * you are worried about those. * * @param string $inputFile * @param string $outputFile * @param string $nonce * @param string $keypair * @return bool * @throws SodiumException * @throws TypeError */ public static function box_open($inputFile, $outputFile, $nonce, $keypair) { /* Type checks: */ if (!is_string($inputFile)) { throw new TypeError('Argument 1 must be a string, ' . gettype($inputFile) . ' given.'); } if (!is_string($outputFile)) { throw new TypeError('Argument 2 must be a string, ' . gettype($outputFile) . ' given.'); } if (!is_string($nonce)) { throw new TypeError('Argument 3 must be a string, ' . gettype($nonce) . ' given.'); } if (!is_string($keypair)) { throw new TypeError('Argument 4 must be a string, ' . gettype($keypair) . ' given.'); } /* Input validation: */ if (self::strlen($nonce) !== ParagonIE_Sodium_Compat::CRYPTO_BOX_NONCEBYTES) { throw new TypeError('Argument 4 must be CRYPTO_BOX_NONCEBYTES bytes'); } if (self::strlen($keypair) !== ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES) { throw new TypeError('Argument 4 must be CRYPTO_BOX_KEYPAIRBYTES bytes'); } /** @var int $size */ $size = filesize($inputFile); if (!is_int($size)) { throw new SodiumException('Could not obtain the file size'); } /** @var resource $ifp */ $ifp = fopen($inputFile, 'rb'); if (!is_resource($ifp)) { throw new SodiumException('Could not open input file for reading'); } /** @var resource $ofp */ $ofp = fopen($outputFile, 'wb'); if (!is_resource($ofp)) { fclose($ifp); throw new SodiumException('Could not open output file for writing'); } $res = self::box_decrypt($ifp, $ofp, $size, $nonce, $keypair); fclose($ifp); fclose($ofp); try { ParagonIE_Sodium_Compat::memzero($nonce); ParagonIE_Sodium_Compat::memzero($ephKeypair); } catch (SodiumException $ex) { if (isset($ephKeypair)) { unset($ephKeypair); } } return $res; } /** * Seal a file (rather than a string). Uses less memory than * ParagonIE_Sodium_Compat::crypto_box_seal(), but produces * the same result. * * @param string $inputFile Absolute path to a file on the filesystem * @param string $outputFile Absolute path to a file on the filesystem * @param string $publicKey ECDH public key * * @return bool * @throws SodiumException * @throws TypeError */ public static function box_seal($inputFile, $outputFile, $publicKey) { /* Type checks: */ if (!is_string($inputFile)) { throw new TypeError('Argument 1 must be a string, ' . gettype($inputFile) . ' given.'); } if (!is_string($outputFile)) { throw new TypeError('Argument 2 must be a string, ' . gettype($outputFile) . ' given.'); } if (!is_string($publicKey)) { throw new TypeError('Argument 3 must be a string, ' . gettype($publicKey) . ' given.'); } /* Input validation: */ if (self::strlen($publicKey) !== ParagonIE_Sodium_Compat::CRYPTO_BOX_PUBLICKEYBYTES) { throw new TypeError('Argument 3 must be CRYPTO_BOX_PUBLICKEYBYTES bytes'); } /** @var int $size */ $size = filesize($inputFile); if (!is_int($size)) { throw new SodiumException('Could not obtain the file size'); } /** @var resource $ifp */ $ifp = fopen($inputFile, 'rb'); if (!is_resource($ifp)) { throw new SodiumException('Could not open input file for reading'); } /** @var resource $ofp */ $ofp = fopen($outputFile, 'wb'); if (!is_resource($ofp)) { fclose($ifp); throw new SodiumException('Could not open output file for writing'); } /** @var string $ephKeypair */ $ephKeypair = ParagonIE_Sodium_Compat::crypto_box_keypair(); /** @var string $msgKeypair */ $msgKeypair = ParagonIE_Sodium_Compat::crypto_box_keypair_from_secretkey_and_publickey( ParagonIE_Sodium_Compat::crypto_box_secretkey($ephKeypair), $publicKey ); /** @var string $ephemeralPK */ $ephemeralPK = ParagonIE_Sodium_Compat::crypto_box_publickey($ephKeypair); /** @var string $nonce */ $nonce = ParagonIE_Sodium_Compat::crypto_generichash( $ephemeralPK . $publicKey, '', 24 ); /** @var int $firstWrite */ $firstWrite = fwrite( $ofp, $ephemeralPK, ParagonIE_Sodium_Compat::CRYPTO_BOX_PUBLICKEYBYTES ); if (!is_int($firstWrite)) { fclose($ifp); fclose($ofp); ParagonIE_Sodium_Compat::memzero($ephKeypair); throw new SodiumException('Could not write to output file'); } if ($firstWrite !== ParagonIE_Sodium_Compat::CRYPTO_BOX_PUBLICKEYBYTES) { ParagonIE_Sodium_Compat::memzero($ephKeypair); fclose($ifp); fclose($ofp); throw new SodiumException('Error writing public key to output file'); } $res = self::box_encrypt($ifp, $ofp, $size, $nonce, $msgKeypair); fclose($ifp); fclose($ofp); try { ParagonIE_Sodium_Compat::memzero($nonce); ParagonIE_Sodium_Compat::memzero($ephKeypair); } catch (SodiumException $ex) { /** @psalm-suppress PossiblyUndefinedVariable */ unset($ephKeypair); } return $res; } /** * Open a sealed file (rather than a string). Uses less memory than * ParagonIE_Sodium_Compat::crypto_box_seal_open(), but produces * the same result. * * Warning: Does not protect against TOCTOU attacks. You should * just load the file into memory and use crypto_box_seal_open() if * you are worried about those. * * @param string $inputFile * @param string $outputFile * @param string $ecdhKeypair * @return bool * @throws SodiumException * @throws TypeError */ public static function box_seal_open($inputFile, $outputFile, $ecdhKeypair) { /* Type checks: */ if (!is_string($inputFile)) { throw new TypeError('Argument 1 must be a string, ' . gettype($inputFile) . ' given.'); } if (!is_string($outputFile)) { throw new TypeError('Argument 2 must be a string, ' . gettype($outputFile) . ' given.'); } if (!is_string($ecdhKeypair)) { throw new TypeError('Argument 3 must be a string, ' . gettype($ecdhKeypair) . ' given.'); } /* Input validation: */ if (self::strlen($ecdhKeypair) !== ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES) { throw new TypeError('Argument 3 must be CRYPTO_BOX_KEYPAIRBYTES bytes'); } $publicKey = ParagonIE_Sodium_Compat::crypto_box_publickey($ecdhKeypair); /** @var int $size */ $size = filesize($inputFile); if (!is_int($size)) { throw new SodiumException('Could not obtain the file size'); } /** @var resource $ifp */ $ifp = fopen($inputFile, 'rb'); if (!is_resource($ifp)) { throw new SodiumException('Could not open input file for reading'); } /** @var resource $ofp */ $ofp = fopen($outputFile, 'wb'); if (!is_resource($ofp)) { fclose($ifp); throw new SodiumException('Could not open output file for writing'); } $ephemeralPK = fread($ifp, ParagonIE_Sodium_Compat::CRYPTO_BOX_PUBLICKEYBYTES); if (!is_string($ephemeralPK)) { throw new SodiumException('Could not read input file'); } if (self::strlen($ephemeralPK) !== ParagonIE_Sodium_Compat::CRYPTO_BOX_PUBLICKEYBYTES) { fclose($ifp); fclose($ofp); throw new SodiumException('Could not read public key from sealed file'); } $nonce = ParagonIE_Sodium_Compat::crypto_generichash( $ephemeralPK . $publicKey, '', 24 ); $msgKeypair = ParagonIE_Sodium_Compat::crypto_box_keypair_from_secretkey_and_publickey( ParagonIE_Sodium_Compat::crypto_box_secretkey($ecdhKeypair), $ephemeralPK ); $res = self::box_decrypt($ifp, $ofp, $size, $nonce, $msgKeypair); fclose($ifp); fclose($ofp); try { ParagonIE_Sodium_Compat::memzero($nonce); ParagonIE_Sodium_Compat::memzero($ephKeypair); } catch (SodiumException $ex) { if (isset($ephKeypair)) { unset($ephKeypair); } } return $res; } /** * Calculate the BLAKE2b hash of a file. * * @param string $filePath Absolute path to a file on the filesystem * @param string|null $key BLAKE2b key * @param int $outputLength Length of hash output * * @return string BLAKE2b hash * @throws SodiumException * @throws TypeError * @psalm-suppress FailedTypeResolution */ public static function generichash($filePath, $key = '', $outputLength = 32) { /* Type checks: */ if (!is_string($filePath)) { throw new TypeError('Argument 1 must be a string, ' . gettype($filePath) . ' given.'); } if (!is_string($key)) { if (is_null($key)) { $key = ''; } else { throw new TypeError('Argument 2 must be a string, ' . gettype($key) . ' given.'); } } if (!is_int($outputLength)) { if (!is_numeric($outputLength)) { throw new TypeError('Argument 3 must be an integer, ' . gettype($outputLength) . ' given.'); } $outputLength = (int) $outputLength; } /* Input validation: */ if (!empty($key)) { if (self::strlen($key) < ParagonIE_Sodium_Compat::CRYPTO_GENERICHASH_KEYBYTES_MIN) { throw new TypeError('Argument 2 must be at least CRYPTO_GENERICHASH_KEYBYTES_MIN bytes'); } if (self::strlen($key) > ParagonIE_Sodium_Compat::CRYPTO_GENERICHASH_KEYBYTES_MAX) { throw new TypeError('Argument 2 must be at most CRYPTO_GENERICHASH_KEYBYTES_MAX bytes'); } } if ($outputLength < ParagonIE_Sodium_Compat::CRYPTO_GENERICHASH_BYTES_MIN) { throw new SodiumException('Argument 3 must be at least CRYPTO_GENERICHASH_BYTES_MIN'); } if ($outputLength > ParagonIE_Sodium_Compat::CRYPTO_GENERICHASH_BYTES_MAX) { throw new SodiumException('Argument 3 must be at least CRYPTO_GENERICHASH_BYTES_MAX'); } /** @var int $size */ $size = filesize($filePath); if (!is_int($size)) { throw new SodiumException('Could not obtain the file size'); } /** @var resource $fp */ $fp = fopen($filePath, 'rb'); if (!is_resource($fp)) { throw new SodiumException('Could not open input file for reading'); } $ctx = ParagonIE_Sodium_Compat::crypto_generichash_init($key, $outputLength); while ($size > 0) { $blockSize = $size > 64 ? 64 : $size; $read = fread($fp, $blockSize); if (!is_string($read)) { throw new SodiumException('Could not read input file'); } ParagonIE_Sodium_Compat::crypto_generichash_update($ctx, $read); $size -= $blockSize; } fclose($fp); return ParagonIE_Sodium_Compat::crypto_generichash_final($ctx, $outputLength); } /** * Encrypt a file (rather than a string). Uses less memory than * ParagonIE_Sodium_Compat::crypto_secretbox(), but produces * the same result. * * @param string $inputFile Absolute path to a file on the filesystem * @param string $outputFile Absolute path to a file on the filesystem * @param string $nonce Number to be used only once * @param string $key Encryption key * * @return bool * @throws SodiumException * @throws TypeError */ public static function secretbox($inputFile, $outputFile, $nonce, $key) { /* Type checks: */ if (!is_string($inputFile)) { throw new TypeError('Argument 1 must be a string, ' . gettype($inputFile) . ' given..'); } if (!is_string($outputFile)) { throw new TypeError('Argument 2 must be a string, ' . gettype($outputFile) . ' given.'); } if (!is_string($nonce)) { throw new TypeError('Argument 3 must be a string, ' . gettype($nonce) . ' given.'); } /* Input validation: */ if (self::strlen($nonce) !== ParagonIE_Sodium_Compat::CRYPTO_SECRETBOX_NONCEBYTES) { throw new TypeError('Argument 3 must be CRYPTO_SECRETBOX_NONCEBYTES bytes'); } if (!is_string($key)) { throw new TypeError('Argument 4 must be a string, ' . gettype($key) . ' given.'); } if (self::strlen($key) !== ParagonIE_Sodium_Compat::CRYPTO_SECRETBOX_KEYBYTES) { throw new TypeError('Argument 4 must be CRYPTO_SECRETBOX_KEYBYTES bytes'); } /** @var int $size */ $size = filesize($inputFile); if (!is_int($size)) { throw new SodiumException('Could not obtain the file size'); } /** @var resource $ifp */ $ifp = fopen($inputFile, 'rb'); if (!is_resource($ifp)) { throw new SodiumException('Could not open input file for reading'); } /** @var resource $ofp */ $ofp = fopen($outputFile, 'wb'); if (!is_resource($ofp)) { fclose($ifp); throw new SodiumException('Could not open output file for writing'); } $res = self::secretbox_encrypt($ifp, $ofp, $size, $nonce, $key); fclose($ifp); fclose($ofp); return $res; } /** * Seal a file (rather than a string). Uses less memory than * ParagonIE_Sodium_Compat::crypto_secretbox_open(), but produces * the same result. * * Warning: Does not protect against TOCTOU attacks. You should * just load the file into memory and use crypto_secretbox_open() if * you are worried about those. * * @param string $inputFile * @param string $outputFile * @param string $nonce * @param string $key * @return bool * @throws SodiumException * @throws TypeError */ public static function secretbox_open($inputFile, $outputFile, $nonce, $key) { /* Type checks: */ if (!is_string($inputFile)) { throw new TypeError('Argument 1 must be a string, ' . gettype($inputFile) . ' given.'); } if (!is_string($outputFile)) { throw new TypeError('Argument 2 must be a string, ' . gettype($outputFile) . ' given.'); } if (!is_string($nonce)) { throw new TypeError('Argument 3 must be a string, ' . gettype($nonce) . ' given.'); } if (!is_string($key)) { throw new TypeError('Argument 4 must be a string, ' . gettype($key) . ' given.'); } /* Input validation: */ if (self::strlen($nonce) !== ParagonIE_Sodium_Compat::CRYPTO_SECRETBOX_NONCEBYTES) { throw new TypeError('Argument 4 must be CRYPTO_SECRETBOX_NONCEBYTES bytes'); } if (self::strlen($key) !== ParagonIE_Sodium_Compat::CRYPTO_SECRETBOX_KEYBYTES) { throw new TypeError('Argument 4 must be CRYPTO_SECRETBOXBOX_KEYBYTES bytes'); } /** @var int $size */ $size = filesize($inputFile); if (!is_int($size)) { throw new SodiumException('Could not obtain the file size'); } /** @var resource $ifp */ $ifp = fopen($inputFile, 'rb'); if (!is_resource($ifp)) { throw new SodiumException('Could not open input file for reading'); } /** @var resource $ofp */ $ofp = fopen($outputFile, 'wb'); if (!is_resource($ofp)) { fclose($ifp); throw new SodiumException('Could not open output file for writing'); } $res = self::secretbox_decrypt($ifp, $ofp, $size, $nonce, $key); fclose($ifp); fclose($ofp); try { ParagonIE_Sodium_Compat::memzero($key); } catch (SodiumException $ex) { /** @psalm-suppress PossiblyUndefinedVariable */ unset($key); } return $res; } /** * Sign a file (rather than a string). Uses less memory than * ParagonIE_Sodium_Compat::crypto_sign_detached(), but produces * the same result. * * @param string $filePath Absolute path to a file on the filesystem * @param string $secretKey Secret signing key * * @return string Ed25519 signature * @throws SodiumException * @throws TypeError */ public static function sign($filePath, $secretKey) { /* Type checks: */ if (!is_string($filePath)) { throw new TypeError('Argument 1 must be a string, ' . gettype($filePath) . ' given.'); } if (!is_string($secretKey)) { throw new TypeError('Argument 2 must be a string, ' . gettype($secretKey) . ' given.'); } /* Input validation: */ if (self::strlen($secretKey) !== ParagonIE_Sodium_Compat::CRYPTO_SIGN_SECRETKEYBYTES) { throw new TypeError('Argument 2 must be CRYPTO_SIGN_SECRETKEYBYTES bytes'); } if (PHP_INT_SIZE === 4) { return self::sign_core32($filePath, $secretKey); } /** @var int $size */ $size = filesize($filePath); if (!is_int($size)) { throw new SodiumException('Could not obtain the file size'); } /** @var resource $fp */ $fp = fopen($filePath, 'rb'); if (!is_resource($fp)) { throw new SodiumException('Could not open input file for reading'); } /** @var string $az */ $az = hash('sha512', self::substr($secretKey, 0, 32), true); $az[0] = self::intToChr(self::chrToInt($az[0]) & 248); $az[31] = self::intToChr((self::chrToInt($az[31]) & 63) | 64); $hs = hash_init('sha512'); self::hash_update($hs, self::substr($az, 32, 32)); /** @var resource $hs */ $hs = self::updateHashWithFile($hs, $fp, $size); /** @var string $nonceHash */ $nonceHash = hash_final($hs, true); /** @var string $pk */ $pk = self::substr($secretKey, 32, 32); /** @var string $nonce */ $nonce = ParagonIE_Sodium_Core_Ed25519::sc_reduce($nonceHash) . self::substr($nonceHash, 32); /** @var string $sig */ $sig = ParagonIE_Sodium_Core_Ed25519::ge_p3_tobytes( ParagonIE_Sodium_Core_Ed25519::ge_scalarmult_base($nonce) ); $hs = hash_init('sha512'); self::hash_update($hs, self::substr($sig, 0, 32)); self::hash_update($hs, self::substr($pk, 0, 32)); /** @var resource $hs */ $hs = self::updateHashWithFile($hs, $fp, $size); /** @var string $hramHash */ $hramHash = hash_final($hs, true); /** @var string $hram */ $hram = ParagonIE_Sodium_Core_Ed25519::sc_reduce($hramHash); /** @var string $sigAfter */ $sigAfter = ParagonIE_Sodium_Core_Ed25519::sc_muladd($hram, $az, $nonce); /** @var string $sig */ $sig = self::substr($sig, 0, 32) . self::substr($sigAfter, 0, 32); try { ParagonIE_Sodium_Compat::memzero($az); } catch (SodiumException $ex) { $az = null; } fclose($fp); return $sig; } /** * Verify a file (rather than a string). Uses less memory than * ParagonIE_Sodium_Compat::crypto_sign_verify_detached(), but * produces the same result. * * @param string $sig Ed25519 signature * @param string $filePath Absolute path to a file on the filesystem * @param string $publicKey Signing public key * * @return bool * @throws SodiumException * @throws TypeError * @throws Exception */ public static function verify($sig, $filePath, $publicKey) { /* Type checks: */ if (!is_string($sig)) { throw new TypeError('Argument 1 must be a string, ' . gettype($sig) . ' given.'); } if (!is_string($filePath)) { throw new TypeError('Argument 2 must be a string, ' . gettype($filePath) . ' given.'); } if (!is_string($publicKey)) { throw new TypeError('Argument 3 must be a string, ' . gettype($publicKey) . ' given.'); } /* Input validation: */ if (self::strlen($sig) !== ParagonIE_Sodium_Compat::CRYPTO_SIGN_BYTES) { throw new TypeError('Argument 1 must be CRYPTO_SIGN_BYTES bytes'); } if (self::strlen($publicKey) !== ParagonIE_Sodium_Compat::CRYPTO_SIGN_PUBLICKEYBYTES) { throw new TypeError('Argument 3 must be CRYPTO_SIGN_PUBLICKEYBYTES bytes'); } if (self::strlen($sig) < 64) { throw new SodiumException('Signature is too short'); } if (PHP_INT_SIZE === 4) { return self::verify_core32($sig, $filePath, $publicKey); } /* Security checks */ if ( (ParagonIE_Sodium_Core_Ed25519::chrToInt($sig[63]) & 240) && ParagonIE_Sodium_Core_Ed25519::check_S_lt_L(self::substr($sig, 32, 32)) ) { throw new SodiumException('S < L - Invalid signature'); } if (ParagonIE_Sodium_Core_Ed25519::small_order($sig)) { throw new SodiumException('Signature is on too small of an order'); } if ((self::chrToInt($sig[63]) & 224) !== 0) { throw new SodiumException('Invalid signature'); } $d = 0; for ($i = 0; $i < 32; ++$i) { $d |= self::chrToInt($publicKey[$i]); } if ($d === 0) { throw new SodiumException('All zero public key'); } /** @var int $size */ $size = filesize($filePath); if (!is_int($size)) { throw new SodiumException('Could not obtain the file size'); } /** @var resource $fp */ $fp = fopen($filePath, 'rb'); if (!is_resource($fp)) { throw new SodiumException('Could not open input file for reading'); } /** @var bool The original value of ParagonIE_Sodium_Compat::$fastMult */ $orig = ParagonIE_Sodium_Compat::$fastMult; // Set ParagonIE_Sodium_Compat::$fastMult to true to speed up verification. ParagonIE_Sodium_Compat::$fastMult = true; /** @var ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A */ $A = ParagonIE_Sodium_Core_Ed25519::ge_frombytes_negate_vartime($publicKey); $hs = hash_init('sha512'); self::hash_update($hs, self::substr($sig, 0, 32)); self::hash_update($hs, self::substr($publicKey, 0, 32)); /** @var resource $hs */ $hs = self::updateHashWithFile($hs, $fp, $size); /** @var string $hDigest */ $hDigest = hash_final($hs, true); /** @var string $h */ $h = ParagonIE_Sodium_Core_Ed25519::sc_reduce($hDigest) . self::substr($hDigest, 32); /** @var ParagonIE_Sodium_Core_Curve25519_Ge_P2 $R */ $R = ParagonIE_Sodium_Core_Ed25519::ge_double_scalarmult_vartime( $h, $A, self::substr($sig, 32) ); /** @var string $rcheck */ $rcheck = ParagonIE_Sodium_Core_Ed25519::ge_tobytes($R); // Close the file handle fclose($fp); // Reset ParagonIE_Sodium_Compat::$fastMult to what it was before. ParagonIE_Sodium_Compat::$fastMult = $orig; return self::verify_32($rcheck, self::substr($sig, 0, 32)); } /** * @param resource $ifp * @param resource $ofp * @param int $mlen * @param string $nonce * @param string $boxKeypair * @return bool * @throws SodiumException * @throws TypeError */ protected static function box_encrypt($ifp, $ofp, $mlen, $nonce, $boxKeypair) { if (PHP_INT_SIZE === 4) { return self::secretbox_encrypt( $ifp, $ofp, $mlen, $nonce, ParagonIE_Sodium_Crypto32::box_beforenm( ParagonIE_Sodium_Crypto32::box_secretkey($boxKeypair), ParagonIE_Sodium_Crypto32::box_publickey($boxKeypair) ) ); } return self::secretbox_encrypt( $ifp, $ofp, $mlen, $nonce, ParagonIE_Sodium_Crypto::box_beforenm( ParagonIE_Sodium_Crypto::box_secretkey($boxKeypair), ParagonIE_Sodium_Crypto::box_publickey($boxKeypair) ) ); } /** * @param resource $ifp * @param resource $ofp * @param int $mlen * @param string $nonce * @param string $boxKeypair * @return bool * @throws SodiumException * @throws TypeError */ protected static function box_decrypt($ifp, $ofp, $mlen, $nonce, $boxKeypair) { if (PHP_INT_SIZE === 4) { return self::secretbox_decrypt( $ifp, $ofp, $mlen, $nonce, ParagonIE_Sodium_Crypto32::box_beforenm( ParagonIE_Sodium_Crypto32::box_secretkey($boxKeypair), ParagonIE_Sodium_Crypto32::box_publickey($boxKeypair) ) ); } return self::secretbox_decrypt( $ifp, $ofp, $mlen, $nonce, ParagonIE_Sodium_Crypto::box_beforenm( ParagonIE_Sodium_Crypto::box_secretkey($boxKeypair), ParagonIE_Sodium_Crypto::box_publickey($boxKeypair) ) ); } /** * Encrypt a file * * @param resource $ifp * @param resource $ofp * @param int $mlen * @param string $nonce * @param string $key * @return bool * @throws SodiumException * @throws TypeError */ protected static function secretbox_encrypt($ifp, $ofp, $mlen, $nonce, $key) { if (PHP_INT_SIZE === 4) { return self::secretbox_encrypt_core32($ifp, $ofp, $mlen, $nonce, $key); } $plaintext = fread($ifp, 32); if (!is_string($plaintext)) { throw new SodiumException('Could not read input file'); } $first32 = self::ftell($ifp); /** @var string $subkey */ $subkey = ParagonIE_Sodium_Core_HSalsa20::hsalsa20($nonce, $key); /** @var string $realNonce */ $realNonce = ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8); /** @var string $block0 */ $block0 = str_repeat("\x00", 32); /** @var int $mlen - Length of the plaintext message */ $mlen0 = $mlen; if ($mlen0 > 64 - ParagonIE_Sodium_Crypto::secretbox_xsalsa20poly1305_ZEROBYTES) { $mlen0 = 64 - ParagonIE_Sodium_Crypto::secretbox_xsalsa20poly1305_ZEROBYTES; } $block0 .= ParagonIE_Sodium_Core_Util::substr($plaintext, 0, $mlen0); /** @var string $block0 */ $block0 = ParagonIE_Sodium_Core_Salsa20::salsa20_xor( $block0, $realNonce, $subkey ); $state = new ParagonIE_Sodium_Core_Poly1305_State( ParagonIE_Sodium_Core_Util::substr( $block0, 0, ParagonIE_Sodium_Crypto::onetimeauth_poly1305_KEYBYTES ) ); // Pre-write 16 blank bytes for the Poly1305 tag $start = self::ftell($ofp); fwrite($ofp, str_repeat("\x00", 16)); /** @var string $c */ $cBlock = ParagonIE_Sodium_Core_Util::substr( $block0, ParagonIE_Sodium_Crypto::secretbox_xsalsa20poly1305_ZEROBYTES ); $state->update($cBlock); fwrite($ofp, $cBlock); $mlen -= 32; /** @var int $iter */ $iter = 1; /** @var int $incr */ $incr = self::BUFFER_SIZE >> 6; /* * Set the cursor to the end of the first half-block. All future bytes will * generated from salsa20_xor_ic, starting from 1 (second block). */ fseek($ifp, $first32, SEEK_SET); while ($mlen > 0) { $blockSize = $mlen > self::BUFFER_SIZE ? self::BUFFER_SIZE : $mlen; $plaintext = fread($ifp, $blockSize); if (!is_string($plaintext)) { throw new SodiumException('Could not read input file'); } $cBlock = ParagonIE_Sodium_Core_Salsa20::salsa20_xor_ic( $plaintext, $realNonce, $iter, $subkey ); fwrite($ofp, $cBlock, $blockSize); $state->update($cBlock); $mlen -= $blockSize; $iter += $incr; } try { ParagonIE_Sodium_Compat::memzero($block0); ParagonIE_Sodium_Compat::memzero($subkey); } catch (SodiumException $ex) { $block0 = null; $subkey = null; } $end = self::ftell($ofp); /* * Write the Poly1305 authentication tag that provides integrity * over the ciphertext (encrypt-then-MAC) */ fseek($ofp, $start, SEEK_SET); fwrite($ofp, $state->finish(), ParagonIE_Sodium_Compat::CRYPTO_SECRETBOX_MACBYTES); fseek($ofp, $end, SEEK_SET); unset($state); return true; } /** * Decrypt a file * * @param resource $ifp * @param resource $ofp * @param int $mlen * @param string $nonce * @param string $key * @return bool * @throws SodiumException * @throws TypeError */ protected static function secretbox_decrypt($ifp, $ofp, $mlen, $nonce, $key) { if (PHP_INT_SIZE === 4) { return self::secretbox_decrypt_core32($ifp, $ofp, $mlen, $nonce, $key); } $tag = fread($ifp, 16); if (!is_string($tag)) { throw new SodiumException('Could not read input file'); } /** @var string $subkey */ $subkey = ParagonIE_Sodium_Core_HSalsa20::hsalsa20($nonce, $key); /** @var string $realNonce */ $realNonce = ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8); /** @var string $block0 */ $block0 = ParagonIE_Sodium_Core_Salsa20::salsa20( 64, ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8), $subkey ); /* Verify the Poly1305 MAC -before- attempting to decrypt! */ $state = new ParagonIE_Sodium_Core_Poly1305_State(self::substr($block0, 0, 32)); if (!self::onetimeauth_verify($state, $ifp, $tag, $mlen)) { throw new SodiumException('Invalid MAC'); } /* * Set the cursor to the end of the first half-block. All future bytes will * generated from salsa20_xor_ic, starting from 1 (second block). */ $first32 = fread($ifp, 32); if (!is_string($first32)) { throw new SodiumException('Could not read input file'); } $first32len = self::strlen($first32); fwrite( $ofp, self::xorStrings( self::substr($block0, 32, $first32len), self::substr($first32, 0, $first32len) ) ); $mlen -= 32; /** @var int $iter */ $iter = 1; /** @var int $incr */ $incr = self::BUFFER_SIZE >> 6; /* Decrypts ciphertext, writes to output file. */ while ($mlen > 0) { $blockSize = $mlen > self::BUFFER_SIZE ? self::BUFFER_SIZE : $mlen; $ciphertext = fread($ifp, $blockSize); if (!is_string($ciphertext)) { throw new SodiumException('Could not read input file'); } $pBlock = ParagonIE_Sodium_Core_Salsa20::salsa20_xor_ic( $ciphertext, $realNonce, $iter, $subkey ); fwrite($ofp, $pBlock, $blockSize); $mlen -= $blockSize; $iter += $incr; } return true; } /** * @param ParagonIE_Sodium_Core_Poly1305_State $state * @param resource $ifp * @param string $tag * @param int $mlen * @return bool * @throws SodiumException * @throws TypeError */ protected static function onetimeauth_verify( ParagonIE_Sodium_Core_Poly1305_State $state, $ifp, $tag = '', $mlen = 0 ) { /** @var int $pos */ $pos = self::ftell($ifp); /** @var int $iter */ $iter = 1; /** @var int $incr */ $incr = self::BUFFER_SIZE >> 6; while ($mlen > 0) { $blockSize = $mlen > self::BUFFER_SIZE ? self::BUFFER_SIZE : $mlen; $ciphertext = fread($ifp, $blockSize); if (!is_string($ciphertext)) { throw new SodiumException('Could not read input file'); } $state->update($ciphertext); $mlen -= $blockSize; $iter += $incr; } $res = ParagonIE_Sodium_Core_Util::verify_16($tag, $state->finish()); fseek($ifp, $pos, SEEK_SET); return $res; } /** * Update a hash context with the contents of a file, without * loading the entire file into memory. * * @param resource|HashContext $hash * @param resource $fp * @param int $size * @return resource|object Resource on PHP < 7.2, HashContext object on PHP >= 7.2 * @throws SodiumException * @throws TypeError * @psalm-suppress PossiblyInvalidArgument * PHP 7.2 changes from a resource to an object, * which causes Psalm to complain about an error. * @psalm-suppress TypeCoercion * Ditto. */ public static function updateHashWithFile($hash, $fp, $size = 0) { /* Type checks: */ if (PHP_VERSION_ID < 70200) { if (!is_resource($hash)) { throw new TypeError('Argument 1 must be a resource, ' . gettype($hash) . ' given.'); } } else { if (!is_object($hash)) { throw new TypeError('Argument 1 must be an object (PHP 7.2+), ' . gettype($hash) . ' given.'); } } if (!is_resource($fp)) { throw new TypeError('Argument 2 must be a resource, ' . gettype($fp) . ' given.'); } if (!is_int($size)) { throw new TypeError('Argument 3 must be an integer, ' . gettype($size) . ' given.'); } /** @var int $originalPosition */ $originalPosition = self::ftell($fp); // Move file pointer to beginning of file fseek($fp, 0, SEEK_SET); for ($i = 0; $i < $size; $i += self::BUFFER_SIZE) { /** @var string|bool $message */ $message = fread( $fp, ($size - $i) > self::BUFFER_SIZE ? $size - $i : self::BUFFER_SIZE ); if (!is_string($message)) { throw new SodiumException('Unexpected error reading from file.'); } /** @var string $message */ /** @psalm-suppress InvalidArgument */ self::hash_update($hash, $message); } // Reset file pointer's position fseek($fp, $originalPosition, SEEK_SET); return $hash; } /** * Sign a file (rather than a string). Uses less memory than * ParagonIE_Sodium_Compat::crypto_sign_detached(), but produces * the same result. (32-bit) * * @param string $filePath Absolute path to a file on the filesystem * @param string $secretKey Secret signing key * * @return string Ed25519 signature * @throws SodiumException * @throws TypeError */ private static function sign_core32($filePath, $secretKey) { $size = filesize($filePath); if (!is_int($size)) { throw new SodiumException('Could not obtain the file size'); } $fp = fopen($filePath, 'rb'); if (!is_resource($fp)) { throw new SodiumException('Could not open input file for reading'); } /** @var string $az */ $az = hash('sha512', self::substr($secretKey, 0, 32), true); $az[0] = self::intToChr(self::chrToInt($az[0]) & 248); $az[31] = self::intToChr((self::chrToInt($az[31]) & 63) | 64); $hs = hash_init('sha512'); self::hash_update($hs, self::substr($az, 32, 32)); /** @var resource $hs */ $hs = self::updateHashWithFile($hs, $fp, $size); $nonceHash = hash_final($hs, true); $pk = self::substr($secretKey, 32, 32); $nonce = ParagonIE_Sodium_Core32_Ed25519::sc_reduce($nonceHash) . self::substr($nonceHash, 32); $sig = ParagonIE_Sodium_Core32_Ed25519::ge_p3_tobytes( ParagonIE_Sodium_Core32_Ed25519::ge_scalarmult_base($nonce) ); $hs = hash_init('sha512'); self::hash_update($hs, self::substr($sig, 0, 32)); self::hash_update($hs, self::substr($pk, 0, 32)); /** @var resource $hs */ $hs = self::updateHashWithFile($hs, $fp, $size); $hramHash = hash_final($hs, true); $hram = ParagonIE_Sodium_Core32_Ed25519::sc_reduce($hramHash); $sigAfter = ParagonIE_Sodium_Core32_Ed25519::sc_muladd($hram, $az, $nonce); /** @var string $sig */ $sig = self::substr($sig, 0, 32) . self::substr($sigAfter, 0, 32); try { ParagonIE_Sodium_Compat::memzero($az); } catch (SodiumException $ex) { $az = null; } fclose($fp); return $sig; } /** * * Verify a file (rather than a string). Uses less memory than * ParagonIE_Sodium_Compat::crypto_sign_verify_detached(), but * produces the same result. (32-bit) * * @param string $sig Ed25519 signature * @param string $filePath Absolute path to a file on the filesystem * @param string $publicKey Signing public key * * @return bool * @throws SodiumException * @throws Exception */ public static function verify_core32($sig, $filePath, $publicKey) { /* Security checks */ if (ParagonIE_Sodium_Core32_Ed25519::check_S_lt_L(self::substr($sig, 32, 32))) { throw new SodiumException('S < L - Invalid signature'); } if (ParagonIE_Sodium_Core32_Ed25519::small_order($sig)) { throw new SodiumException('Signature is on too small of an order'); } if ((self::chrToInt($sig[63]) & 224) !== 0) { throw new SodiumException('Invalid signature'); } $d = 0; for ($i = 0; $i < 32; ++$i) { $d |= self::chrToInt($publicKey[$i]); } if ($d === 0) { throw new SodiumException('All zero public key'); } /** @var int|bool $size */ $size = filesize($filePath); if (!is_int($size)) { throw new SodiumException('Could not obtain the file size'); } /** @var int $size */ /** @var resource|bool $fp */ $fp = fopen($filePath, 'rb'); if (!is_resource($fp)) { throw new SodiumException('Could not open input file for reading'); } /** @var resource $fp */ /** @var bool The original value of ParagonIE_Sodium_Compat::$fastMult */ $orig = ParagonIE_Sodium_Compat::$fastMult; // Set ParagonIE_Sodium_Compat::$fastMult to true to speed up verification. ParagonIE_Sodium_Compat::$fastMult = true; /** @var ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $A */ $A = ParagonIE_Sodium_Core32_Ed25519::ge_frombytes_negate_vartime($publicKey); $hs = hash_init('sha512'); self::hash_update($hs, self::substr($sig, 0, 32)); self::hash_update($hs, self::substr($publicKey, 0, 32)); /** @var resource $hs */ $hs = self::updateHashWithFile($hs, $fp, $size); /** @var string $hDigest */ $hDigest = hash_final($hs, true); /** @var string $h */ $h = ParagonIE_Sodium_Core32_Ed25519::sc_reduce($hDigest) . self::substr($hDigest, 32); /** @var ParagonIE_Sodium_Core32_Curve25519_Ge_P2 $R */ $R = ParagonIE_Sodium_Core32_Ed25519::ge_double_scalarmult_vartime( $h, $A, self::substr($sig, 32) ); /** @var string $rcheck */ $rcheck = ParagonIE_Sodium_Core32_Ed25519::ge_tobytes($R); // Close the file handle fclose($fp); // Reset ParagonIE_Sodium_Compat::$fastMult to what it was before. ParagonIE_Sodium_Compat::$fastMult = $orig; return self::verify_32($rcheck, self::substr($sig, 0, 32)); } /** * Encrypt a file (32-bit) * * @param resource $ifp * @param resource $ofp * @param int $mlen * @param string $nonce * @param string $key * @return bool * @throws SodiumException * @throws TypeError */ protected static function secretbox_encrypt_core32($ifp, $ofp, $mlen, $nonce, $key) { $plaintext = fread($ifp, 32); if (!is_string($plaintext)) { throw new SodiumException('Could not read input file'); } $first32 = self::ftell($ifp); /** @var string $subkey */ $subkey = ParagonIE_Sodium_Core32_HSalsa20::hsalsa20($nonce, $key); /** @var string $realNonce */ $realNonce = ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8); /** @var string $block0 */ $block0 = str_repeat("\x00", 32); /** @var int $mlen - Length of the plaintext message */ $mlen0 = $mlen; if ($mlen0 > 64 - ParagonIE_Sodium_Crypto::secretbox_xsalsa20poly1305_ZEROBYTES) { $mlen0 = 64 - ParagonIE_Sodium_Crypto::secretbox_xsalsa20poly1305_ZEROBYTES; } $block0 .= ParagonIE_Sodium_Core32_Util::substr($plaintext, 0, $mlen0); /** @var string $block0 */ $block0 = ParagonIE_Sodium_Core32_Salsa20::salsa20_xor( $block0, $realNonce, $subkey ); $state = new ParagonIE_Sodium_Core32_Poly1305_State( ParagonIE_Sodium_Core32_Util::substr( $block0, 0, ParagonIE_Sodium_Crypto::onetimeauth_poly1305_KEYBYTES ) ); // Pre-write 16 blank bytes for the Poly1305 tag $start = self::ftell($ofp); fwrite($ofp, str_repeat("\x00", 16)); /** @var string $c */ $cBlock = ParagonIE_Sodium_Core32_Util::substr( $block0, ParagonIE_Sodium_Crypto::secretbox_xsalsa20poly1305_ZEROBYTES ); $state->update($cBlock); fwrite($ofp, $cBlock); $mlen -= 32; /** @var int $iter */ $iter = 1; /** @var int $incr */ $incr = self::BUFFER_SIZE >> 6; /* * Set the cursor to the end of the first half-block. All future bytes will * generated from salsa20_xor_ic, starting from 1 (second block). */ fseek($ifp, $first32, SEEK_SET); while ($mlen > 0) { $blockSize = $mlen > self::BUFFER_SIZE ? self::BUFFER_SIZE : $mlen; $plaintext = fread($ifp, $blockSize); if (!is_string($plaintext)) { throw new SodiumException('Could not read input file'); } $cBlock = ParagonIE_Sodium_Core32_Salsa20::salsa20_xor_ic( $plaintext, $realNonce, $iter, $subkey ); fwrite($ofp, $cBlock, $blockSize); $state->update($cBlock); $mlen -= $blockSize; $iter += $incr; } try { ParagonIE_Sodium_Compat::memzero($block0); ParagonIE_Sodium_Compat::memzero($subkey); } catch (SodiumException $ex) { $block0 = null; $subkey = null; } $end = self::ftell($ofp); /* * Write the Poly1305 authentication tag that provides integrity * over the ciphertext (encrypt-then-MAC) */ fseek($ofp, $start, SEEK_SET); fwrite($ofp, $state->finish(), ParagonIE_Sodium_Compat::CRYPTO_SECRETBOX_MACBYTES); fseek($ofp, $end, SEEK_SET); unset($state); return true; } /** * Decrypt a file (32-bit) * * @param resource $ifp * @param resource $ofp * @param int $mlen * @param string $nonce * @param string $key * @return bool * @throws SodiumException * @throws TypeError */ protected static function secretbox_decrypt_core32($ifp, $ofp, $mlen, $nonce, $key) { $tag = fread($ifp, 16); if (!is_string($tag)) { throw new SodiumException('Could not read input file'); } /** @var string $subkey */ $subkey = ParagonIE_Sodium_Core32_HSalsa20::hsalsa20($nonce, $key); /** @var string $realNonce */ $realNonce = ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8); /** @var string $block0 */ $block0 = ParagonIE_Sodium_Core32_Salsa20::salsa20( 64, ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8), $subkey ); /* Verify the Poly1305 MAC -before- attempting to decrypt! */ $state = new ParagonIE_Sodium_Core32_Poly1305_State(self::substr($block0, 0, 32)); if (!self::onetimeauth_verify_core32($state, $ifp, $tag, $mlen)) { throw new SodiumException('Invalid MAC'); } /* * Set the cursor to the end of the first half-block. All future bytes will * generated from salsa20_xor_ic, starting from 1 (second block). */ $first32 = fread($ifp, 32); if (!is_string($first32)) { throw new SodiumException('Could not read input file'); } $first32len = self::strlen($first32); fwrite( $ofp, self::xorStrings( self::substr($block0, 32, $first32len), self::substr($first32, 0, $first32len) ) ); $mlen -= 32; /** @var int $iter */ $iter = 1; /** @var int $incr */ $incr = self::BUFFER_SIZE >> 6; /* Decrypts ciphertext, writes to output file. */ while ($mlen > 0) { $blockSize = $mlen > self::BUFFER_SIZE ? self::BUFFER_SIZE : $mlen; $ciphertext = fread($ifp, $blockSize); if (!is_string($ciphertext)) { throw new SodiumException('Could not read input file'); } $pBlock = ParagonIE_Sodium_Core32_Salsa20::salsa20_xor_ic( $ciphertext, $realNonce, $iter, $subkey ); fwrite($ofp, $pBlock, $blockSize); $mlen -= $blockSize; $iter += $incr; } return true; } /** * One-time message authentication for 32-bit systems * * @param ParagonIE_Sodium_Core32_Poly1305_State $state * @param resource $ifp * @param string $tag * @param int $mlen * @return bool * @throws SodiumException * @throws TypeError */ protected static function onetimeauth_verify_core32( ParagonIE_Sodium_Core32_Poly1305_State $state, $ifp, $tag = '', $mlen = 0 ) { /** @var int $pos */ $pos = self::ftell($ifp); while ($mlen > 0) { $blockSize = $mlen > self::BUFFER_SIZE ? self::BUFFER_SIZE : $mlen; $ciphertext = fread($ifp, $blockSize); if (!is_string($ciphertext)) { throw new SodiumException('Could not read input file'); } $state->update($ciphertext); $mlen -= $blockSize; } $res = ParagonIE_Sodium_Core32_Util::verify_16($tag, $state->finish()); fseek($ifp, $pos, SEEK_SET); return $res; } /** * @param resource $resource * @return int * @throws SodiumException */ private static function ftell($resource) { $return = ftell($resource); if (!is_int($return)) { throw new SodiumException('ftell() returned false'); } return (int) $return; } }
| ver. 1.4 |
Github
|
.
| PHP 8.1.34 | Генерация страницы: 0 |
proxy
|
phpinfo
|
Настройка