]> source.dussan.org Git - nextcloud-server.git/commitdiff
Made encyrption keyfiles be deleted when their parents are
authorSam Tuke <samtuke@owncloud.com>
Tue, 29 Jan 2013 19:54:40 +0000 (19:54 +0000)
committerSam Tuke <samtuke@owncloud.com>
Tue, 29 Jan 2013 19:54:40 +0000 (19:54 +0000)
Made encryption keyfiles be renamed when their parents are
Fixed bugs with encryptAll() execution on login

apps/files_encryption/appinfo/spec.txt
apps/files_encryption/hooks/hooks.php
apps/files_encryption/lib/keymanager.php
apps/files_encryption/lib/proxy.php
apps/files_encryption/lib/util.php

index ab248be64d5cad828ade4fb288e3a55e0ec3ddfc..2d22dffe08da9d3e1a331aff5166aa9dfd05e16c 100644 (file)
@@ -1,3 +1,15 @@
+Encrypted files
+---------------
+
+- Each encrypted file has at least two components: the encrypted data file
+  ('catfile'), and it's corresponding key file ('keyfile'). Shared files have an
+  additional key file ('share key'). The catfile contains the encrypted data
+  concatenated with delimiter text, followed by the initialisation vector ('IV'),
+  and padding. e.g.:
+
+  [encrypted data string][delimiter][IV][padding]
+  [anhAAjAmcGXqj1X9g==][00iv00][MSHU5N5gECP7aAg7][xx] (square braces added)
+
 Notes
 -----
 
index 73d7957541a801ca8d3d5729851f6bd5b9115e71..dafa14fc0002d15444df77418b9a10532d44e9ae 100644 (file)
@@ -37,8 +37,6 @@ class Hooks {
         * @note This method should never be called for users using client side encryption\r
         */\r
        public static function login( $params ) {\r
-                       \r
-                       // TODO: use lots of dependency injection here\r
                \r
                        $view = new \OC_FilesystemView( '/' );\r
 \r
@@ -83,8 +81,17 @@ class Hooks {
                        \r
                        // Encrypt existing user files:\r
                        // This serves to upgrade old versions of the encryption\r
-                       // app (see appinfo/spec.txt\r
-                       $this->encryptAll( $publicKey, $this->userFilesDir, $session->getLegacyKey(), $params['password'] );\r
+                       // app (see appinfo/spec.txt)\r
+                       if ( \r
+                               $util->encryptAll( $publicKey,  '/' . $params['uid'] . '/' . 'files', $session->getLegacyKey(), $params['password'] )\r
+                       ) {\r
+                               \r
+                               \OC_Log::write( \r
+                                       'Encryption library', 'Encryption of file belonging to "' . $params['uid'] . '" was started at login'\r
+                                       , \OC_Log::INFO \r
+                               );\r
+                       \r
+                       }\r
 \r
                return true;\r
 \r
index 301e5b33fd86fc14b5ef078df4c63566665b1c71..8656bb96758d1d960e165c850cb9c28d573f0ba7 100755 (executable)
@@ -234,33 +234,33 @@ class Keymanager {
        }\r
        \r
        /**\r
-        * @brief retrieve file encryption key\r
+        * @brief Delete a keyfile\r
         *\r
-        * @param string file name\r
-        * @return string file key or false\r
+        * @param OC_FilesystemView $view\r
+        * @param string $userId username\r
+        * @param string $path path of the file the key belongs to\r
+        * @return bool Outcome of unlink operation\r
+        * @note $path must be relative to data/user/files. e.g. mydoc.txt NOT\r
+        *       /data/admin/files/mydoc.txt\r
         */\r
-       public static function deleteFileKey( $path, $staticUserClass = 'OCP\User' ) {\r
+       public static function deleteFileKey( \OC_FilesystemView $view, $userId, $path ) {\r
                \r
-               $keypath = ltrim( $path, '/' );\r
-               $user = $staticUserClass::getUser();\r
-\r
-               // update $keypath and $user if path point to a file shared by someone else\r
-//             $query = \OC_DB::prepare( "SELECT uid_owner, source, target FROM `*PREFIX*sharing` WHERE target = ? AND uid_shared_with = ?" );\r
-//             \r
-//             $result = $query->execute( array ('/'.$user.'/files/'.$keypath, $user));\r
-//             \r
-//             if ($row = $result->fetchRow()) {\r
-//             \r
-//                     $keypath = $row['source'];\r
-//                     $keypath_parts = explode( '/', $keypath );\r
-//                     $user = $keypath_parts[1];\r
-//                     $keypath = str_replace( '/' . $user . '/files/', '', $keypath );\r
-//                     \r
-//             }\r
+               $trimmed = ltrim( $path, '/' );\r
+               $keyPath =  '/' . $userId . '/files_encryption/keyfiles/' . $trimmed . '.key';\r
                \r
-               $view = new \OC_FilesystemView( '/' . $user. '/files_encryption/keyfiles/' );\r
+               // Unlink doesn't tell us if file was deleted (not found returns\r
+               // true), so we perform our own test\r
+               if ( $view->file_exists( $keyPath ) ) {\r
                \r
-               return $view->unlink( $keypath . '.key' );\r
+                       return $view->unlink( $keyPath );\r
+                       \r
+               } else {\r
+                       \r
+                       \OC_Log::write( 'Encryption library', 'Could not delete keyfile; does not exist: "' . $keyPath, \OC_Log::ERROR );\r
+                       \r
+                       return false;\r
+                       \r
+               }\r
                \r
        }\r
        \r
index 025af3c7f14f9be367e58d6e145b02439355a20f..6d2a574abd2c0c71ed268ba502078f4971c7b36d 100644 (file)
@@ -192,6 +192,73 @@ class Proxy extends \OC_FileProxy {
                
        }
        
+       /**
+        * @brief When a file is deleted, remove its keyfile also
+        */
+       public function postUnlink( $path ) {
+       
+               // Disable encryption proxy to prevent recursive calls
+               \OC_FileProxy::$enabled = false;
+               
+               $view = new \OC_FilesystemView( '/' );
+               
+               $userId = \OCP\USER::getUser();
+       
+               // Format path to be relative to user files dir
+               $trimmed = ltrim( $path, '/' );
+               $split = explode( '/', $trimmed );
+               $sliced = array_slice( $split, 2 );
+               $relPath = implode( '/', $sliced );
+       
+               // Delete keyfile so it isn't orphaned
+               $result = Keymanager::deleteFileKey( $view, $userId, $relPath );
+       
+               \OC_FileProxy::$enabled = true;
+               
+               return $result;
+       
+       }
+
+       /**
+        * @brief When a file is renamed, rename its keyfile also
+        * @return bool Result of rename()
+        * @note This is pre rather than post because using post didn't work
+        */
+       public function preRename( $oldPath, $newPath ) {
+       
+//             trigger_error( "PATHS = ".var_export($oldPath, 1).'  '.var_export($newPath, 1));
+               
+               // Disable encryption proxy to prevent recursive calls
+               \OC_FileProxy::$enabled = false;
+               
+               $view = new \OC_FilesystemView( '/' );
+               
+               $userId = \OCP\USER::getUser();
+       
+               // Format paths to be relative to user files dir
+               $oldTrimmed = ltrim( $oldPath, '/' );
+               $oldSplit = explode( '/', $oldTrimmed );
+               $oldSliced = array_slice( $oldSplit, 2 );
+               $oldRelPath = implode( '/', $oldSliced );
+               $oldKeyfilePath = $userId . '/' . 'files_encryption' . '/' . 'keyfiles' . '/' . $oldRelPath . '.key';
+               
+               $newTrimmed = ltrim( $newPath, '/' );
+               $newSplit = explode( '/', $newTrimmed );
+               $newSliced = array_slice( $newSplit, 2 );
+               $newRelPath = implode( '/', $newSliced );
+               $newKeyfilePath = $userId . '/' . 'files_encryption' . '/' . 'keyfiles' . '/' . $newRelPath . '.key';
+               
+//             trigger_error("RENAMING = ".var_export($oldKeyfilePath, 1).' -> '.var_export($newKeyfilePath, 1));
+               
+               // Rename keyfile so it isn't orphaned
+               $result = $view->rename( $oldKeyfilePath, $newKeyfilePath );
+               
+               \OC_FileProxy::$enabled = true;
+               
+               return $result;
+       
+       }
+       
        public function postFopen( $path, &$result ){
        
                if ( !$result ) {
index fd4d7a9fcc60256c3e3d744ae9b1bb8daa7c12b0..2a69bba43c964be6545b0e8ce48ce7c1a3a3fa91 100644 (file)
@@ -225,6 +225,9 @@ class Util {
         * @brief Find all files and their encryption status within a directory
         * @param string $directory The path of the parent directory to search
         * @return mixed false if 0 found, array on success. Keys: name, path
+        
+        * @note $directory needs to be a path relative to OC data dir. e.g.
+        *       /admin/files NOT /backup OR /home/www/oc/data/admin/files
         */
        public function findFiles( $directory ) {
                
@@ -293,7 +296,7 @@ class Util {
                                return false;
                        
                        } else {
-                       
+                               
                                return $found;
                        
                        }
@@ -334,20 +337,29 @@ class Util {
        
                if ( $found = $this->findFiles( $dirPath ) ) {
                
+                       // Disable proxy to prevent file being encrypted twice
+                       \OC_FileProxy::$enabled = false;
+               
                        // Encrypt unencrypted files
-                       foreach ( $found['plain'] as $plainFilePath ) {
-                       
+                       foreach ( $found['plain'] as $plainFile ) {
+                               
                                // Fetch data from file
-                               $plainData = $this->view->file_get_contents( $plainFilePath );
+                               $plainData = $this->view->file_get_contents( $plainFile['path'] );
                                
                                // Encrypt data, generate catfile
                                $encrypted = Crypt::keyEncryptKeyfile( $plainData, $publicKey );
                                
+                               // Format path to be relative to user files dir
+                               $trimmed = ltrim( $plainFile['path'], '/' );
+                               $split = explode( '/', $trimmed );
+                               $sliced = array_slice( $split, 2 );
+                               $relPath = implode( '/', $sliced );
+                               
                                // Save catfile
-                               Keymanager::setFileKey( $this->view, $plainFilePath, $this->userId, $encrypted['key'] );
+                               Keymanager::setFileKey( $this->view, $relPath, $this->userId, $encrypted['key'] );
                                
                                // Overwrite the existing file with the encrypted one
-                               $this->view->file_put_contents( $plainFilePath, $encrypted['data'] );
+                               $this->view->file_put_contents( $plainFile['path'], $encrypted['data'] );
                        
                        }
                        
@@ -367,15 +379,25 @@ class Util {
                                        $recrypted = Crypt::legacyKeyRecryptKeyfile( $legacyData, $legacyPassphrase, $publicKey, $newPassphrase );
                                        
                                        // Save catfile
-                                       Keymanager::setFileKey( $this->view, $plainFilePath, $this->userId, $recrypted['key'] );
+                                       Keymanager::setFileKey( $this->view, $plainFile['path'], $this->userId, $recrypted['key'] );
                                        
                                        // Overwrite the existing file with the encrypted one
-                                       $this->view->file_put_contents( $plainFilePath, $recrypted['data'] );
+                                       $this->view->file_put_contents( $plainFile['path'], $recrypted['data'] );
                                
                                }
                                
                        }
+                       
+                       \OC_FileProxy::$enabled = true;
+                       
+                       // If files were found, return true
+                       return true;
                
+               } else {
+               
+                       // If no files were found, return false
+                       return false;
+                       
                }
                
        }