From 9f51841c57ca96eb7ce518dde9c6d35c905110c6 Mon Sep 17 00:00:00 2001 From: Sam Tuke Date: Wed, 25 Jul 2012 18:28:56 +0100 Subject: [PATCH] Mainly work on implementing new encryption system (+ keyfile handling) into proxy classs --- apps/files_encryption/appinfo/app.php | 16 ++++-- apps/files_encryption/hooks/hooks.php | 1 - apps/files_encryption/lib/keymanager.php | 24 +++++---- apps/files_encryption/lib/proxy.php | 65 +++++++++++++++--------- apps/files_encryption/lib/util.php | 9 ++-- 5 files changed, 73 insertions(+), 42 deletions(-) diff --git a/apps/files_encryption/appinfo/app.php b/apps/files_encryption/appinfo/app.php index 969c824cfd..1a4021e939 100644 --- a/apps/files_encryption/appinfo/app.php +++ b/apps/files_encryption/appinfo/app.php @@ -5,18 +5,26 @@ OC::$CLASSPATH['OCA_Encryption\Hooks'] = 'apps/files_encryption/hooks/hooks.php' OC::$CLASSPATH['OCA_Encryption\Util'] = 'apps/files_encryption/lib/util.php'; OC::$CLASSPATH['OCA_Encryption\Keymanager'] = 'apps/files_encryption/lib/keymanager.php'; OC::$CLASSPATH['OC_CryptStream'] = 'apps/files_encryption/lib/cryptstream.php'; -OC::$CLASSPATH['OC_FileProxy_Encryption'] = 'apps/files_encryption/lib/proxy.php'; +OC::$CLASSPATH['OCA_Encryption\Proxy'] = 'apps/files_encryption/lib/proxy.php'; -//OC_FileProxy::register(new OC_FileProxy_Encryption()); +OC_FileProxy::register(new OCA_Encryption\Proxy()); OCP\Util::connectHook('OC_User','post_login','OCA_Encryption\Hooks','login'); stream_wrapper_register('crypt','OC_CryptStream'); -if( !isset($_SESSION['enckey']) and OCP\User::isLoggedIn() ){//force the user to re-loggin if the encryption key isn't unlocked (happens when a user is logged in before the encryption app is enabled) +if( +!isset( $_SESSION['enckey'] ) +and OCP\User::isLoggedIn() +) { + + // Force the user to re-log in if the encryption key isn't unlocked (happens when a user is logged in before the encryption app is enabled) OCP\User::logout(); + header("Location: ".OC::$WEBROOT.'/'); + exit(); + } -OCP\App::registerAdmin('files_encryption', 'settings'); +OCP\App::registerAdmin('files_encryption', 'settings'); \ No newline at end of file diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php index 70bbbcf478..654686208f 100644 --- a/apps/files_encryption/hooks/hooks.php +++ b/apps/files_encryption/hooks/hooks.php @@ -52,7 +52,6 @@ class Hooks { return true; - } } diff --git a/apps/files_encryption/lib/keymanager.php b/apps/files_encryption/lib/keymanager.php index d78db132b1..e4462796f0 100644 --- a/apps/files_encryption/lib/keymanager.php +++ b/apps/files_encryption/lib/keymanager.php @@ -27,6 +27,7 @@ namespace OCA_Encryption; */ class Keymanager { + # TODO: Try and get rid of username dependencies as these methods need to be used in a proxy class that doesn't have username access /** * @brief retrieve private key from a user @@ -36,9 +37,9 @@ class Keymanager { */ public static function getPrivateKey( $user ) { - $view = new \OC_FilesystemView( '/' . $user . '/' . 'files_encryption' . '/' ); + $view = new \OC_FilesystemView( '/' . $user . '/' . 'files_encryption' ); - return $view->file_get_contents( $user.'.private.key' ); + return $view->file_get_contents( '/' . $user.'.private.key' ); } /** @@ -96,15 +97,20 @@ class Keymanager { /** * @brief store file encryption key * - * @param string user name of the file owner - * @param string file name - * @param string key + * @param string $userId name of the file owner + * @param string $path relative path of the file, including filename + * @param string $key * @return bool true/false */ - public static function setFileKey($user, $file, $key) { - $fileKeyStorage = \OCP\Config::getSystemValue('datadirectory').'/'.$user.'/files_encryption/keyfiles/'; - $view = new \OC_FilesystemView($fileKeyStorage); - return $view->file_put_contents($file.'.key', $key); + public static function setFileKey( $userId, $path, $key ) { + + \OC_FileProxy::$enabled = false; + + $view = new \OC_FilesystemView( '/' . $userId . '/' . 'files_encryption' ); + + return $view->file_put_contents( '/' . $path . '.key', $key ); + + \OC_FileProxy::$enabled = true; } diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index 080fd04cd7..53ed05d2c3 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -3,8 +3,9 @@ /** * ownCloud * -* @author Robin Appelman -* @copyright 2011 Robin Appelman icewind1991@gmail.com +* @author Sam Tuke, Robin Appelman +* @copyright 2012 Sam Tuke samtuke@owncloud.com, Robin Appelman +* icewind1991@gmail.com * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE @@ -26,7 +27,9 @@ * transparent encryption */ -class OC_FileProxy_Encryption extends OC_FileProxy { +namespace OCA_Encryption; + +class Proxy extends \OC_FileProxy { private static $blackList = null; //mimetypes blacklisted from encryption @@ -43,7 +46,7 @@ class OC_FileProxy_Encryption extends OC_FileProxy { if ( is_null( self::$enableEncryption ) ) { - self::$enableEncryption = ( OCP\Config::getAppValue( 'files_encryption', 'enable_encryption', 'true' ) == 'true' ); + self::$enableEncryption = ( \OCP\Config::getAppValue( 'files_encryption', 'enable_encryption', 'true' ) == 'true' ); } @@ -55,11 +58,11 @@ class OC_FileProxy_Encryption extends OC_FileProxy { if( is_null(self::$blackList ) ) { - self::$blackList = explode(',',OCP\Config::getAppValue( 'files_encryption','type_blacklist','jpg,png,jpeg,avi,mpg,mpeg,mkv,mp3,oga,ogv,ogg' ) ); + self::$blackList = explode(',', \OCP\Config::getAppValue( 'files_encryption','type_blacklist','jpg,png,jpeg,avi,mpg,mpeg,mkv,mp3,oga,ogv,ogg' ) ); } - if( self::isEncrypted( $path ) ) { + if( Crypt::isEncryptedContent( $path ) ) { return true; @@ -84,7 +87,7 @@ class OC_FileProxy_Encryption extends OC_FileProxy { private static function isEncrypted( $path ){ // Fetch all file metadata from DB - $metadata = OC_FileCache_Cached::get( $path, '' ); + $metadata = \OC_FileCache_Cached::get( $path, '' ); // Return encryption status return isset( $metadata['encrypted'] ) and ( bool )$metadata['encrypted']; @@ -95,13 +98,24 @@ class OC_FileProxy_Encryption extends OC_FileProxy { if ( self::shouldEncrypt( $path ) ) { - if ( !is_resource( $data ) ) {//stream put contents should have been converter to fopen + if ( !is_resource( $data ) ) { //stream put contents should have been converter to fopen + // Set the filesize for userland, before encrypting $size = strlen( $data ); - $data = OCA_Encryption\Crypt::symmetricEncryptFileContent( $data, '', $cached['size'] ); + // Encrypt plain data and fetch key + $encrypted = Crypt::symmetricEncryptFileContentKeyfile( $data, $_SESSION['enckey'] ); - OC_FileCache::put( $path, array( 'encrypted'=>true, 'size' => $size ), '' ); + // Replace plain content with encrypted content by reference + $data = $encrypted['encrypted']; + + # TODO: check if file is in subdirectories, and if so, create those parent directories. Or else monitor creation of directories using hooks to ensure path will always exist (what about existing directories when encryption is enabled?) + + // Save keyfile for newly encrypted file in parallel directory + Keymanager::setFileKey( \OCP\USER::getUser(), $path, $encrypted['key'] ); + + // Update the file cache with file info + \OC_FileCache::put( $path, array( 'encrypted'=>true, 'size' => $size ), '' ); } } @@ -109,11 +123,11 @@ class OC_FileProxy_Encryption extends OC_FileProxy { public function postFile_get_contents( $path, $data ) { - if ( self::isEncrypted( $path ) ) { - - $cached = OC_FileCache_Cached::get( $path, '' ); + if ( Crypt::isEncryptedContent( $data ) ) { + trigger_error('best'); + $cached = \OC_FileCache_Cached::get( $path, '' ); - $data = OCA_Encryption\Crypt::symmetricDecryptFileContent( $data, '' ); + $data = Crypt::symmetricDecryptFileContent( $data, $_SESSION['enckey'] ); } @@ -121,21 +135,22 @@ class OC_FileProxy_Encryption extends OC_FileProxy { } public function postFopen($path,&$result){ + if(!$result){ return $result; } $meta=stream_get_meta_data($result); - if(self::isEncrypted($path)){ + if(Crypt::isEncryptedContent($path)){ fclose($result); $result=fopen('crypt://'.$path,$meta['mode']); }elseif(self::shouldEncrypt($path) and $meta['mode']!='r' and $meta['mode']!='rb'){ - if(OC_Filesystem::file_exists($path) and OC_Filesystem::filesize($path)>0){ + if( \OC_Filesystem::file_exists( $path ) and \OC_Filesystem::filesize($path)>0){ //first encrypt the target file so we don't end up with a half encrypted file - OCP\Util::writeLog('files_encryption','Decrypting '.$path.' before writing',OCP\Util::DEBUG); + \OCP\Util::writeLog('files_encryption','Decrypting '.$path.' before writing', \OCP\Util::DEBUG); $tmp=fopen('php://temp'); - OCP\Files::streamCopy($result,$tmp); + \OCP\Files::streamCopy($result,$tmp); fclose($result); - OC_Filesystem::file_put_contents($path,$tmp); + \OC_Filesystem::file_put_contents($path,$tmp); fclose($tmp); } $result=fopen('crypt://'.$path,$meta['mode']); @@ -144,23 +159,23 @@ class OC_FileProxy_Encryption extends OC_FileProxy { } public function postGetMimeType($path,$mime){ - if(self::isEncrypted($path)){ - $mime=OCP\Files::getMimeType('crypt://'.$path,'w'); + if(Crypt::isEncryptedContent($path)){ + $mime = \OCP\Files::getMimeType('crypt://'.$path,'w'); } return $mime; } public function postStat($path,$data){ - if(self::isEncrypted($path)){ - $cached=OC_FileCache_Cached::get($path,''); + if(Crypt::isEncryptedContent($path)){ + $cached= \OC_FileCache_Cached::get($path,''); $data['size']=$cached['size']; } return $data; } public function postFileSize($path,$size){ - if(self::isEncrypted($path)){ - $cached=OC_FileCache_Cached::get($path,''); + if(Crypt::isEncryptedContent($path)){ + $cached = \OC_FileCache_Cached::get($path,''); return $cached['size']; }else{ return $size; diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index e876e886c4..ab58b4aa72 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -184,15 +184,16 @@ class Util { * if the key is left out, the default handeler will be used */ public function getLegacyKey( $passphrase ) { - - //OC_FileProxy::$enabled = false; + + // Disable proxies to prevent attempt to automatically decrypt key + OC_FileProxy::$enabled = false; if ( $passphrase and $key = $this->view->file_get_contents( '/encryption.key' ) ) { - //OC_FileProxy::$enabled = true; + OC_FileProxy::$enabled = true; if ( $this->legacyKey = $this->legacyDecrypt( $key, $passphrase ) ) { @@ -206,6 +207,8 @@ class Util { } else { + OC_FileProxy::$enabled = true; + return false; }