From 3b850a2524471030da27227cba18b31ffc998aa4 Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Mon, 20 May 2013 01:24:36 +0200 Subject: [PATCH] reformat code added and changed phpdoc --- apps/files_encryption/lib/crypt.php | 863 +++++++------ apps/files_encryption/lib/helper.php | 114 +- apps/files_encryption/lib/keymanager.php | 517 ++++---- apps/files_encryption/lib/proxy.php | 669 +++++----- apps/files_encryption/lib/session.php | 163 +-- apps/files_encryption/lib/stream.php | 578 ++++----- apps/files_encryption/lib/util.php | 1322 +++++++++++--------- apps/files_encryption/tests/crypt.php | 903 ++++++------- apps/files_encryption/tests/keymanager.php | 149 +-- apps/files_encryption/tests/share.php | 640 +++++----- apps/files_encryption/tests/util.php | 192 +-- 11 files changed, 3175 insertions(+), 2935 deletions(-) diff --git a/apps/files_encryption/lib/crypt.php b/apps/files_encryption/lib/crypt.php index ba588819d0..783c19d254 100755 --- a/apps/files_encryption/lib/crypt.php +++ b/apps/files_encryption/lib/crypt.php @@ -4,8 +4,8 @@ * ownCloud * * @author Sam Tuke, Frank Karlitschek, Robin Appelman - * @copyright 2012 Sam Tuke samtuke@owncloud.com, - * Robin Appelman icewind@owncloud.com, Frank Karlitschek + * @copyright 2012 Sam Tuke samtuke@owncloud.com, + * Robin Appelman icewind@owncloud.com, Frank Karlitschek * frank@owncloud.org * * This library is free software; you can redistribute it and/or @@ -27,505 +27,532 @@ namespace OCA\Encryption; require_once 'Crypt_Blowfish/Blowfish.php'; -// Todo: -// - Add a setting "DonĀ“t encrypt files larger than xx because of performance" -// - Don't use a password directly as encryption key. but a key which is -// stored on the server and encrypted with the user password. -> change pass -// faster - /** * Class for common cryptography functionality */ -class Crypt { +class Crypt +{ /** * @brief return encryption mode client or server side encryption - * @param string user name (use system wide setting if name=null) + * @param string $user name (use system wide setting if name=null) * @return string 'client' or 'server' */ - public static function mode( $user = null ) { + public static function mode($user = null) + { return 'server'; - + } - - /** - * @brief Create a new encryption keypair - * @return array publicKey, privatekey - */ - public static function createKeypair() { - + + /** + * @brief Create a new encryption keypair + * @return array publicKey, privatekey + */ + public static function createKeypair() + { + $res = openssl_pkey_new(array('private_key_bits' => 4096)); // Get private key - openssl_pkey_export( $res, $privateKey ); + openssl_pkey_export($res, $privateKey); // Get public key - $publicKey = openssl_pkey_get_details( $res ); - + $publicKey = openssl_pkey_get_details($res); + $publicKey = $publicKey['key']; - - return( array( 'publicKey' => $publicKey, 'privateKey' => $privateKey ) ); - + + return (array('publicKey' => $publicKey, 'privateKey' => $privateKey)); + } - - /** - * @brief Add arbitrary padding to encrypted data - * @param string $data data to be padded - * @return padded data - * @note In order to end up with data exactly 8192 bytes long we must - * add two letters. It is impossible to achieve exactly 8192 length - * blocks with encryption alone, hence padding is added to achieve the - * required length. - */ - public static function addPadding( $data ) { - + + /** + * @brief Add arbitrary padding to encrypted data + * @param string $data data to be padded + * @return string padded data + * @note In order to end up with data exactly 8192 bytes long we must + * add two letters. It is impossible to achieve exactly 8192 length + * blocks with encryption alone, hence padding is added to achieve the + * required length. + */ + public static function addPadding($data) + { + $padded = $data . 'xx'; - + return $padded; - + } - - /** - * @brief Remove arbitrary padding to encrypted data - * @param string $padded padded data to remove padding from - * @return unpadded data on success, false on error - */ - public static function removePadding( $padded ) { - - if ( substr( $padded, -2 ) == 'xx' ) { - - $data = substr( $padded, 0, -2 ); - + + /** + * @brief Remove arbitrary padding to encrypted data + * @param string $padded padded data to remove padding from + * @return string unpadded data on success, false on error + */ + public static function removePadding($padded) + { + + if (substr($padded, -2) == 'xx') { + + $data = substr($padded, 0, -2); + return $data; - + } else { - + // TODO: log the fact that unpadded data was submitted for removal of padding return false; - + } - + } - - /** - * @brief Check if a file's contents contains an IV and is symmetrically encrypted - * @return true / false - * @note see also OCA\Encryption\Util->isEncryptedPath() - */ - public static function isCatfileContent( $content ) { - - if ( !$content ) { - + + /** + * @brief Check if a file's contents contains an IV and is symmetrically encrypted + * @param $content + * @return boolean + * @note see also OCA\Encryption\Util->isEncryptedPath() + */ + public static function isCatfileContent($content) + { + + if (!$content) { + return false; - + } - - $noPadding = self::removePadding( $content ); - + + $noPadding = self::removePadding($content); + // Fetch encryption metadata from end of file - $meta = substr( $noPadding, -22 ); - + $meta = substr($noPadding, -22); + // Fetch IV from end of file - $iv = substr( $meta, -16 ); - + $iv = substr($meta, -16); + // Fetch identifier from start of metadata - $identifier = substr( $meta, 0, 6 ); - - if ( $identifier == '00iv00') { - + $identifier = substr($meta, 0, 6); + + if ($identifier == '00iv00') { + return true; - + } else { - + return false; - + } - + } - + /** * Check if a file is encrypted according to database file cache * @param string $path * @return bool */ - public static function isEncryptedMeta( $path ) { - + public static function isEncryptedMeta($path) + { + // TODO: Use DI to get \OC\Files\Filesystem out of here - - // Fetch all file metadata from DB - $metadata = \OC\Files\Filesystem::getFileInfo( $path); - - // Return encryption status - return isset( $metadata['encrypted'] ) and ( bool )$metadata['encrypted']; - - } - - /** - * @brief Check if a file is encrypted via legacy system - * @param string $relPath The path of the file, relative to user/data; - * e.g. filename or /Docs/filename, NOT admin/files/filename - * @return true / false - */ - public static function isLegacyEncryptedContent( $data, $relPath ) { // Fetch all file metadata from DB - $metadata = \OC\Files\Filesystem::getFileInfo( $relPath, '' ); - + $metadata = \OC\Files\Filesystem::getFileInfo($path); + + // Return encryption status + return isset($metadata['encrypted']) and ( bool )$metadata['encrypted']; + + } + + /** + * @brief Check if a file is encrypted via legacy system + * @param $data + * @param string $relPath The path of the file, relative to user/data; + * e.g. filename or /Docs/filename, NOT admin/files/filename + * @return boolean + */ + public static function isLegacyEncryptedContent($data, $relPath) + { + + // Fetch all file metadata from DB + $metadata = \OC\Files\Filesystem::getFileInfo($relPath, ''); + // If a file is flagged with encryption in DB, but isn't a // valid content + IV combination, it's probably using the // legacy encryption system - if ( - isset( $metadata['encrypted'] ) - and $metadata['encrypted'] === true - and ! self::isCatfileContent( $data ) + if ( + isset($metadata['encrypted']) + and $metadata['encrypted'] === true + and !self::isCatfileContent($data) ) { - + return true; - + } else { - + return false; - + } - + } - - /** - * @brief Symmetrically encrypt a string - * @returns encrypted file - */ - public static function encrypt( $plainContent, $iv, $passphrase = '' ) { - - if ( $encryptedContent = openssl_encrypt( $plainContent, 'AES-128-CFB', $passphrase, false, $iv ) ) { + + /** + * @brief Symmetrically encrypt a string + * @return string encrypted file content + */ + public static function encrypt($plainContent, $iv, $passphrase = '') + { + + if ($encryptedContent = openssl_encrypt($plainContent, 'AES-128-CFB', $passphrase, false, $iv)) { return $encryptedContent; - + } else { - - \OC_Log::write( 'Encryption library', 'Encryption (symmetric) of content failed', \OC_Log::ERROR ); - + + \OC_Log::write('Encryption library', 'Encryption (symmetric) of content failed', \OC_Log::ERROR); + return false; - + } - + } - - /** - * @brief Symmetrically decrypt a string - * @returns decrypted file - */ - public static function decrypt( $encryptedContent, $iv, $passphrase ) { - - if ( $plainContent = openssl_decrypt( $encryptedContent, 'AES-128-CFB', $passphrase, false, $iv ) ) { + + /** + * @brief Symmetrically decrypt a string + * @return string decrypted file content + */ + public static function decrypt($encryptedContent, $iv, $passphrase) + { + + if ($plainContent = openssl_decrypt($encryptedContent, 'AES-128-CFB', $passphrase, false, $iv)) { return $plainContent; - - + + } else { - - throw new \Exception( 'Encryption library: Decryption (symmetric) of content failed' ); - + + throw new \Exception('Encryption library: Decryption (symmetric) of content failed'); + return false; - + } - + } - - /** - * @brief Concatenate encrypted data with its IV and padding - * @param string $content content to be concatenated - * @param string $iv IV to be concatenated - * @returns string concatenated content - */ - public static function concatIv ( $content, $iv ) { - + + /** + * @brief Concatenate encrypted data with its IV and padding + * @param string $content content to be concatenated + * @param string $iv IV to be concatenated + * @returns string concatenated content + */ + public static function concatIv($content, $iv) + { + $combined = $content . '00iv00' . $iv; - + return $combined; - + } - - /** - * @brief Split concatenated data and IV into respective parts - * @param string $catFile concatenated data to be split - * @returns array keys: encrypted, iv - */ - public static function splitIv ( $catFile ) { - + + /** + * @brief Split concatenated data and IV into respective parts + * @param string $catFile concatenated data to be split + * @returns array keys: encrypted, iv + */ + public static function splitIv($catFile) + { + // Fetch encryption metadata from end of file - $meta = substr( $catFile, -22 ); - + $meta = substr($catFile, -22); + // Fetch IV from end of file - $iv = substr( $meta, -16 ); - + $iv = substr($meta, -16); + // Remove IV and IV identifier text to expose encrypted content - $encrypted = substr( $catFile, 0, -22 ); - + $encrypted = substr($catFile, 0, -22); + $split = array( 'encrypted' => $encrypted - , 'iv' => $iv + , 'iv' => $iv ); - + return $split; - + } - - /** - * @brief Symmetrically encrypts a string and returns keyfile content - * @param $plainContent content to be encrypted in keyfile - * @returns encrypted content combined with IV - * @note IV need not be specified, as it will be stored in the returned keyfile - * and remain accessible therein. - */ - public static function symmetricEncryptFileContent( $plainContent, $passphrase = '' ) { - - if ( !$plainContent ) { - + + /** + * @brief Symmetrically encrypts a string and returns keyfile content + * @param string $plainContent content to be encrypted in keyfile + * @param string $passphrase + * @return bool|string + * @return string encrypted content combined with IV + * @note IV need not be specified, as it will be stored in the returned keyfile + * and remain accessible therein. + */ + public static function symmetricEncryptFileContent($plainContent, $passphrase = '') + { + + if (!$plainContent) { + return false; - + } - + $iv = self::generateIv(); - - if ( $encryptedContent = self::encrypt( $plainContent, $iv, $passphrase ) ) { - - // Combine content to encrypt with IV identifier and actual IV - $catfile = self::concatIv( $encryptedContent, $iv ); - - $padded = self::addPadding( $catfile ); - - return $padded; - + + if ($encryptedContent = self::encrypt($plainContent, $iv, $passphrase)) { + + // Combine content to encrypt with IV identifier and actual IV + $catfile = self::concatIv($encryptedContent, $iv); + + $padded = self::addPadding($catfile); + + return $padded; + } else { - - \OC_Log::write( 'Encryption library', 'Encryption (symmetric) of keyfile content failed', \OC_Log::ERROR ); - + + \OC_Log::write('Encryption library', 'Encryption (symmetric) of keyfile content failed', \OC_Log::ERROR); + return false; - + } - + } /** - * @brief Symmetrically decrypts keyfile content - * @param string $source - * @param string $target - * @param string $key the decryption key - * @returns decrypted content - * - * This function decrypts a file - */ - public static function symmetricDecryptFileContent( $keyfileContent, $passphrase = '' ) { - - if ( !$keyfileContent ) { - - throw new \Exception( 'Encryption library: no data provided for decryption' ); - + * @brief Symmetrically decrypts keyfile content + * @param $keyfileContent + * @param string $passphrase + * @throws \Exception + * @return bool|string + * @internal param string $source + * @internal param string $target + * @internal param string $key the decryption key + * @returns string decrypted content + * + * This function decrypts a file + */ + public static function symmetricDecryptFileContent($keyfileContent, $passphrase = '') + { + + if (!$keyfileContent) { + + throw new \Exception('Encryption library: no data provided for decryption'); + } - + // Remove padding - $noPadding = self::removePadding( $keyfileContent ); - + $noPadding = self::removePadding($keyfileContent); + // Split into enc data and catfile - $catfile = self::splitIv( $noPadding ); - - if ( $plainContent = self::decrypt( $catfile['encrypted'], $catfile['iv'], $passphrase ) ) { - + $catfile = self::splitIv($noPadding); + + if ($plainContent = self::decrypt($catfile['encrypted'], $catfile['iv'], $passphrase)) { + return $plainContent; - + } - + } - + /** - * @brief Creates symmetric keyfile content using a generated key - * @param string $plainContent content to be encrypted - * @returns array keys: key, encrypted - * @note symmetricDecryptFileContent() can be used to decrypt files created using this method - * - * This function decrypts a file - */ - public static function symmetricEncryptFileContentKeyfile( $plainContent ) { - + * @brief Creates symmetric keyfile content using a generated key + * @param string $plainContent content to be encrypted + * @returns array keys: key, encrypted + * @note symmetricDecryptFileContent() can be used to decrypt files created using this method + * + * This function decrypts a file + */ + public static function symmetricEncryptFileContentKeyfile($plainContent) + { + $key = self::generateKey(); - - if( $encryptedContent = self::symmetricEncryptFileContent( $plainContent, $key ) ) { - + + if ($encryptedContent = self::symmetricEncryptFileContent($plainContent, $key)) { + return array( 'key' => $key - , 'encrypted' => $encryptedContent + , 'encrypted' => $encryptedContent ); - + } else { - + return false; - + } - + } - + /** - * @brief Create asymmetrically encrypted keyfile content using a generated key - * @param string $plainContent content to be encrypted - * @param array $publicKeys array keys must be the userId of corresponding user - * @returns array keys: keys (array, key = userId), data - * @note symmetricDecryptFileContent() can decrypt files created using this method - */ - public static function multiKeyEncrypt( $plainContent, array $publicKeys ) { - + * @brief Create asymmetrically encrypted keyfile content using a generated key + * @param string $plainContent content to be encrypted + * @param array $publicKeys array keys must be the userId of corresponding user + * @returns array keys: keys (array, key = userId), data + * @note symmetricDecryptFileContent() can decrypt files created using this method + */ + public static function multiKeyEncrypt($plainContent, array $publicKeys) + { + // openssl_seal returns false without errors if $plainContent // is empty, so trigger our own error - if ( empty( $plainContent ) ) { - - trigger_error( "Cannot mutliKeyEncrypt empty plain content" ); - throw new \Exception( 'Cannot mutliKeyEncrypt empty plain content' ); - + if (empty($plainContent)) { + + trigger_error("Cannot mutliKeyEncrypt empty plain content"); + throw new \Exception('Cannot mutliKeyEncrypt empty plain content'); + } - + // Set empty vars to be set by openssl by reference $sealed = ''; $shareKeys = array(); - - if( openssl_seal( $plainContent, $sealed, $shareKeys, $publicKeys ) ) { - + + if (openssl_seal($plainContent, $sealed, $shareKeys, $publicKeys)) { + $i = 0; - + // Ensure each shareKey is labelled with its // corresponding userId - foreach ( $publicKeys as $userId => $publicKey ) { - + foreach ($publicKeys as $userId => $publicKey) { + $mappedShareKeys[$userId] = $shareKeys[$i]; $i++; - + } - + return array( 'keys' => $mappedShareKeys - , 'data' => $sealed + , 'data' => $sealed ); - - } else { - - return false; - - } - - } - - /** - * @brief Asymmetrically encrypt a file using multiple public keys - * @param string $plainContent content to be encrypted - * @returns string $plainContent decrypted string - * @note symmetricDecryptFileContent() can be used to decrypt files created using this method - * - * This function decrypts a file - */ - public static function multiKeyDecrypt( $encryptedContent, $shareKey, $privateKey ) { - - if ( !$encryptedContent ) { - - return false; - - } - - if ( openssl_open( $encryptedContent, $plainContent, $shareKey, $privateKey ) ) { - - return $plainContent; - - } else { - - \OC_Log::write( 'Encryption library', 'Decryption (asymmetric) of sealed content failed', \OC_Log::ERROR ); - - return false; - - } - - } - - /** - * @brief Asymetrically encrypt a string using a public key - * @returns encrypted file - */ - public static function keyEncrypt( $plainContent, $publicKey ) { - openssl_public_encrypt( $plainContent, $encryptedContent, $publicKey ); - - return $encryptedContent; - + } else { + + return false; + + } + } - - /** - * @brief Asymetrically decrypt a file using a private key - * @returns decrypted file - */ - public static function keyDecrypt( $encryptedContent, $privatekey ) { - - $result = @openssl_private_decrypt( $encryptedContent, $plainContent, $privatekey ); - - if ( $result ) { + + /** + * @brief Asymmetrically encrypt a file using multiple public keys + * @param $encryptedContent + * @param $shareKey + * @param $privateKey + * @return bool + * @internal param string $plainContent content to be encrypted + * @returns string $plainContent decrypted string + * @note symmetricDecryptFileContent() can be used to decrypt files created using this method + * + * This function decrypts a file + */ + public static function multiKeyDecrypt($encryptedContent, $shareKey, $privateKey) + { + + if (!$encryptedContent) { + + return false; + + } + + if (openssl_open($encryptedContent, $plainContent, $shareKey, $privateKey)) { + + return $plainContent; + + } else { + + \OC_Log::write('Encryption library', 'Decryption (asymmetric) of sealed content failed', \OC_Log::ERROR); + + return false; + + } + + } + + /** + * @brief Asymetrically encrypt a string using a public key + * @return string encrypted file + */ + public static function keyEncrypt($plainContent, $publicKey) + { + + openssl_public_encrypt($plainContent, $encryptedContent, $publicKey); + + return $encryptedContent; + + } + + /** + * @brief Asymetrically decrypt a file using a private key + * @return string decrypted file + */ + public static function keyDecrypt($encryptedContent, $privatekey) + { + + $result = @openssl_private_decrypt($encryptedContent, $plainContent, $privatekey); + + if ($result) { return $plainContent; } return $result; - + } - + /** * @brief Generates a pseudo random initialisation vector * @return String $iv generated IV */ - public static function generateIv() { - - if ( $random = openssl_random_pseudo_bytes( 12, $strong ) ) { - - if ( !$strong ) { - + public static function generateIv() + { + + if ($random = openssl_random_pseudo_bytes(12, $strong)) { + + if (!$strong) { + // If OpenSSL indicates randomness is insecure, log error - \OC_Log::write( 'Encryption library', 'Insecure symmetric key was generated using openssl_random_pseudo_bytes()', \OC_Log::WARN ); - + \OC_Log::write('Encryption library', 'Insecure symmetric key was generated using openssl_random_pseudo_bytes()', \OC_Log::WARN); + } - + // We encode the iv purely for string manipulation // purposes - it gets decoded before use - $iv = base64_encode( $random ); - + $iv = base64_encode($random); + return $iv; - + } else { - - throw new Exception( 'Generating IV failed' ); - + + throw new \Exception('Generating IV failed'); + } - + } - + /** * @brief Generate a pseudo random 1024kb ASCII key * @returns $key Generated key */ - public static function generateKey() { - + public static function generateKey() + { + // Generate key - if ( $key = base64_encode( openssl_random_pseudo_bytes( 183, $strong ) ) ) { - - if ( !$strong ) { - + if ($key = base64_encode(openssl_random_pseudo_bytes(183, $strong))) { + + if (!$strong) { + // If OpenSSL indicates randomness is insecure, log error - throw new Exception ( 'Encryption library, Insecure symmetric key was generated using openssl_random_pseudo_bytes()' ); - + throw new \Exception('Encryption library, Insecure symmetric key was generated using openssl_random_pseudo_bytes()'); + } - + return $key; - + } else { - + return false; - + } - + } /** @@ -535,70 +562,89 @@ class Crypt { * * if the key is left out, the default handeler will be used */ - public static function getBlowfish( $key = '' ) { - - if ( $key ) { - - return new \Crypt_Blowfish( $key ); - + public static function getBlowfish($key = '') + { + + if ($key) { + + return new \Crypt_Blowfish($key); + } else { - + return false; - + } - + } - - public static function legacyCreateKey( $passphrase ) { - + + /** + * @param $passphrase + * @return mixed + */ + public static function legacyCreateKey($passphrase) + { + // Generate a random integer - $key = mt_rand( 10000, 99999 ) . mt_rand( 10000, 99999 ) . mt_rand( 10000, 99999 ) . mt_rand( 10000, 99999 ); + $key = mt_rand(10000, 99999) . mt_rand(10000, 99999) . mt_rand(10000, 99999) . mt_rand(10000, 99999); // Encrypt the key with the passphrase - $legacyEncKey = self::legacyEncrypt( $key, $passphrase ); + $legacyEncKey = self::legacyEncrypt($key, $passphrase); return $legacyEncKey; - + } /** * @brief encrypts content using legacy blowfish system - * @param $content the cleartext message you want to encrypt - * @param $key the encryption key (optional) - * @returns encrypted content + * @param string $content the cleartext message you want to encrypt + * @param string $passphrase + * @return + * @internal param \OCA\Encryption\the $key encryption key (optional) + * @returns string encrypted content * * This function encrypts an content */ - public static function legacyEncrypt( $content, $passphrase = '' ) { - - $bf = self::getBlowfish( $passphrase ); - - return $bf->encrypt( $content ); - - } - - /** - * @brief decrypts content using legacy blowfish system - * @param $content the cleartext message you want to decrypt - * @param $key the encryption key (optional) - * @returns cleartext content - * - * This function decrypts an content - */ - public static function legacyDecrypt( $content, $passphrase = '' ) { - - $bf = self::getBlowfish( $passphrase ); - - $decrypted = $bf->decrypt( $content ); - - return rtrim($decrypted, "\0");; - + public static function legacyEncrypt($content, $passphrase = '') + { + + $bf = self::getBlowfish($passphrase); + + return $bf->encrypt($content); + } - private static function legacyBlockDecrypt($data, $key='',$maxLength=0) { + /** + * @brief decrypts content using legacy blowfish system + * @param string $content the cleartext message you want to decrypt + * @param string $passphrase + * @return string + * @internal param \OCA\Encryption\the $key encryption key (optional) + * @return string cleartext content + * + * This function decrypts an content + */ + public static function legacyDecrypt($content, $passphrase = '') + { + + $bf = self::getBlowfish($passphrase); + + $decrypted = $bf->decrypt($content); + + return rtrim($decrypted, "\0");; + + } + + /** + * @param $data + * @param string $key + * @param int $maxLength + * @return string + */ + private static function legacyBlockDecrypt($data, $key = '', $maxLength = 0) + { $result = ''; while (strlen($data)) { - $result.=self::legacyDecrypt(substr($data, 0, 8192), $key); + $result .= self::legacyDecrypt(substr($data, 0, 8192), $key); $data = substr($data, 8192); } if ($maxLength > 0) { @@ -607,19 +653,28 @@ class Crypt { return rtrim($result, "\0"); } } - - public static function legacyKeyRecryptKeyfile( $legacyEncryptedContent, $legacyPassphrase, $publicKeys, $newPassphrase, $path ) { - - $decrypted = self::legacyBlockDecrypt( $legacyEncryptedContent, $legacyPassphrase ); + + /** + * @param $legacyEncryptedContent + * @param $legacyPassphrase + * @param $publicKeys + * @param $newPassphrase + * @param $path + * @return array + */ + public static function legacyKeyRecryptKeyfile($legacyEncryptedContent, $legacyPassphrase, $publicKeys, $newPassphrase, $path) + { + + $decrypted = self::legacyBlockDecrypt($legacyEncryptedContent, $legacyPassphrase); // Encrypt plain data, generate keyfile & encrypted file - $cryptedData = self::symmetricEncryptFileContentKeyfile( $decrypted ); + $cryptedData = self::symmetricEncryptFileContentKeyfile($decrypted); // Encrypt plain keyfile to multiple sharefiles - $multiEncrypted = Crypt::multiKeyEncrypt( $cryptedData['key'], $publicKeys ); + $multiEncrypted = Crypt::multiKeyEncrypt($cryptedData['key'], $publicKeys); + + return array('data' => $cryptedData['encrypted'], 'filekey' => $multiEncrypted['data'], 'sharekeys' => $multiEncrypted['keys']); - return array( 'data' => $cryptedData['encrypted'], 'filekey' => $multiEncrypted['data'], 'sharekeys' => $multiEncrypted['keys'] ); - } } \ No newline at end of file diff --git a/apps/files_encryption/lib/helper.php b/apps/files_encryption/lib/helper.php index a04c65e251..c57f0bc009 100755 --- a/apps/files_encryption/lib/helper.php +++ b/apps/files_encryption/lib/helper.php @@ -23,76 +23,82 @@ namespace OCA\Encryption; -/** - * @brief Class to manage registration of hooks an various helper methods - */ + /** + * @brief Class to manage registration of hooks an various helper methods + */ /** * Class Helper * @package OCA\Encryption */ -class Helper { - +class Helper +{ + /** * @brief register share related hooks - * + * */ - public static function registerShareHooks() { + public static function registerShareHooks() + { - \OCP\Util::connectHook( 'OCP\Share', 'pre_shared', 'OCA\Encryption\Hooks', 'preShared' ); - \OCP\Util::connectHook( 'OCP\Share', 'post_shared', 'OCA\Encryption\Hooks', 'postShared' ); - \OCP\Util::connectHook( 'OCP\Share', 'post_unshare', 'OCA\Encryption\Hooks', 'postUnshare' ); + \OCP\Util::connectHook('OCP\Share', 'pre_shared', 'OCA\Encryption\Hooks', 'preShared'); + \OCP\Util::connectHook('OCP\Share', 'post_shared', 'OCA\Encryption\Hooks', 'postShared'); + \OCP\Util::connectHook('OCP\Share', 'post_unshare', 'OCA\Encryption\Hooks', 'postUnshare'); } - /** - * @brief register user related hooks - * - */ - public static function registerUserHooks() { + /** + * @brief register user related hooks + * + */ + public static function registerUserHooks() + { - \OCP\Util::connectHook( 'OC_User', 'post_login', 'OCA\Encryption\Hooks', 'login' ); - \OCP\Util::connectHook( 'OC_User', 'post_setPassword', 'OCA\Encryption\Hooks', 'setPassphrase' ); - \OCP\Util::connectHook( 'OC_User', 'post_createUser', 'OCA\Encryption\Hooks', 'postCreateUser' ); - \OCP\Util::connectHook( 'OC_User', 'post_deleteUser', 'OCA\Encryption\Hooks', 'postDeleteUser' ); - } + \OCP\Util::connectHook('OC_User', 'post_login', 'OCA\Encryption\Hooks', 'login'); + \OCP\Util::connectHook('OC_User', 'post_setPassword', 'OCA\Encryption\Hooks', 'setPassphrase'); + \OCP\Util::connectHook('OC_User', 'post_createUser', 'OCA\Encryption\Hooks', 'postCreateUser'); + \OCP\Util::connectHook('OC_User', 'post_deleteUser', 'OCA\Encryption\Hooks', 'postDeleteUser'); + } - /** - * @brief register webdav related hooks - * - */ - public static function registerWebdavHooks() { + /** + * @brief register webdav related hooks + * + */ + public static function registerWebdavHooks() + { - } + } - /** - * @brief register filesystem related hooks - * - */ - public static function registerFilesystemHooks() { + /** + * @brief register filesystem related hooks + * + */ + public static function registerFilesystemHooks() + { - \OCP\Util::connectHook('OC_Filesystem', 'post_rename', 'OCA\Encryption\Hooks', 'postRename'); - } + \OCP\Util::connectHook('OC_Filesystem', 'post_rename', 'OCA\Encryption\Hooks', 'postRename'); + } - /** - * @brief setup user for files_encryption - * - * @param Util $util - * @param string $password - * @return bool - */ - public static function setupUser($util, $password) { - // Check files_encryption infrastructure is ready for action - if ( ! $util->ready() ) { + /** + * @brief setup user for files_encryption + * + * @param Util $util + * @param string $password + * @return bool + */ + public static function setupUser($util, $password) + { + // Check files_encryption infrastructure is ready for action + if (!$util->ready()) { - \OC_Log::write( 'Encryption library', 'User account "' . $util->getUserId() . '" is not ready for encryption; configuration started', \OC_Log::DEBUG ); + \OC_Log::write('Encryption library', 'User account "' . $util->getUserId() . '" is not ready for encryption; configuration started', \OC_Log::DEBUG); - if(!$util->setupServerSide( $password )) { - return false; - } - } + if (!$util->setupServerSide($password)) { + return false; + } + } - return true; - } + return true; + } /** * @brief enable recovery @@ -103,7 +109,8 @@ class Helper { * @internal param string $password * @return bool */ - public static function adminEnableRecovery($recoveryKeyId, $recoveryPassword) { + public static function adminEnableRecovery($recoveryKeyId, $recoveryPassword) + { $view = new \OC\Files\View('/'); if ($recoveryKeyId === null) { @@ -139,7 +146,7 @@ class Helper { $view->file_put_contents('/owncloud_private_key/' . $recoveryKeyId . '.private.key', $encryptedPrivateKey); // create control file which let us check later on if the entered password was correct. - $encryptedControlData = \OCA\Encryption\Crypt::keyEncrypt("ownCloud", $keypair['publicKey']); + $encryptedControlData = \OCA\Encryption\Crypt::keyEncrypt("ownCloud", $keypair['publicKey']); if (!$view->is_dir('/control-file')) { $view->mkdir('/control-file'); } @@ -170,7 +177,8 @@ class Helper { * @param $recoveryPassword * @return bool */ - public static function adminDisableRecovery($recoveryPassword) { + public static function adminDisableRecovery($recoveryPassword) + { $util = new Util(new \OC_FilesystemView('/'), \OCP\User::getUser()); $return = $util->checkRecoveryPassword($recoveryPassword); diff --git a/apps/files_encryption/lib/keymanager.php b/apps/files_encryption/lib/keymanager.php index b422ff099b..1bc334e7a1 100755 --- a/apps/files_encryption/lib/keymanager.php +++ b/apps/files_encryption/lib/keymanager.php @@ -27,7 +27,8 @@ namespace OCA\Encryption; * @brief Class to manage storage and retrieval of encryption keys * @note Where a method requires a view object, it's root must be '/' */ -class Keymanager { +class Keymanager +{ /** * @brief retrieve the ENCRYPTED private key from a user @@ -37,17 +38,18 @@ class Keymanager { * @return string private key or false (hopefully) * @note the key returned by this method must be decrypted before use */ - public static function getPrivateKey( \OC_FilesystemView $view, $user ) { - - $path = '/' . $user . '/' . 'files_encryption' . '/' . $user.'.private.key'; + public static function getPrivateKey(\OC_FilesystemView $view, $user) + { - $proxyStatus = \OC_FileProxy::$enabled; - \OC_FileProxy::$enabled = false; + $path = '/' . $user . '/' . 'files_encryption' . '/' . $user . '.private.key'; - $key = $view->file_get_contents( $path ); + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; + + $key = $view->file_get_contents($path); + + \OC_FileProxy::$enabled = $proxyStatus; - \OC_FileProxy::$enabled = $proxyStatus; - return $key; } @@ -57,104 +59,111 @@ class Keymanager { * @param $userId * @return string public key or false */ - public static function getPublicKey( \OC_FilesystemView $view, $userId ) { + public static function getPublicKey(\OC_FilesystemView $view, $userId) + { - $proxyStatus = \OC_FileProxy::$enabled; + $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; - - $result = $view->file_get_contents( '/public-keys/' . $userId . '.public.key' ); - + + $result = $view->file_get_contents('/public-keys/' . $userId . '.public.key'); + \OC_FileProxy::$enabled = $proxyStatus; - return $result; - + return $result; + } - + /** * @brief Retrieve a user's public and private key * @param \OC_FilesystemView $view * @param $userId * @return array keys: privateKey, publicKey */ - public static function getUserKeys( \OC_FilesystemView $view, $userId ) { - + public static function getUserKeys(\OC_FilesystemView $view, $userId) + { + return array( - 'publicKey' => self::getPublicKey( $view, $userId ) - , 'privateKey' => self::getPrivateKey( $view, $userId ) + 'publicKey' => self::getPublicKey($view, $userId) + , 'privateKey' => self::getPrivateKey($view, $userId) ); - + } - + /** * @brief Retrieve public keys for given users * @param \OC_FilesystemView $view * @param array $userIds * @return array of public keys for the specified users */ - public static function getPublicKeys( \OC_FilesystemView $view, array $userIds ) { - + public static function getPublicKeys(\OC_FilesystemView $view, array $userIds) + { + $keys = array(); - - foreach ( $userIds as $userId ) { - - $keys[$userId] = self::getPublicKey( $view, $userId ); - + + foreach ($userIds as $userId) { + + $keys[$userId] = self::getPublicKey($view, $userId); + } - + return $keys; - + } - + /** * @brief store file encryption key * + * @param \OC_FilesystemView $view * @param string $path relative path of the file, including filename - * @param string $key + * @param $userId + * @param $catfile + * @internal param string $key * @return bool true/false - * @note The keyfile is not encrypted here. Client code must + * @note The keyfile is not encrypted here. Client code must * asymmetrically encrypt the keyfile before passing it to this method */ - public static function setFileKey( \OC_FilesystemView $view, $path, $userId, $catfile ) { - + public static function setFileKey(\OC_FilesystemView $view, $path, $userId, $catfile) + { + $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; //here we need the currently logged in user, while userId can be a different user - $util = new Util( $view, \OCP\User::getUser() ); - list( $owner, $filename ) = $util->getUidAndFilename( $path ); + $util = new Util($view, \OCP\User::getUser()); + list($owner, $filename) = $util->getUidAndFilename($path); $basePath = '/' . $owner . '/files_encryption/keyfiles'; - - $targetPath = self::keySetPreparation( $view, $filename, $basePath, $owner ); - - if ( !$view->is_dir( $basePath . '/' . $targetPath ) ) { + + $targetPath = self::keySetPreparation($view, $filename, $basePath, $owner); + + if (!$view->is_dir($basePath . '/' . $targetPath)) { // create all parent folders - $info = pathinfo( $basePath . '/' . $targetPath ); - $keyfileFolderName = $view->getLocalFolder( $info['dirname'] ); - - if ( ! file_exists( $keyfileFolderName ) ) { - - mkdir( $keyfileFolderName, 0750, true ); - + $info = pathinfo($basePath . '/' . $targetPath); + $keyfileFolderName = $view->getLocalFolder($info['dirname']); + + if (!file_exists($keyfileFolderName)) { + + mkdir($keyfileFolderName, 0750, true); + } } // try reusing key file if part file - if ( self::isPartialFilePath( $targetPath ) ) { - - $result = $view->file_put_contents( $basePath . '/' . self::fixPartialFilePath( $targetPath ) . '.key', $catfile ); - + if (self::isPartialFilePath($targetPath)) { + + $result = $view->file_put_contents($basePath . '/' . self::fixPartialFilePath($targetPath) . '.key', $catfile); + } else { - - $result = $view->file_put_contents( $basePath . '/' . $targetPath . '.key', $catfile ); - + + $result = $view->file_put_contents($basePath . '/' . $targetPath . '.key', $catfile); + } - + \OC_FileProxy::$enabled = $proxyStatus; - + return $result; - + } /** @@ -163,15 +172,16 @@ class Keymanager { * @return string File path without .part extension * @note this is needed for reusing keys */ - public static function fixPartialFilePath( $path ) { - + public static function fixPartialFilePath($path) + { + if (preg_match('/\.part$/', $path)) { $newLength = strlen($path) - 5; $fPath = substr($path, 0, $newLength); return $fPath; - + } else { return $path; @@ -185,19 +195,21 @@ class Keymanager { * @param string $path Path that may identify a .part file * @return bool */ - public static function isPartialFilePath( $path ) { - - if ( preg_match('/\.part$/', $path ) ) { - + public static function isPartialFilePath($path) + { + + if (preg_match('/\.part$/', $path)) { + return true; - + } else { - + return false; - + } } + /** * @brief retrieve keyfile for an encrypted file * @param \OC_FilesystemView $view @@ -208,227 +220,239 @@ class Keymanager { * @note The keyfile returned is asymmetrically encrypted. Decryption * of the keyfile must be performed by client code */ - public static function getFileKey( \OC_FilesystemView $view, $userId, $filePath ) { + public static function getFileKey(\OC_FilesystemView $view, $userId, $filePath) + { // try reusing key file if part file - if ( self::isPartialFilePath( $filePath ) ) { - - $result = self::getFileKey( $view, $userId, self::fixPartialFilePath( $filePath ) ); - - if ( $result ) { - + if (self::isPartialFilePath($filePath)) { + + $result = self::getFileKey($view, $userId, self::fixPartialFilePath($filePath)); + + if ($result) { + return $result; - + } - + } $util = new Util($view, \OCP\User::getUser()); list($owner, $filename) = $util->getUidAndFilename($filePath); - $filePath_f = ltrim( $filename, '/' ); + $filePath_f = ltrim($filename, '/'); $keyfilePath = '/' . $owner . '/files_encryption/keyfiles/' . $filePath_f . '.key'; $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; - - if ( $view->file_exists( $keyfilePath ) ) { - $result = $view->file_get_contents( $keyfilePath ); - + if ($view->file_exists($keyfilePath)) { + + $result = $view->file_get_contents($keyfilePath); + } else { - - $result = false; - + + $result = false; + } - + \OC_FileProxy::$enabled = $proxyStatus; - + return $result; - + } - + /** * @brief Delete a keyfile * - * @param OC_FilesystemView $view + * @param \OC_FilesystemView $view * @param string $userId username * @param string $path path of the file the key belongs to * @return bool Outcome of unlink operation * @note $path must be relative to data/user/files. e.g. mydoc.txt NOT * /data/admin/files/mydoc.txt */ - public static function deleteFileKey( \OC_FilesystemView $view, $userId, $path ) { - - $trimmed = ltrim( $path, '/' ); - $keyPath = '/' . $userId . '/files_encryption/keyfiles/' . $trimmed; + public static function deleteFileKey(\OC_FilesystemView $view, $userId, $path) + { + + $trimmed = ltrim($path, '/'); + $keyPath = '/' . $userId . '/files_encryption/keyfiles/' . $trimmed; $result = false; - if ( $view->is_dir($keyPath) ) { + if ($view->is_dir($keyPath)) { $result = $view->unlink($keyPath); - } else if ( $view->file_exists( $keyPath.'.key' ) ) { + } else if ($view->file_exists($keyPath . '.key')) { - $result = $view->unlink( $keyPath.'.key' ); + $result = $view->unlink($keyPath . '.key'); } - if ( !$result ) { - - \OC_Log::write( 'Encryption library', 'Could not delete keyfile; does not exist: "' . $keyPath, \OC_Log::ERROR ); + if (!$result) { + + \OC_Log::write('Encryption library', 'Could not delete keyfile; does not exist: "' . $keyPath, \OC_Log::ERROR); } return $result; - + } - + /** * @brief store private key from the user - * @param string key + * @param string $key * @return bool * @note Encryption of the private key must be performed by client code * as no encryption takes place here */ - public static function setPrivateKey( $key ) { - + public static function setPrivateKey($key) + { + $user = \OCP\User::getUser(); - - $view = new \OC_FilesystemView( '/' . $user . '/files_encryption' ); + + $view = new \OC_FilesystemView('/' . $user . '/files_encryption'); $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; - - if ( !$view->file_exists( '' ) ) $view->mkdir( '' ); - - $result = $view->file_put_contents( $user . '.private.key', $key ); - + + if (!$view->file_exists('')) $view->mkdir(''); + + $result = $view->file_put_contents($user . '.private.key', $key); + \OC_FileProxy::$enabled = $proxyStatus; return $result; - + } - + /** * @brief store private keys from the user * - * @param string privatekey - * @param string publickey + * @param string $privatekey + * @param string $publickey * @return bool true/false */ - public static function setUserKeys($privatekey, $publickey) { - - return ( self::setPrivateKey( $privatekey ) && self::setPublicKey( $publickey ) ); - + public static function setUserKeys($privatekey, $publickey) + { + + return (self::setPrivateKey($privatekey) && self::setPublicKey($publickey)); + } - + /** * @brief store public key of the user * - * @param string key + * @param string $key * @return bool true/false */ - public static function setPublicKey( $key ) { - - $view = new \OC_FilesystemView( '/public-keys' ); + public static function setPublicKey($key) + { + + $view = new \OC_FilesystemView('/public-keys'); $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; - - if ( !$view->file_exists( '' ) ) $view->mkdir( '' ); - - $result = $view->file_put_contents( \OCP\User::getUser() . '.public.key', $key ); - + + if (!$view->file_exists('')) $view->mkdir(''); + + $result = $view->file_put_contents(\OCP\User::getUser() . '.public.key', $key); + \OC_FileProxy::$enabled = $proxyStatus; return $result; - + } - + /** * @brief store share key * + * @param \OC_FilesystemView $view * @param string $path relative path of the file, including filename - * @param string $key - * @param null $view - * @param string $dbClassName + * @param $userId + * @param $shareKey + * @internal param string $key + * @internal param string $dbClassName * @return bool true/false * @note The keyfile is not encrypted here. Client code must * asymmetrically encrypt the keyfile before passing it to this method */ - public static function setShareKey( \OC_FilesystemView $view, $path, $userId, $shareKey ) { + public static function setShareKey(\OC_FilesystemView $view, $path, $userId, $shareKey) + { // Here we need the currently logged in user, while userId can be a different user - $util = new Util( $view, \OCP\User::getUser() ); + $util = new Util($view, \OCP\User::getUser()); - list( $owner, $filename ) = $util->getUidAndFilename( $path ); + list($owner, $filename) = $util->getUidAndFilename($path); $basePath = '/' . $owner . '/files_encryption/share-keys'; - - $shareKeyPath = self::keySetPreparation( $view, $filename, $basePath, $owner ); + + $shareKeyPath = self::keySetPreparation($view, $filename, $basePath, $owner); // try reusing key file if part file - if(self::isPartialFilePath($shareKeyPath)) { - + if (self::isPartialFilePath($shareKeyPath)) { + $writePath = $basePath . '/' . self::fixPartialFilePath($shareKeyPath) . '.' . $userId . '.shareKey'; - + } else { - + $writePath = $basePath . '/' . $shareKeyPath . '.' . $userId . '.shareKey'; - + } $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; - $result = $view->file_put_contents( $writePath, $shareKey ); + $result = $view->file_put_contents($writePath, $shareKey); \OC_FileProxy::$enabled = $proxyStatus; - if ( - is_int( $result ) + if ( + is_int($result) && $result > 0 ) { - + return true; - + } else { - + return false; - + } - + } - + /** * @brief store multiple share keys for a single file + * @param \OC_FilesystemView $view + * @param $path + * @param array $shareKeys * @return bool */ - public static function setShareKeys( \OC_FilesystemView $view, $path, array $shareKeys ) { + public static function setShareKeys(\OC_FilesystemView $view, $path, array $shareKeys) + { // $shareKeys must be an array with the following format: // [userId] => [encrypted key] - + $result = true; - - foreach ( $shareKeys as $userId => $shareKey ) { - - if ( ! self::setShareKey( $view, $path, $userId, $shareKey ) ) { - + + foreach ($shareKeys as $userId => $shareKey) { + + if (!self::setShareKey($view, $path, $userId, $shareKey)) { + // If any of the keys are not set, flag false $result = false; - + } - + } - + // Returns false if any of the keys weren't set return $result; - + } - + /** * @brief retrieve shareKey for an encrypted file * @param \OC_FilesystemView $view @@ -439,59 +463,61 @@ class Keymanager { * @note The sharekey returned is encrypted. Decryption * of the keyfile must be performed by client code */ - public static function getShareKey( \OC_FilesystemView $view, $userId, $filePath ) { + public static function getShareKey(\OC_FilesystemView $view, $userId, $filePath) + { // try reusing key file if part file - if(self::isPartialFilePath($filePath)) { - + if (self::isPartialFilePath($filePath)) { + $result = self::getShareKey($view, $userId, self::fixPartialFilePath($filePath)); - - if($result) { - + + if ($result) { + return $result; - + } - + } $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; //here we need the currently logged in user, while userId can be a different user - $util = new Util( $view, \OCP\User::getUser() ); + $util = new Util($view, \OCP\User::getUser()); list($owner, $filename) = $util->getUidAndFilename($filePath); $shareKeyPath = \OC\Files\Filesystem::normalizePath('/' . $owner . '/files_encryption/share-keys/' . $filename . '.' . $userId . '.shareKey'); - if ( $view->file_exists( $shareKeyPath ) ) { - - $result = $view->file_get_contents( $shareKeyPath ); - + if ($view->file_exists($shareKeyPath)) { + + $result = $view->file_get_contents($shareKeyPath); + } else { - + $result = false; - + } - + \OC_FileProxy::$enabled = $proxyStatus; - + return $result; - + } /** * @brief delete all share keys of a given file * @param \OC_FilesystemView $view - * @param type $userId owner of the file - * @param type $filePath path to the file, relative to the owners file dir + * @param string $userId owner of the file + * @param string $filePath path to the file, relative to the owners file dir */ - public static function delAllShareKeys(\OC_FilesystemView $view, $userId, $filePath) { - - if ($view->is_dir($userId.'/files/'.$filePath)) { - $view->unlink($userId.'/files_encryption/share-keys/'.$filePath); + public static function delAllShareKeys(\OC_FilesystemView $view, $userId, $filePath) + { + + if ($view->is_dir($userId . '/files/' . $filePath)) { + $view->unlink($userId . '/files_encryption/share-keys/' . $filePath); } else { - $localKeyPath = $view->getLocalFile($userId.'/files_encryption/share-keys/'.$filePath); - $matches = glob(preg_quote($localKeyPath).'*.shareKey'); + $localKeyPath = $view->getLocalFile($userId . '/files_encryption/share-keys/' . $filePath); + $matches = glob(preg_quote($localKeyPath) . '*.shareKey'); foreach ($matches as $ma) { unlink($ma); } @@ -501,13 +527,14 @@ class Keymanager { /** * @brief Delete a single user's shareKey for a single file */ - public static function delShareKey( \OC_FilesystemView $view, $userIds, $filePath ) { + public static function delShareKey(\OC_FilesystemView $view, $userIds, $filePath) + { - $proxyStatus = \OC_FileProxy::$enabled; + $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; //here we need the currently logged in user, while userId can be a different user - $util = new Util( $view, \OCP\User::getUser() ); + $util = new Util($view, \OCP\User::getUser()); list($owner, $filename) = $util->getUidAndFilename($filePath); @@ -515,7 +542,7 @@ class Keymanager { $result = false; - if ( $view->is_dir($shareKeyPath) ) { + if ($view->is_dir($shareKeyPath)) { $localPath = \OC_Filesystem::normalizePath($view->getLocalFolder($shareKeyPath)); $result = self::recursiveDelShareKeys($localPath, $userIds); @@ -523,40 +550,42 @@ class Keymanager { } else { foreach ($userIds as $userId) { - $view->unlink($shareKeyPath.'.'.$userId.'.shareKey'); + $view->unlink($shareKeyPath . '.' . $userId . '.shareKey'); } $result = true; } - if ( ! $result ) { - - \OC_Log::write( 'Encryption library', 'Could not delete shareKey; does not exist: "' . $shareKeyPath, \OC_Log::ERROR ); - + if (!$result) { + + \OC_Log::write('Encryption library', 'Could not delete shareKey; does not exist: "' . $shareKeyPath, \OC_Log::ERROR); + } - + \OC_FileProxy::$enabled = $proxyStatus; - + return $result; - + } /** * @brief recursively delete share keys from given users * - * @param type $dir directory - * @param type $userIds user ids for which the share keys should be deleted + * @param string $dir directory + * @param array $userIds user ids for which the share keys should be deleted */ - private static function recursiveDelShareKeys($dir, $userIds) { + private static function recursiveDelShareKeys($dir, $userIds) + { foreach ($userIds as $userId) { - $completePath = $dir.'/.*'.'.'.$userId.'.shareKey'; - $matches = glob(preg_quote($dir).'/*'.preg_quote('.'.$userId.'.shareKey')); + $completePath = $dir . '/.*' . '.' . $userId . '.shareKey'; + $matches = glob(preg_quote($dir) . '/*' . preg_quote('.' . $userId . '.shareKey')); } - foreach ($matches as $ma) { + /** @var $matches array */ + foreach ($matches as $ma) { unlink($ma); } - $subdirs = $directories = glob(preg_quote($dir) . '/*' , GLOB_ONLYDIR); - foreach ( $subdirs as $subdir ) { + $subdirs = $directories = glob(preg_quote($dir) . '/*', GLOB_ONLYDIR); + foreach ($subdirs as $subdir) { self::recursiveDelShareKeys($subdir, $userIds); } return true; @@ -565,16 +594,17 @@ class Keymanager { /** * @brief Make preparations to vars and filesystem for saving a keyfile */ - public static function keySetPreparation( \OC_FilesystemView $view, $path, $basePath, $userId ) { - - $targetPath = ltrim( $path, '/' ); - - $path_parts = pathinfo( $targetPath ); - + public static function keySetPreparation(\OC_FilesystemView $view, $path, $basePath, $userId) + { + + $targetPath = ltrim($path, '/'); + + $path_parts = pathinfo($targetPath); + // If the file resides within a subdirectory, create it - if ( - isset( $path_parts['dirname'] ) - && ! $view->file_exists( $basePath . '/' . $path_parts['dirname'] ) + if ( + isset($path_parts['dirname']) + && !$view->file_exists($basePath . '/' . $path_parts['dirname']) ) { $sub_dirs = explode(DIRECTORY_SEPARATOR, $basePath . '/' . $path_parts['dirname']); $dir = ''; @@ -585,41 +615,26 @@ class Keymanager { } } } - + return $targetPath; - + } - - /** - * @brief change password of private encryption key - * - * @param string $oldpasswd old password - * @param string $newpasswd new password - * @return bool true/false - */ - public static function changePasswd($oldpasswd, $newpasswd) { - - if ( \OCP\User::checkPassword(\OCP\User::getUser(), $newpasswd) ) { - return Crypt::changekeypasscode($oldpasswd, $newpasswd); - } - return false; - - } - + /** * @brief Fetch the legacy encryption key from user files - * @param string $login used to locate the legacy key - * @param string $passphrase used to decrypt the legacy key - * @return true / false + * @internal param string $login used to locate the legacy key + * @internal param string $passphrase used to decrypt the legacy key + * @return boolean * * if the key is left out, the default handeler will be used */ - public function getLegacyKey() { - + public function getLegacyKey() + { + $user = \OCP\User::getUser(); - $view = new \OC_FilesystemView( '/' . $user ); - return $view->file_get_contents( 'encryption.key' ); - + $view = new \OC_FilesystemView('/' . $user); + return $view->file_get_contents('encryption.key'); + } - + } \ No newline at end of file diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index 1d60770b4d..55ad882a8f 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -1,41 +1,46 @@ . -* -*/ + * ownCloud + * + * @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 + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this library. If not, see . + * + */ /** -* @brief Encryption proxy which handles filesystem operations before and after -* execution and encrypts, and handles keyfiles accordingly. Used for -* webui. -*/ + * @brief Encryption proxy which handles filesystem operations before and after + * execution and encrypts, and handles keyfiles accordingly. Used for + * webui. + */ namespace OCA\Encryption; -class Proxy extends \OC_FileProxy { +/** + * Class Proxy + * @package OCA\Encryption + */ +class Proxy extends \OC_FileProxy +{ private static $blackList = null; //mimetypes blacklisted from encryption - + private static $enableEncryption = null; - + /** * Check if a file requires encryption * @param string $path @@ -43,461 +48,481 @@ class Proxy extends \OC_FileProxy { * * Tests if server side encryption is enabled, and file is allowed by blacklists */ - private static function shouldEncrypt( $path ) { - - if ( is_null( self::$enableEncryption ) ) { - - if ( - \OCP\Config::getAppValue( 'files_encryption', 'enable_encryption', 'true' ) == 'true' - && Crypt::mode() == 'server' + private static function shouldEncrypt($path) + { + + if (is_null(self::$enableEncryption)) { + + if ( + \OCP\Config::getAppValue('files_encryption', 'enable_encryption', 'true') == 'true' + && Crypt::mode() == 'server' ) { - + self::$enableEncryption = true; - + } else { - + self::$enableEncryption = false; - + } - + } - - if ( !self::$enableEncryption ) { - + + if (!self::$enableEncryption) { + return false; - + } - - if ( is_null(self::$blackList ) ) { - - self::$blackList = explode(',', \OCP\Config::getAppValue( 'files_encryption', 'type_blacklist', '' ) ); - + + if (is_null(self::$blackList)) { + + self::$blackList = explode(',', \OCP\Config::getAppValue('files_encryption', 'type_blacklist', '')); + } - - if ( Crypt::isCatfileContent( $path ) ) { - + + if (Crypt::isCatfileContent($path)) { + return true; - + } - - $extension = substr( $path, strrpos( $path, '.' ) +1 ); - - if ( array_search( $extension, self::$blackList ) === false ) { - + + $extension = substr($path, strrpos($path, '.') + 1); + + if (array_search($extension, self::$blackList) === false) { + return true; - + } - + return false; } - - public function preFile_put_contents( $path, &$data ) { - if ( self::shouldEncrypt( $path ) ) { + /** + * @param $path + * @param $data + * @return bool + */ + public function preFile_put_contents($path, &$data) + { + + if (self::shouldEncrypt($path)) { // Stream put contents should have been converted to fopen - if ( !is_resource( $data ) ) { + if (!is_resource($data)) { $userId = \OCP\USER::getUser(); - $view = new \OC_FilesystemView( '/' ); - $util = new Util( $view, $userId ); - $session = new Session( $view ); + $view = new \OC_FilesystemView('/'); + $util = new Util($view, $userId); + $session = new Session($view); $privateKey = $session->getPrivateKey(); - $filePath = $util->stripUserFilesPath( $path ); + $filePath = $util->stripUserFilesPath($path); // Set the filesize for userland, before encrypting - $size = strlen( $data ); - + $size = strlen($data); + // Disable encryption proxy to prevent recursive calls $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; - + // Check if there is an existing key we can reuse - if ( $encKeyfile = Keymanager::getFileKey( $view, $userId, $filePath ) ) { - + if ($encKeyfile = Keymanager::getFileKey($view, $userId, $filePath)) { + // Fetch shareKey - $shareKey = Keymanager::getShareKey( $view, $userId, $filePath ); - + $shareKey = Keymanager::getShareKey($view, $userId, $filePath); + // Decrypt the keyfile - $plainKey = Crypt::multiKeyDecrypt( $encKeyfile, $shareKey, $privateKey ); - + $plainKey = Crypt::multiKeyDecrypt($encKeyfile, $shareKey, $privateKey); + } else { - + // Make a new key $plainKey = Crypt::generateKey(); - + } - + // Encrypt data - $encData = Crypt::symmetricEncryptFileContent( $data, $plainKey ); - + $encData = Crypt::symmetricEncryptFileContent($data, $plainKey); + $sharingEnabled = \OCP\Share::isEnabled(); // if file exists try to get sharing users - if($view->file_exists($path)) { - $uniqueUserIds = $util->getSharingUsersArray( $sharingEnabled, $filePath, $userId ); + if ($view->file_exists($path)) { + $uniqueUserIds = $util->getSharingUsersArray($sharingEnabled, $filePath, $userId); } else { $uniqueUserIds[] = $userId; } // Fetch public keys for all users who will share the file - $publicKeys = Keymanager::getPublicKeys( $view, $uniqueUserIds ); + $publicKeys = Keymanager::getPublicKeys($view, $uniqueUserIds); // Encrypt plain keyfile to multiple sharefiles - $multiEncrypted = Crypt::multiKeyEncrypt( $plainKey, $publicKeys ); - + $multiEncrypted = Crypt::multiKeyEncrypt($plainKey, $publicKeys); + // Save sharekeys to user folders - Keymanager::setShareKeys( $view, $filePath, $multiEncrypted['keys'] ); - + Keymanager::setShareKeys($view, $filePath, $multiEncrypted['keys']); + // Set encrypted keyfile as common varname $encKey = $multiEncrypted['data']; - + // Save keyfile for newly encrypted file in parallel directory tree - Keymanager::setFileKey( $view, $filePath, $userId, $encKey ); + Keymanager::setFileKey($view, $filePath, $userId, $encKey); // Replace plain content with encrypted content by reference $data = $encData; - + // Update the file cache with file info - \OC\Files\Filesystem::putFileInfo( $filePath, array( 'encrypted'=>true, 'size' => strlen($size), 'unencrypted_size' => $size), '' ); + \OC\Files\Filesystem::putFileInfo($filePath, array('encrypted' => true, 'size' => strlen($size), 'unencrypted_size' => $size), ''); // Re-enable proxy - our work is done \OC_FileProxy::$enabled = $proxyStatus; - + } } return true; - + } - + /** * @param string $path Path of file from which has been read * @param string $data Data that has been read from file */ - public function postFile_get_contents( $path, $data ) { + public function postFile_get_contents($path, $data) + { + + // FIXME: $path for shared files is just /uid/files/Shared/filepath - // FIXME: $path for shared files is just /uid/files/Shared/filepath - $userId = \OCP\USER::getUser(); - $view = new \OC_FilesystemView( '/' ); - $util = new Util( $view, $userId ); - - $relPath = $util->stripUserFilesPath( $path ); - - + $view = new \OC_FilesystemView('/'); + $util = new Util($view, $userId); + + $relPath = $util->stripUserFilesPath($path); + + // TODO check for existing key file and reuse it if possible to avoid problems with versioning etc. // Disable encryption proxy to prevent recursive calls - $proxyStatus = \OC_FileProxy::$enabled; - \OC_FileProxy::$enabled = false; + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; - // If data is a catfile - if ( - Crypt::mode() == 'server' - && Crypt::isCatfileContent( $data ) // TODO: Do we really need this check? Can't we assume it is properly encrypted? + // If data is a catfile + if ( + Crypt::mode() == 'server' + && Crypt::isCatfileContent($data) // TODO: Do we really need this check? Can't we assume it is properly encrypted? ) { - + // TODO: use get owner to find correct location of key files for shared files - $session = new Session( $view ); - $privateKey = $session->getPrivateKey( $userId ); - + $session = new Session($view); + $privateKey = $session->getPrivateKey($userId); + // Get the encrypted keyfile - $encKeyfile = Keymanager::getFileKey( $view, $userId, $relPath ); - + $encKeyfile = Keymanager::getFileKey($view, $userId, $relPath); + // Attempt to fetch the user's shareKey - $shareKey = Keymanager::getShareKey( $view, $userId, $relPath ); - + $shareKey = Keymanager::getShareKey($view, $userId, $relPath); + // Decrypt keyfile with shareKey - $plainKeyfile = Crypt::multiKeyDecrypt( $encKeyfile, $shareKey, $privateKey ); - - $plainData = Crypt::symmetricDecryptFileContent( $data, $plainKeyfile ); + $plainKeyfile = Crypt::multiKeyDecrypt($encKeyfile, $shareKey, $privateKey); + + $plainData = Crypt::symmetricDecryptFileContent($data, $plainKeyfile); } elseif ( - Crypt::mode() == 'server' - && isset( $_SESSION['legacyenckey'] ) - && Crypt::isEncryptedMeta( $path ) + Crypt::mode() == 'server' + && isset($_SESSION['legacyenckey']) + && Crypt::isEncryptedMeta($path) ) { - - $plainData = Crypt::legacyDecrypt( $data, $session->getLegacyKey() ); - + + $plainData = Crypt::legacyDecrypt($data, $session->getLegacyKey()); + } - + \OC_FileProxy::$enabled = $proxyStatus; - - if ( ! isset( $plainData ) ) { - + + if (!isset($plainData)) { + $plainData = $data; - + } - + return $plainData; - + } - + /** * @brief When a file is deleted, remove its keyfile also */ - public function preUnlink( $path ) { - + public function preUnlink($path) + { + // let the trashbin handle this - if ( \OCP\App::isEnabled('files_trashbin') ) { - return true; + if (\OCP\App::isEnabled('files_trashbin')) { + return true; } - + // Disable encryption proxy to prevent recursive calls - $proxyStatus = \OC_FileProxy::$enabled; - \OC_FileProxy::$enabled = false; - - $view = new \OC_FilesystemView( '/' ); + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; + + $view = new \OC_FilesystemView('/'); $userId = \OCP\USER::getUser(); - $util = new Util( $view, $userId ); + $util = new Util($view, $userId); // Format path to be relative to user files dir - $relPath = $util->stripUserFilesPath( $path ); + $relPath = $util->stripUserFilesPath($path); - list( $owner, $ownerPath ) = $util->getUidAndFilename( $relPath ); + list($owner, $ownerPath) = $util->getUidAndFilename($relPath); // Delete keyfile & shareKey so it isn't orphaned if ( - ! ( - Keymanager::deleteFileKey( $view, $owner, $ownerPath ) - && Keymanager::delAllShareKeys( $view, $owner, $ownerPath ) + !( + Keymanager::deleteFileKey($view, $owner, $ownerPath) + && Keymanager::delAllShareKeys($view, $owner, $ownerPath) ) ) { - - \OC_Log::write( 'Encryption library', 'Keyfile or shareKey could not be deleted for file "'.$ownerPath.'"', \OC_Log::ERROR ); - + + \OC_Log::write('Encryption library', 'Keyfile or shareKey could not be deleted for file "' . $ownerPath . '"', \OC_Log::ERROR); + } - + \OC_FileProxy::$enabled = $proxyStatus; - + // If we don't return true then file delete will fail; better // to leave orphaned keyfiles than to disallow file deletion return true; - + } /** - * @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 postWrite( $path ) - { - $this->handleFile($path); + * @brief When a file is renamed, rename its keyfile also + * @param $path + * @return bool Result of rename() + * @note This is pre rather than post because using post didn't work + */ + public function postWrite($path) + { + $this->handleFile($path); - return true; - } + return true; + } - public function postTouch( $path ) - { - $this->handleFile($path); + /** + * @param $path + * @return bool + */ + public function postTouch($path) + { + $this->handleFile($path); - return true; - } + return true; + } - public function postFopen( $path, &$result ){ + /** + * @param $path + * @param $result + * @return resource + */ + public function postFopen($path, &$result) + { + + if (!$result) { - if ( !$result ) { - return $result; - + } - // Reformat path for use with OC_FSV - $path_split = explode( '/', $path ); - $path_f = implode( '/', array_slice( $path_split, 3 ) ); + // Reformat path for use with OC_FSV + $path_split = explode('/', $path); + $path_f = implode('/', array_slice($path_split, 3)); - // FIXME: handling for /userId/cache used by webdav for chunking. The cache chunks are NOT encrypted - if($path_split[2] == 'cache') { - return $result; - } + // FIXME: handling for /userId/cache used by webdav for chunking. The cache chunks are NOT encrypted + if ($path_split[2] == 'cache') { + return $result; + } // Disable encryption proxy to prevent recursive calls - $proxyStatus = \OC_FileProxy::$enabled; - \OC_FileProxy::$enabled = false; + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; + + $meta = stream_get_meta_data($result); + + $view = new \OC_FilesystemView(''); + + $util = new Util($view, \OCP\USER::getUser()); - $meta = stream_get_meta_data( $result ); - - $view = new \OC_FilesystemView( '' ); - - $util = new Util( $view, \OCP\USER::getUser()); - // If file is already encrypted, decrypt using crypto protocol - if ( - Crypt::mode() == 'server' - && $util->isEncryptedPath( $path ) + if ( + Crypt::mode() == 'server' + && $util->isEncryptedPath($path) ) { - + // Close the original encrypted file - fclose( $result ); - + fclose($result); + // Open the file using the crypto stream wrapper // protocol and let it do the decryption work instead - $result = fopen( 'crypt://' . $path_f, $meta['mode'] ); - - - } elseif ( - self::shouldEncrypt( $path ) - and $meta ['mode'] != 'r' - and $meta['mode'] != 'rb' - ) { - // If the file is not yet encrypted, but should be - // encrypted when it's saved (it's not read only) - - // NOTE: this is the case for new files saved via WebDAV - -// if ( -// $view->file_exists( $path ) -// and $view->filesize( $path ) > 0 -// ) { -// $x = $view->file_get_contents( $path ); -// -// $tmp = tmpfile(); - -// // Make a temporary copy of the original file -// \OCP\Files::streamCopy( $result, $tmp ); -// -// // Close the original stream, we'll return another one -// fclose( $result ); -// -// $view->file_put_contents( $path_f, $tmp ); -// -// fclose( $tmp ); - -// } + $result = fopen('crypt://' . $path_f, $meta['mode']); - $result = fopen( 'crypt://'.$path_f, $meta['mode'] ); - + + } elseif ( + self::shouldEncrypt($path) + and $meta ['mode'] != 'r' + and $meta['mode'] != 'rb' + ) { + $result = fopen('crypt://' . $path_f, $meta['mode']); } - + // Re-enable the proxy \OC_FileProxy::$enabled = $proxyStatus; - + return $result; - + } - public function postGetMimeType( $path, $mime ) { + /** + * @param $path + * @param $mime + * @return string + */ + public function postGetMimeType($path, $mime) + { + + if (Crypt::isCatfileContent($path)) { + + $mime = \OCP\Files::getMimeType('crypt://' . $path, 'w'); - if ( Crypt::isCatfileContent( $path ) ) { - - $mime = \OCP\Files::getMimeType( 'crypt://' . $path, 'w' ); - } - + return $mime; - + } - public function postGetFileInfo( $path, $data ) { + /** + * @param $path + * @param $data + * @return array + */ + public function postGetFileInfo($path, $data) + { - // if path is a folder do nothing - if(is_array($data) && array_key_exists('size', $data)) { + // if path is a folder do nothing + if (is_array($data) && array_key_exists('size', $data)) { - // Disable encryption proxy to prevent recursive calls - $proxyStatus = \OC_FileProxy::$enabled; - \OC_FileProxy::$enabled = false; + // Disable encryption proxy to prevent recursive calls + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; - // get file size - $data['size'] = self::postFileSize($path, $data['size']); + // get file size + $data['size'] = self::postFileSize($path, $data['size']); - // Re-enable the proxy - \OC_FileProxy::$enabled = $proxyStatus; - } + // Re-enable the proxy + \OC_FileProxy::$enabled = $proxyStatus; + } - return $data; - } + return $data; + } - public function postStat($path, $data) - { - // check if file is encrypted - if (Crypt::isCatfileContent($path)) { + /** + * @param $path + * @param $data + * @return mixed + */ + public function postStat($path, $data) + { + // check if file is encrypted + if (Crypt::isCatfileContent($path)) { - // get file info from cache - $cached = \OC\Files\Filesystem::getFileInfo($path, ''); + // get file info from cache + $cached = \OC\Files\Filesystem::getFileInfo($path, ''); - // set the real file size - $data['size'] = $cached['unencrypted_size']; - } + // set the real file size + $data['size'] = $cached['unencrypted_size']; + } - return $data; - } + return $data; + } - public function postFileSize($path, $size) - { + /** + * @param $path + * @param $size + * @return bool + */ + public function postFileSize($path, $size) + { - $view = new \OC_FilesystemView('/'); + $view = new \OC_FilesystemView('/'); - // if path is a folder do nothing - if ($view->is_dir($path)) { - return $size; - } + // if path is a folder do nothing + if ($view->is_dir($path)) { + return $size; + } - // Reformat path for use with OC_FSV - $path_split = explode('/', $path); - $path_f = implode('/', array_slice($path_split, 3)); + // Reformat path for use with OC_FSV + $path_split = explode('/', $path); + $path_f = implode('/', array_slice($path_split, 3)); - // if path is empty we cannot resolve anything - if(empty($path_f)) { - return $size; - } + // if path is empty we cannot resolve anything + if (empty($path_f)) { + return $size; + } - // get file info from database/cache - $fileInfo = \OC\Files\Filesystem::getFileInfo($path_f); + // get file info from database/cache + $fileInfo = \OC\Files\Filesystem::getFileInfo($path_f); - // if file is encrypted return real file size - if (is_array($fileInfo) && $fileInfo['encrypted'] === true) { - $size = $fileInfo['unencrypted_size']; - } else { - // self healing if file was removed from file cache - if(is_array($fileInfo)) { - $userId = \OCP\User::getUser(); - $util = new Util( $view, $userId ); - $fixSize = $util->getFileSize($path); - if($fixSize > 0) { - $size = $fixSize; + // if file is encrypted return real file size + if (is_array($fileInfo) && $fileInfo['encrypted'] === true) { + $size = $fileInfo['unencrypted_size']; + } else { + // self healing if file was removed from file cache + if (is_array($fileInfo)) { + $userId = \OCP\User::getUser(); + $util = new Util($view, $userId); + $fixSize = $util->getFileSize($path); + if ($fixSize > 0) { + $size = $fixSize; - $fileInfo['encrypted'] = true; - $fileInfo['unencrypted_size'] = $size; + $fileInfo['encrypted'] = true; + $fileInfo['unencrypted_size'] = $size; - // put file info - $view->putFileInfo( $path_f, $fileInfo ); - } - } - } - return $size; - } + // put file info + $view->putFileInfo($path_f, $fileInfo); + } + } + } + return $size; + } - public function handleFile($path) { + /** + * @param $path + */ + public function handleFile($path) + { - // Disable encryption proxy to prevent recursive calls - $proxyStatus = \OC_FileProxy::$enabled; - \OC_FileProxy::$enabled = false; + // Disable encryption proxy to prevent recursive calls + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; - $view = new \OC_FilesystemView('/'); - $session = new Session($view); - $userId = \OCP\User::getUser(); - $util = new Util( $view, $userId ); + $view = new \OC_FilesystemView('/'); + $session = new Session($view); + $userId = \OCP\User::getUser(); + $util = new Util($view, $userId); - // Reformat path for use with OC_FSV - $path_split = explode( '/', $path ); - $path_f = implode( '/', array_slice( $path_split, 3 ) ); + // Reformat path for use with OC_FSV + $path_split = explode('/', $path); + $path_f = implode('/', array_slice($path_split, 3)); - // only if file is on 'files' folder fix file size and sharing - if($path_split[2] == 'files' && $util->fixFileSize($path)) { + // only if file is on 'files' folder fix file size and sharing + if ($path_split[2] == 'files' && $util->fixFileSize($path)) { - // get sharing app state - $sharingEnabled = \OCP\Share::isEnabled(); + // get sharing app state + $sharingEnabled = \OCP\Share::isEnabled(); - // get users - $usersSharing = $util->getSharingUsersArray($sharingEnabled, $path_f); + // get users + $usersSharing = $util->getSharingUsersArray($sharingEnabled, $path_f); - // update sharing-keys - $util->setSharedFileKeyfiles($session, $usersSharing, $path_f); - } + // update sharing-keys + $util->setSharedFileKeyfiles($session, $usersSharing, $path_f); + } - \OC_FileProxy::$enabled = $proxyStatus; - } - } + \OC_FileProxy::$enabled = $proxyStatus; + } +} diff --git a/apps/files_encryption/lib/session.php b/apps/files_encryption/lib/session.php index 8d604dc721..8425cedd99 100644 --- a/apps/files_encryption/lib/session.php +++ b/apps/files_encryption/lib/session.php @@ -26,73 +26,75 @@ namespace OCA\Encryption; * Class for handling encryption related session data */ -class Session { +class Session +{ private $view; - + /** * @brief if session is started, check if ownCloud key pair is set up, if not create it - * - * The ownCloud key pair is used to allow public link sharing even if encryption is enabled + * @param \OC_FilesystemView $view + * + * @note The ownCloud key pair is used to allow public link sharing even if encryption is enabled */ - public function __construct( $view ) { - + public function __construct($view) + { + $this->view = $view; + if (!$this->view->is_dir('owncloud_private_key')) { + + $this->view->mkdir('owncloud_private_key'); - if ( ! $this->view->is_dir( 'owncloud_private_key' ) ) { - - $this->view->mkdir( 'owncloud_private_key' ); - } $publicShareKeyId = \OC_Appconfig::getValue('files_encryption', 'publicShareKeyId'); if ($publicShareKeyId === null) { - $publicShareKeyId = 'pubShare_'.substr(md5(time()),0,8); + $publicShareKeyId = 'pubShare_' . substr(md5(time()), 0, 8); \OC_Appconfig::setValue('files_encryption', 'publicShareKeyId', $publicShareKeyId); } - - if ( - ! $this->view->file_exists( "/public-keys/".$publicShareKeyId.".public.key" ) - || ! $this->view->file_exists( "/owncloud_private_key/".$publicShareKeyId.".private.key" ) + + if ( + !$this->view->file_exists("/public-keys/" . $publicShareKeyId . ".public.key") + || !$this->view->file_exists("/owncloud_private_key/" . $publicShareKeyId . ".private.key") ) { - - $keypair = Crypt::createKeypair(); - // Disable encryption proxy to prevent recursive calls - $proxyStatus = \OC_FileProxy::$enabled; - \OC_FileProxy::$enabled = false; + $keypair = Crypt::createKeypair(); + + // Disable encryption proxy to prevent recursive calls + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; + + // Save public key + + if (!$view->is_dir('/public-keys')) { + $view->mkdir('/public-keys'); + } + + $this->view->file_put_contents('/public-keys/' . $publicShareKeyId . '.public.key', $keypair['publicKey']); + + // Encrypt private key empthy passphrase + $encryptedPrivateKey = Crypt::symmetricEncryptFileContent($keypair['privateKey'], ''); + + // Save private key + $this->view->file_put_contents('/owncloud_private_key/' . $publicShareKeyId . '.private.key', $encryptedPrivateKey); - // Save public key - - if (!$view->is_dir('/public-keys')) { - $view->mkdir('/public-keys'); - } - - $this->view->file_put_contents( '/public-keys/'.$publicShareKeyId.'.public.key', $keypair['publicKey'] ); - - // Encrypt private key empthy passphrase - $encryptedPrivateKey = Crypt::symmetricEncryptFileContent( $keypair['privateKey'], '' ); - - // Save private key - $this->view->file_put_contents( '/owncloud_private_key/'.$publicShareKeyId.'.private.key', $encryptedPrivateKey ); - \OC_FileProxy::$enabled = $proxyStatus; - + } - if(\OCP\USER::getUser() === false) { - // Disable encryption proxy to prevent recursive calls - $proxyStatus = \OC_FileProxy::$enabled; - \OC_FileProxy::$enabled = false; + if (\OCP\USER::getUser() === false) { + // Disable encryption proxy to prevent recursive calls + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; - $encryptedKey = $this->view->file_get_contents( '/owncloud_private_key/'.$publicShareKeyId.'.private.key' ); - $privateKey = Crypt::symmetricDecryptFileContent( $encryptedKey, '' ); - $this->setPrivateKey($privateKey); + $encryptedKey = $this->view->file_get_contents('/owncloud_private_key/' . $publicShareKeyId . '.private.key'); + $privateKey = Crypt::symmetricDecryptFileContent($encryptedKey, ''); + $this->setPrivateKey($privateKey); - \OC_FileProxy::$enabled = $proxyStatus; - } + \OC_FileProxy::$enabled = $proxyStatus; + } } /** @@ -100,71 +102,72 @@ class Session { * @param string $privateKey * @return bool */ - public function setPrivateKey( $privateKey ) { - + public function setPrivateKey($privateKey) + { + $_SESSION['privateKey'] = $privateKey; - + return true; - + } - + /** * @brief Gets user private key from session * @returns string $privateKey The user's plaintext private key * */ - public function getPrivateKey() { - - if ( - isset( $_SESSION['privateKey'] ) - && !empty( $_SESSION['privateKey'] ) + public function getPrivateKey() + { + + if ( + isset($_SESSION['privateKey']) + && !empty($_SESSION['privateKey']) ) { - + return $_SESSION['privateKey']; - + } else { - + return false; - + } - + } - + /** * @brief Sets user legacy key to session + * @param $legacyKey * @return bool - * */ - public function setLegacyKey( $legacyKey ) { - - if ( $_SESSION['legacyKey'] = $legacyKey ) { - - return true; - - } - + public function setLegacyKey($legacyKey) + { + + $_SESSION['legacyKey'] = $legacyKey; + + return true; } - + /** * @brief Gets user legacy key from session * @returns string $legacyKey The user's plaintext legacy key * */ - public function getLegacyKey() { - - if ( - isset( $_SESSION['legacyKey'] ) - && !empty( $_SESSION['legacyKey'] ) + public function getLegacyKey() + { + + if ( + isset($_SESSION['legacyKey']) + && !empty($_SESSION['legacyKey']) ) { - + return $_SESSION['legacyKey']; - + } else { - + return false; - + } - + } } \ No newline at end of file diff --git a/apps/files_encryption/lib/stream.php b/apps/files_encryption/lib/stream.php index ab96783508..31546a2cc5 100644 --- a/apps/files_encryption/lib/stream.php +++ b/apps/files_encryption/lib/stream.php @@ -3,7 +3,7 @@ * ownCloud * * @author Robin Appelman - * @copyright 2012 Sam Tuke , 2011 Robin Appelman + * @copyright 2012 Sam Tuke , 2011 Robin Appelman * * * This library is free software; you can redistribute it and/or @@ -32,30 +32,31 @@ namespace OCA\Encryption; /** * @brief Provides 'crypt://' stream wrapper protocol. - * @note We use a stream wrapper because it is the most secure way to handle + * @note We use a stream wrapper because it is the most secure way to handle * decrypted content transfers. There is no safe way to decrypt the entire file * somewhere on the server, so we have to encrypt and decrypt blocks on the fly. * @note Paths used with this protocol MUST BE RELATIVE. Use URLs like: - * crypt://filename, or crypt://subdirectory/filename, NOT - * crypt:///home/user/owncloud/data. Otherwise keyfiles will be put in - * [owncloud]/data/user/files_encryption/keyfiles/home/user/owncloud/data and + * crypt://filename, or crypt://subdirectory/filename, NOT + * crypt:///home/user/owncloud/data. Otherwise keyfiles will be put in + * [owncloud]/data/user/files_encryption/keyfiles/home/user/owncloud/data and * will not be accessible to other methods. - * @note Data read and written must always be 8192 bytes long, as this is the - * buffer size used internally by PHP. The encryption process makes the input - * data longer, and input is chunked into smaller pieces in order to result in + * @note Data read and written must always be 8192 bytes long, as this is the + * buffer size used internally by PHP. The encryption process makes the input + * data longer, and input is chunked into smaller pieces in order to result in * a 8192 encrypted block size. - * @note When files are deleted via webdav, or when they are updated and the - * previous version deleted, this is handled by OC\Files\View, and thus the + * @note When files are deleted via webdav, or when they are updated and the + * previous version deleted, this is handled by OC\Files\View, and thus the * encryption proxies are used and keyfiles deleted. */ -class Stream { +class Stream +{ public static $sourceStreams = array(); + private $plainKey; + private $encKeyfiles; - // TODO: make all below properties private again once unit testing is - // configured correctly - public $rawPath; // The raw path relative to the data dir - public $relPath; // rel path to users file dir + private $rawPath; // The raw path relative to the data dir + private $relPath; // rel path to users file dir private $userId; private $handle; // Resource returned by fopen private $path; @@ -63,226 +64,238 @@ class Stream { private $meta = array(); // Header / meta for source stream private $count; private $writeCache; - public $size; - public $unencryptedSize; + private $size; + private $unencryptedSize; private $publicKey; private $keyfile; private $encKeyfile; private static $view; // a fsview object set to user dir private $rootView; // a fsview object set to '/' - public function stream_open( $path, $mode, $options, &$opened_path ) { + /** + * @param $path + * @param $mode + * @param $options + * @param $opened_path + * @return bool + */ + public function stream_open($path, $mode, $options, &$opened_path) + { - if ( ! isset( $this->rootView ) ) { - $this->rootView = new \OC_FilesystemView( '/' ); + if (!isset($this->rootView)) { + $this->rootView = new \OC_FilesystemView('/'); } - $util = new Util( $this->rootView, \OCP\USER::getUser()); + $util = new Util($this->rootView, \OCP\USER::getUser()); - $this->userId = $util->getUserId(); + $this->userId = $util->getUserId(); + + // Strip identifier text from path, this gives us the path relative to data//files + $this->relPath = \OC\Files\Filesystem::normalizePath(str_replace('crypt://', '', $path)); - // Strip identifier text from path, this gives us the path relative to data//files - $this->relPath = \OC\Files\Filesystem::normalizePath(str_replace( 'crypt://', '', $path )); - // rawPath is relative to the data directory $this->rawPath = $util->getUserFilesDir() . $this->relPath; - + if ( - dirname( $this->rawPath ) == 'streams' - and isset( self::$sourceStreams[basename( $this->rawPath )] ) + dirname($this->rawPath) == 'streams' + and isset(self::$sourceStreams[basename($this->rawPath)]) ) { - + // Is this just for unit testing purposes? - $this->handle = self::$sourceStreams[basename( $this->rawPath )]['stream']; + $this->handle = self::$sourceStreams[basename($this->rawPath)]['stream']; - $this->path = self::$sourceStreams[basename( $this->rawPath )]['path']; + $this->path = self::$sourceStreams[basename($this->rawPath)]['path']; - $this->size = self::$sourceStreams[basename( $this->rawPath )]['size']; + $this->size = self::$sourceStreams[basename($this->rawPath)]['size']; } else { - // Disable fileproxies so we can get the file size and open the source file without recursive encryption - $proxyStatus = \OC_FileProxy::$enabled; - \OC_FileProxy::$enabled = false; + // Disable fileproxies so we can get the file size and open the source file without recursive encryption + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; - if ( - $mode == 'w' - or $mode == 'w+' - or $mode == 'wb' - or $mode == 'wb+' + if ( + $mode == 'w' + or $mode == 'w+' + or $mode == 'wb' + or $mode == 'wb+' ) { // We're writing a new file so start write counter with 0 bytes $this->size = 0; - $this->unencryptedSize = 0; + $this->unencryptedSize = 0; } else { - - $this->size = $this->rootView->filesize( $this->rawPath, $mode ); - - //$this->size = filesize( $this->rawPath ); - + + $this->size = $this->rootView->filesize($this->rawPath, $mode); + } - //$this->handle = fopen( $this->rawPath, $mode ); - - $this->handle = $this->rootView->fopen( $this->rawPath, $mode ); - + $this->handle = $this->rootView->fopen($this->rawPath, $mode); + \OC_FileProxy::$enabled = $proxyStatus; - if ( ! is_resource( $this->handle ) ) { + if (!is_resource($this->handle)) { - \OCP\Util::writeLog( 'files_encryption', 'failed to open file "' . $this->rawPath . '"', \OCP\Util::ERROR ); + \OCP\Util::writeLog('files_encryption', 'failed to open file "' . $this->rawPath . '"', \OCP\Util::ERROR); } else { - - $this->meta = stream_get_meta_data( $this->handle ); - + + $this->meta = stream_get_meta_data($this->handle); + } } - return is_resource( $this->handle ); + return is_resource($this->handle); } - - public function stream_seek( $offset, $whence = SEEK_SET ) { - + + /** + * @param $offset + * @param int $whence + */ + public function stream_seek($offset, $whence = SEEK_SET) + { + $this->flush(); - - fseek( $this->handle, $offset, $whence ); - + + fseek($this->handle, $offset, $whence); + } - - public function stream_tell() { + + /** + * @return int + */ + public function stream_tell() + { return ftell($this->handle); } - - public function stream_read( $count ) { - + + /** + * @param $count + * @return bool|string + * @throws \Exception + */ + public function stream_read($count) + { + $this->writeCache = ''; - if ( $count != 8192 ) { - + if ($count != 8192) { + // $count will always be 8192 https://bugs.php.net/bug.php?id=21641 // This makes this function a lot simpler, but will break this class if the above 'bug' gets 'fixed' - \OCP\Util::writeLog( 'files_encryption', 'PHP "bug" 21641 no longer holds, decryption system requires refactoring', \OCP\Util::FATAL ); + \OCP\Util::writeLog('files_encryption', 'PHP "bug" 21641 no longer holds, decryption system requires refactoring', \OCP\Util::FATAL); die(); } -// $pos = ftell( $this->handle ); -// // Get the data from the file handle - $data = fread( $this->handle, 8192 ); - - $result = ''; - - if ( strlen( $data ) ) { - - if ( ! $this->getKey() ) { - - // Error! We don't have a key to decrypt the file with - throw new \Exception( 'Encryption key not found for "' . $this->rawPath . '" during attempted read via stream' ); - - } - - // Decrypt data - $result = Crypt::symmetricDecryptFileContent( $data, $this->plainKey ); - - } + $data = fread($this->handle, 8192); -// $length = $this->size - $pos; -// -// if ( $length < 8192 ) { -// -// $result = substr( $result, 0, $length ); -// -// } + $result = ''; + + if (strlen($data)) { + + if (!$this->getKey()) { + + // Error! We don't have a key to decrypt the file with + throw new \Exception('Encryption key not found for "' . $this->rawPath . '" during attempted read via stream'); + + } + + // Decrypt data + $result = Crypt::symmetricDecryptFileContent($data, $this->plainKey); + + } return $result; } - + /** * @brief Encrypt and pad data ready for writing to disk * @param string $plainData data to be encrypted * @param string $key key to use for encryption - * @return encrypted data on success, false on failure + * @return string encrypted data on success, false on failure */ - public function preWriteEncrypt( $plainData, $key ) { - + public function preWriteEncrypt($plainData, $key) + { + // Encrypt data to 'catfile', which includes IV - if ( $encrypted = Crypt::symmetricEncryptFileContent( $plainData, $key ) ) { - - return $encrypted; - + if ($encrypted = Crypt::symmetricEncryptFileContent($plainData, $key)) { + + return $encrypted; + } else { - + return false; - + } - + } - + /** * @brief Fetch the plain encryption key for the file and set it as plainKey property - * @param bool $generate if true, a new key will be generated if none can be found + * @internal param bool $generate if true, a new key will be generated if none can be found * @return bool true on key found and set, false on key not found and new key generated and set */ - public function getKey() { - + public function getKey() + { + // Check if key is already set - if ( isset( $this->plainKey ) && isset( $this->encKeyfile ) ) { - + if (isset($this->plainKey) && isset($this->encKeyfile)) { + return true; - + } - + // Fetch and decrypt keyfile - // Fetch existing keyfile - $this->encKeyfile = Keymanager::getFileKey( $this->rootView, $this->userId, $this->relPath ); + // Fetch existing keyfile + $this->encKeyfile = Keymanager::getFileKey($this->rootView, $this->userId, $this->relPath); // If a keyfile already exists - if ( $this->encKeyfile ) { + if ($this->encKeyfile) { $this->setUserProperty(); - - $session = new Session( $this->rootView ); - - $privateKey = $session->getPrivateKey( $this->userId ); - - $shareKey = Keymanager::getShareKey( $this->rootView, $this->userId, $this->relPath ); - - $this->plainKey = Crypt::multiKeyDecrypt( $this->encKeyfile, $shareKey, $privateKey ); - + + $session = new Session($this->rootView); + + $privateKey = $session->getPrivateKey($this->userId); + + $shareKey = Keymanager::getShareKey($this->rootView, $this->userId, $this->relPath); + + $this->plainKey = Crypt::multiKeyDecrypt($this->encKeyfile, $shareKey, $privateKey); + return true; - + } else { - + return false; - + } - + } - - public function setUserProperty() { - + + public function setUserProperty() + { + // Only get the user again if it isn't already set - if ( empty( $this->userId ) ) { - + if (empty($this->userId)) { + // TODO: Move this user call out of here - it belongs // elsewhere $this->userId = \OCP\User::getUser(); - + } - + // TODO: Add a method for getting the user in case OCP\User:: // getUser() doesn't work (can that scenario ever occur?) - + } - + /** * @brief Handle plain data from the stream, and write it in 8192 byte blocks * @param string $data data to be written to disk @@ -292,89 +305,64 @@ class Stream { * @note Padding is added to each encrypted block to ensure that the resulting block is exactly 8192 bytes. This is removed during stream_read * @note PHP automatically updates the file pointer after writing data to reflect it's length. There is generally no need to update the poitner manually using fseek */ - public function stream_write( $data ) { - + public function stream_write($data) + { + // Disable the file proxies so that encryption is not // automatically attempted when the file is written to disk - // we are handling that separately here and we don't want to // get into an infinite loop - $proxyStatus = \OC_FileProxy::$enabled; + $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; - + // Get the length of the unencrypted data that we are handling - $length = strlen( $data ); - + $length = strlen($data); + // So far this round, no data has been written $written = 0; - + // Find out where we are up to in the writing of data to the // file - $pointer = ftell( $this->handle ); - + $pointer = ftell($this->handle); + // Make sure the userId is set $this->setUserProperty(); - + // Get / generate the keyfile for the file we're handling // If we're writing a new file (not overwriting an existing // one), save the newly generated keyfile - if ( ! $this->getKey() ) { - - $this->plainKey = Crypt::generateKey(); - - } - + if (!$this->getKey()) { + + $this->plainKey = Crypt::generateKey(); + + } + - // If extra data is left over from the last round, make sure it // is integrated into the next 6126 / 8192 block - if ( $this->writeCache ) { - + if ($this->writeCache) { + // Concat writeCache to start of $data $data = $this->writeCache . $data; - + // Clear the write cache, ready for resuse - it has been // flushed and its old contents processed $this->writeCache = ''; } -// -// // Make sure we always start on a block start - if ( 0 != ( $pointer % 8192 ) ) { - // if the current position of - // file indicator is not aligned to a 8192 byte block, fix it - // so that it is -// fseek( $this->handle, - ( $pointer % 8192 ), SEEK_CUR ); -// -// $pointer = ftell( $this->handle ); -// -// $unencryptedNewBlock = fread( $this->handle, 8192 ); -// -// fseek( $this->handle, - ( $currentPos % 8192 ), SEEK_CUR ); -// -// $block = Crypt::symmetricDecryptFileContent( $unencryptedNewBlock, $this->plainKey ); -// -// $x = substr( $block, 0, $currentPos % 8192 ); -// -// $data = $x . $data; -// -// fseek( $this->handle, - ( $currentPos % 8192 ), SEEK_CUR ); -// - } -// $currentPos = ftell( $this->handle ); - -// // While there still remains somed data to be processed & written - while( strlen( $data ) > 0 ) { - -// // Remaining length for this iteration, not of the -// // entire file (may be greater than 8192 bytes) -// $remainingLength = strlen( $data ); -// -// // If data remaining to be written is less than the -// // size of 1 6126 byte block - if ( strlen( $data ) < 6126 ) { - + // While there still remains somed data to be processed & written + while (strlen($data) > 0) { + + // Remaining length for this iteration, not of the + // entire file (may be greater than 8192 bytes) + $remainingLength = strlen( $data ); + + // If data remaining to be written is less than the + // size of 1 6126 byte block + if (strlen($data) < 6126) { + // Set writeCache to contents of $data // The writeCache will be carried over to the // next write round, and added to the start of @@ -387,148 +375,174 @@ class Stream { // Clear $data ready for next round $data = ''; - + } else { - + // Read the chunk from the start of $data - $chunk = substr( $data, 0, 6126 ); - - $encrypted = $this->preWriteEncrypt( $chunk, $this->plainKey ); - + $chunk = substr($data, 0, 6126); + + $encrypted = $this->preWriteEncrypt($chunk, $this->plainKey); + // Write the data chunk to disk. This will be // attended to the last data chunk if the file // being handled totals more than 6126 bytes - fwrite( $this->handle, $encrypted ); - - $writtenLen = strlen( $encrypted ); - //fseek( $this->handle, $writtenLen, SEEK_CUR ); + fwrite($this->handle, $encrypted); + + $writtenLen = strlen($encrypted); // Remove the chunk we just processed from // $data, leaving only unprocessed data in $data // var, for handling on the next round - $data = substr( $data, 6126 ); + $data = substr($data, 6126); } - - } - - $this->size = max( $this->size, $pointer + $length ); - $this->unencryptedSize += $length; - \OC_FileProxy::$enabled = $proxyStatus; + } + + $this->size = max($this->size, $pointer + $length); + $this->unencryptedSize += $length; + + \OC_FileProxy::$enabled = $proxyStatus; return $length; } - public function stream_set_option( $option, $arg1, $arg2 ) { - switch($option) { + /** + * @param $option + * @param $arg1 + * @param $arg2 + */ + public function stream_set_option($option, $arg1, $arg2) + { + switch ($option) { case STREAM_OPTION_BLOCKING: - stream_set_blocking( $this->handle, $arg1 ); + stream_set_blocking($this->handle, $arg1); break; case STREAM_OPTION_READ_TIMEOUT: - stream_set_timeout( $this->handle, $arg1, $arg2 ); + stream_set_timeout($this->handle, $arg1, $arg2); break; case STREAM_OPTION_WRITE_BUFFER: - stream_set_write_buffer( $this->handle, $arg1, $arg2 ); + stream_set_write_buffer($this->handle, $arg1, $arg2); } } - public function stream_stat() { + /** + * @return array + */ + public function stream_stat() + { return fstat($this->handle); } - - public function stream_lock( $mode ) { - flock( $this->handle, $mode ); - } - - public function stream_flush() { - - return fflush( $this->handle ); - // Not a typo: http://php.net/manual/en/function.fflush.php - + + /** + * @param $mode + */ + public function stream_lock($mode) + { + flock($this->handle, $mode); } - public function stream_eof() { + /** + * @return bool + */ + public function stream_flush() + { + + return fflush($this->handle); + // Not a typo: http://php.net/manual/en/function.fflush.php + + } + + /** + * @return bool + */ + public function stream_eof() + { return feof($this->handle); } - private function flush() { - - if ( $this->writeCache ) { - + private function flush() + { + + if ($this->writeCache) { + // Set keyfile property for file in question $this->getKey(); - - $encrypted = $this->preWriteEncrypt( $this->writeCache, $this->plainKey ); - - fwrite( $this->handle, $encrypted ); - + + $encrypted = $this->preWriteEncrypt($this->writeCache, $this->plainKey); + + fwrite($this->handle, $encrypted); + $this->writeCache = ''; - + } - + } - public function stream_close() { + /** + * @return bool + */ + public function stream_close() + { - $this->flush(); - - if ( - $this->meta['mode']!='r' - and $this->meta['mode']!='rb' - and $this->size > 0 + $this->flush(); + + if ( + $this->meta['mode'] != 'r' + and $this->meta['mode'] != 'rb' + and $this->size > 0 ) { - // Disable encryption proxy to prevent recursive calls - $proxyStatus = \OC_FileProxy::$enabled; - \OC_FileProxy::$enabled = false; + // Disable encryption proxy to prevent recursive calls + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; - // Fetch user's public key - $this->publicKey = Keymanager::getPublicKey( $this->rootView, $this->userId ); + // Fetch user's public key + $this->publicKey = Keymanager::getPublicKey($this->rootView, $this->userId); - // Check if OC sharing api is enabled - $sharingEnabled = \OCP\Share::isEnabled(); + // Check if OC sharing api is enabled + $sharingEnabled = \OCP\Share::isEnabled(); - $util = new Util( $this->rootView, $this->userId ); + $util = new Util($this->rootView, $this->userId); - // Get all users sharing the file includes current user - $uniqueUserIds = $util->getSharingUsersArray( $sharingEnabled, $this->relPath, $this->userId); + // Get all users sharing the file includes current user + $uniqueUserIds = $util->getSharingUsersArray($sharingEnabled, $this->relPath, $this->userId); - // Fetch public keys for all sharing users - $publicKeys = Keymanager::getPublicKeys( $this->rootView, $uniqueUserIds ); + // Fetch public keys for all sharing users + $publicKeys = Keymanager::getPublicKeys($this->rootView, $uniqueUserIds); - // Encrypt enc key for all sharing users - $this->encKeyfiles = Crypt::multiKeyEncrypt( $this->plainKey, $publicKeys ); + // Encrypt enc key for all sharing users + $this->encKeyfiles = Crypt::multiKeyEncrypt($this->plainKey, $publicKeys); - $view = new \OC_FilesystemView( '/' ); + $view = new \OC_FilesystemView('/'); - // Save the new encrypted file key - Keymanager::setFileKey( $this->rootView, $this->relPath, $this->userId, $this->encKeyfiles['data'] ); + // Save the new encrypted file key + Keymanager::setFileKey($this->rootView, $this->relPath, $this->userId, $this->encKeyfiles['data']); - // Save the sharekeys - Keymanager::setShareKeys( $view, $this->relPath, $this->encKeyfiles['keys'] ); + // Save the sharekeys + Keymanager::setShareKeys($view, $this->relPath, $this->encKeyfiles['keys']); - // get file info - $fileInfo = $view->getFileInfo($this->rawPath); - if(!is_array($fileInfo)) { - $fileInfo = array(); - } + // get file info + $fileInfo = $view->getFileInfo($this->rawPath); + if (!is_array($fileInfo)) { + $fileInfo = array(); + } - // Re-enable proxy - our work is done - \OC_FileProxy::$enabled = $proxyStatus; + // Re-enable proxy - our work is done + \OC_FileProxy::$enabled = $proxyStatus; - // set encryption data - $fileInfo['encrypted'] = true; - $fileInfo['size'] = $this->size; - $fileInfo['unencrypted_size'] = $this->unencryptedSize; + // set encryption data + $fileInfo['encrypted'] = true; + $fileInfo['size'] = $this->size; + $fileInfo['unencrypted_size'] = $this->unencryptedSize; - // set fileinfo - $view->putFileInfo( $this->rawPath, $fileInfo); + // set fileinfo + $view->putFileInfo($this->rawPath, $fileInfo); } - return fclose( $this->handle ); - + return fclose($this->handle); + } } diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 82f789c520..9ba7b3b3a3 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -3,7 +3,7 @@ * ownCloud * * @author Sam Tuke, Frank Karlitschek - * @copyright 2012 Sam Tuke , + * @copyright 2012 Sam Tuke , * Frank Karlitschek * * This library is free software; you can redistribute it and/or @@ -55,49 +55,49 @@ namespace OCA\Encryption; * unused, likely to become obsolete shortly */ -class Util { - - +class Util +{ + // Web UI: - + //// DONE: files created via web ui are encrypted //// DONE: file created & encrypted via web ui are readable in web ui //// DONE: file created & encrypted via web ui are readable via webdav - - + + // WebDAV: - + //// DONE: new data filled files added via webdav get encrypted //// DONE: new data filled files added via webdav are readable via webdav //// DONE: reading unencrypted files when encryption is enabled works via //// webdav //// DONE: files created & encrypted via web ui are readable via webdav - - + + // Legacy support: - + //// DONE: add method to check if file is encrypted using new system //// DONE: add method to check if file is encrypted using old system //// DONE: add method to fetch legacy key //// DONE: add method to decrypt legacy encrypted data - - + + // Admin UI: - + //// DONE: changing user password also changes encryption passphrase - + //// TODO: add support for optional recovery in case of lost passphrase / keys //// TODO: add admin optional required long passphrase for users //// TODO: implement flag system to allow user to specify encryption by folder, subfolder, etc. - - + + // Integration testing: - + //// TODO: test new encryption with versioning //// DONE: test new encryption with sharing //// TODO: test new encryption with proxies - - + + private $view; // OC_FilesystemView object for filesystem operations private $userId; // ID of the currently logged-in user private $pwd; // User Password @@ -110,228 +110,246 @@ class Util { private $privateKeyPath; // Path to user's private key private $publicShareKeyId; private $recoveryKeyId; - private $isPublic; + private $isPublic; - public function __construct( \OC_FilesystemView $view, $userId, $client = false ) { + /** + * @param \OC_FilesystemView $view + * @param $userId + * @param bool $client + */ + public function __construct(\OC_FilesystemView $view, $userId, $client = false) + { $this->view = $view; $this->userId = $userId; $this->client = $client; - $this->isPublic = false; + $this->isPublic = false; - $this->publicShareKeyId = \OC_Appconfig::getValue('files_encryption', 'publicShareKeyId'); - $this->recoveryKeyId = \OC_Appconfig::getValue('files_encryption', 'recoveryKeyId'); + $this->publicShareKeyId = \OC_Appconfig::getValue('files_encryption', 'publicShareKeyId'); + $this->recoveryKeyId = \OC_Appconfig::getValue('files_encryption', 'recoveryKeyId'); - // if we are anonymous/public - if($this->userId === false) { - $this->userId = $this->publicShareKeyId; + // if we are anonymous/public + if ($this->userId === false) { + $this->userId = $this->publicShareKeyId; - // only handle for files_sharing app - if($GLOBALS['app'] === 'files_sharing') { - $this->userDir = '/' . $GLOBALS['fileOwner']; - $this->fileFolderName = 'files'; - $this->userFilesDir = '/' . $GLOBALS['fileOwner'] . '/' . $this->fileFolderName; // TODO: Does this need to be user configurable? - $this->publicKeyDir = '/' . 'public-keys'; - $this->encryptionDir = '/' . $GLOBALS['fileOwner'] . '/' . 'files_encryption'; - $this->keyfilesPath = $this->encryptionDir . '/' . 'keyfiles'; - $this->shareKeysPath = $this->encryptionDir . '/' . 'share-keys'; - $this->publicKeyPath = $this->publicKeyDir . '/' . $this->userId . '.public.key'; // e.g. data/public-keys/admin.public.key - $this->privateKeyPath = '/owncloud_private_key/' . $this->userId . '.private.key'; // e.g. data/admin/admin.private.key - $this->isPublic = true; - } - - } else { - $this->userDir = '/' . $this->userId; - $this->fileFolderName = 'files'; - $this->userFilesDir = '/' . $this->userId . '/' . $this->fileFolderName; // TODO: Does this need to be user configurable? - $this->publicKeyDir = '/' . 'public-keys'; - $this->encryptionDir = '/' . $this->userId . '/' . 'files_encryption'; - $this->keyfilesPath = $this->encryptionDir . '/' . 'keyfiles'; - $this->shareKeysPath = $this->encryptionDir . '/' . 'share-keys'; - $this->publicKeyPath = $this->publicKeyDir . '/' . $this->userId . '.public.key'; // e.g. data/public-keys/admin.public.key - $this->privateKeyPath = $this->encryptionDir . '/' . $this->userId . '.private.key'; // e.g. data/admin/admin.private.key - } - } - - public function ready() { - - if( - ! $this->view->file_exists( $this->encryptionDir ) - or ! $this->view->file_exists( $this->keyfilesPath ) - or ! $this->view->file_exists( $this->shareKeysPath ) - or ! $this->view->file_exists( $this->publicKeyPath ) - or ! $this->view->file_exists( $this->privateKeyPath ) - ) { - - return false; - - } else { - - return true; - - } - - } - - /** - * @brief Sets up user folders and keys for serverside encryption - * @param $passphrase passphrase to encrypt server-stored private key with - */ - public function setupServerSide( $passphrase = null ) { - - // Set directories to check / create - $setUpDirs = array( - $this->userDir - , $this->userFilesDir - , $this->publicKeyDir - , $this->encryptionDir - , $this->keyfilesPath - , $this->shareKeysPath - ); - - // Check / create all necessary dirs - foreach ( $setUpDirs as $dirPath ) { - - if( !$this->view->file_exists( $dirPath ) ) { - - $this->view->mkdir( $dirPath ); - + // only handle for files_sharing app + if ($GLOBALS['app'] === 'files_sharing') { + $this->userDir = '/' . $GLOBALS['fileOwner']; + $this->fileFolderName = 'files'; + $this->userFilesDir = '/' . $GLOBALS['fileOwner'] . '/' . $this->fileFolderName; // TODO: Does this need to be user configurable? + $this->publicKeyDir = '/' . 'public-keys'; + $this->encryptionDir = '/' . $GLOBALS['fileOwner'] . '/' . 'files_encryption'; + $this->keyfilesPath = $this->encryptionDir . '/' . 'keyfiles'; + $this->shareKeysPath = $this->encryptionDir . '/' . 'share-keys'; + $this->publicKeyPath = $this->publicKeyDir . '/' . $this->userId . '.public.key'; // e.g. data/public-keys/admin.public.key + $this->privateKeyPath = '/owncloud_private_key/' . $this->userId . '.private.key'; // e.g. data/admin/admin.private.key + $this->isPublic = true; } - + + } else { + $this->userDir = '/' . $this->userId; + $this->fileFolderName = 'files'; + $this->userFilesDir = '/' . $this->userId . '/' . $this->fileFolderName; // TODO: Does this need to be user configurable? + $this->publicKeyDir = '/' . 'public-keys'; + $this->encryptionDir = '/' . $this->userId . '/' . 'files_encryption'; + $this->keyfilesPath = $this->encryptionDir . '/' . 'keyfiles'; + $this->shareKeysPath = $this->encryptionDir . '/' . 'share-keys'; + $this->publicKeyPath = $this->publicKeyDir . '/' . $this->userId . '.public.key'; // e.g. data/public-keys/admin.public.key + $this->privateKeyPath = $this->encryptionDir . '/' . $this->userId . '.private.key'; // e.g. data/admin/admin.private.key } - - // Create user keypair - if ( - ! $this->view->file_exists( $this->publicKeyPath ) - or ! $this->view->file_exists( $this->privateKeyPath ) + } + + /** + * @return bool + */ + public function ready() + { + + if ( + !$this->view->file_exists($this->encryptionDir) + or !$this->view->file_exists($this->keyfilesPath) + or !$this->view->file_exists($this->shareKeysPath) + or !$this->view->file_exists($this->publicKeyPath) + or !$this->view->file_exists($this->privateKeyPath) ) { - + + return false; + + } else { + + return true; + + } + + } + + /** + * @brief Sets up user folders and keys for serverside encryption + * @param string $passphrase passphrase to encrypt server-stored private key with + */ + public function setupServerSide($passphrase = null) + { + + // Set directories to check / create + $setUpDirs = array( + $this->userDir + , $this->userFilesDir + , $this->publicKeyDir + , $this->encryptionDir + , $this->keyfilesPath + , $this->shareKeysPath + ); + + // Check / create all necessary dirs + foreach ($setUpDirs as $dirPath) { + + if (!$this->view->file_exists($dirPath)) { + + $this->view->mkdir($dirPath); + + } + + } + + // Create user keypair + if ( + !$this->view->file_exists($this->publicKeyPath) + or !$this->view->file_exists($this->privateKeyPath) + ) { + // Generate keypair $keypair = Crypt::createKeypair(); - + \OC_FileProxy::$enabled = false; - + // Save public key - $this->view->file_put_contents( $this->publicKeyPath, $keypair['publicKey'] ); - + $this->view->file_put_contents($this->publicKeyPath, $keypair['publicKey']); + // Encrypt private key with user pwd as passphrase - $encryptedPrivateKey = Crypt::symmetricEncryptFileContent( $keypair['privateKey'], $passphrase ); - + $encryptedPrivateKey = Crypt::symmetricEncryptFileContent($keypair['privateKey'], $passphrase); + // Save private key - $this->view->file_put_contents( $this->privateKeyPath, $encryptedPrivateKey ); - + $this->view->file_put_contents($this->privateKeyPath, $encryptedPrivateKey); + \OC_FileProxy::$enabled = true; - + } - + // If there's no record for this user's encryption preferences - if ( false === $this->recoveryEnabledForUser() ) { - + if (false === $this->recoveryEnabledForUser()) { + // create database configuration $sql = 'INSERT INTO `*PREFIX*encryption` (`uid`,`mode`,`recovery_enabled`) VALUES (?,?,?)'; - $args = array( $this->userId, 'server-side', 0); - $query = \OCP\DB::prepare( $sql ); - $query->execute( $args ); - + $args = array($this->userId, 'server-side', 0); + $query = \OCP\DB::prepare($sql); + $query->execute($args); + } - + return true; - + } - public function getPublicShareKeyId() { + /** + * @return string + */ + public function getPublicShareKeyId() + { return $this->publicShareKeyId; } - + /** * @brief Check whether pwd recovery is enabled for a given user - * @return 1 = yes, 0 = no, false = no record - * @note If records are not being returned, check for a hidden space + * @return bool 1 = yes, 0 = no, false = no record + * + * @note If records are not being returned, check for a hidden space * at the start of the uid in db */ - public function recoveryEnabledForUser() { - + public function recoveryEnabledForUser() + { + $sql = 'SELECT recovery_enabled FROM `*PREFIX*encryption` WHERE uid = ?'; - - $args = array( $this->userId ); - $query = \OCP\DB::prepare( $sql ); - - $result = $query->execute( $args ); - + $args = array($this->userId); + + $query = \OCP\DB::prepare($sql); + + $result = $query->execute($args); + $recoveryEnabled = array(); - - while( $row = $result->fetchRow() ) { - + + while ($row = $result->fetchRow()) { + $recoveryEnabled[] = $row['recovery_enabled']; - + } - + // If no record is found - if ( empty( $recoveryEnabled ) ) { - + if (empty($recoveryEnabled)) { + return false; - - // If a record is found + + // If a record is found } else { - + return $recoveryEnabled[0]; - + } - + } - + /** * @brief Enable / disable pwd recovery for a given user * @param bool $enabled Whether to enable or disable recovery * @return bool */ - public function setRecoveryForUser( $enabled ) { - + public function setRecoveryForUser($enabled) + { + $recoveryStatus = $this->recoveryEnabledForUser(); - + // If a record for this user already exists, update it - if ( false === $recoveryStatus ) { - + if (false === $recoveryStatus) { + $sql = 'INSERT INTO `*PREFIX*encryption` (`uid`,`mode`,`recovery_enabled`) VALUES (?,?,?)'; - - $args = array( $this->userId, 'server-side', $enabled ); - - // Create a new record instead + + $args = array($this->userId, 'server-side', $enabled); + + // Create a new record instead } else { - + $sql = 'UPDATE *PREFIX*encryption SET recovery_enabled = ? WHERE uid = ?'; - - $args = array( $enabled, $this->userId ); - + + $args = array($enabled, $this->userId); + } - - $query = \OCP\DB::prepare( $sql ); - - if ( $query->execute( $args ) ) { - + + $query = \OCP\DB::prepare($sql); + + if ($query->execute($args)) { + return true; - + } else { - + return false; - + } - + } - + /** * @brief Find all files and their encryption status within a directory * @param string $directory The path of the parent directory to search @@ -339,45 +357,46 @@ class Util { * @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 findEncFiles( $directory ) { - + public function findEncFiles($directory) + { + // Disable proxy - we don't want files to be decrypted before // we handle them \OC_FileProxy::$enabled = false; - - $found = array( 'plain' => array(), 'encrypted' => array(), 'legacy' => array() ); - - if ( - $this->view->is_dir( $directory ) - && $handle = $this->view->opendir( $directory ) + + $found = array('plain' => array(), 'encrypted' => array(), 'legacy' => array()); + + if ( + $this->view->is_dir($directory) + && $handle = $this->view->opendir($directory) ) { - - while ( false !== ( $file = readdir( $handle ) ) ) { - + + while (false !== ($file = readdir($handle))) { + if ( - $file != "." - && $file != ".." + $file != "." + && $file != ".." ) { - - $filePath = $directory . '/' . $this->view->getRelativePath( '/' . $file ); - $relPath = $this->stripUserFilesPath( $filePath ); - + + $filePath = $directory . '/' . $this->view->getRelativePath('/' . $file); + $relPath = $this->stripUserFilesPath($filePath); + // If the path is a directory, search // its contents - if ( $this->view->is_dir( $filePath ) ) { - - $this->findEncFiles( $filePath ); - - // If the path is a file, determine - // its encryption status - } elseif ( $this->view->is_file( $filePath ) ) { - + if ($this->view->is_dir($filePath)) { + + $this->findEncFiles($filePath); + + // If the path is a file, determine + // its encryption status + } elseif ($this->view->is_file($filePath)) { + // Disable proxies again, some- // where they got re-enabled :/ \OC_FileProxy::$enabled = false; - - $data = $this->view->file_get_contents( $filePath ); - + + $data = $this->view->file_get_contents($filePath); + // If the file is encrypted // NOTE: If the userId is // empty or not set, file will @@ -385,128 +404,131 @@ class Util { // NOTE: This is inefficient; // scanning every file like this // will eat server resources :( - if ( - Keymanager::getFileKey( $this->view, $this->userId, $relPath ) - && Crypt::isCatfileContent( $data ) + if ( + Keymanager::getFileKey($this->view, $this->userId, $relPath) + && Crypt::isCatfileContent($data) ) { - - $found['encrypted'][] = array( 'name' => $file, 'path' => $filePath ); - - // If the file uses old - // encryption system - } elseif ( Crypt::isLegacyEncryptedContent( $this->tail( $filePath, 3 ), $relPath ) ) { - - $found['legacy'][] = array( 'name' => $file, 'path' => $filePath ); - - // If the file is not encrypted + + $found['encrypted'][] = array('name' => $file, 'path' => $filePath); + + // If the file uses old + // encryption system + } elseif (Crypt::isLegacyEncryptedContent($this->tail($filePath, 3), $relPath)) { + + $found['legacy'][] = array('name' => $file, 'path' => $filePath); + + // If the file is not encrypted } else { - - $found['plain'][] = array( 'name' => $file, 'path' => $relPath ); - + + $found['plain'][] = array('name' => $file, 'path' => $relPath); + } - + } - + } - + } - + \OC_FileProxy::$enabled = true; - - if ( empty( $found ) ) { - + + if (empty($found)) { + return false; - + } else { - + return $found; - + } - + } - + \OC_FileProxy::$enabled = true; - + return false; } - - /** - * @brief Fetch the last lines of a file efficiently - * @note Safe to use on large files; does not read entire file to memory - * @note Derivative of http://tekkie.flashbit.net/php/tail-functionality-in-php - */ - public function tail( $filename, $numLines ) { - + + /** + * @brief Fetch the last lines of a file efficiently + * @note Safe to use on large files; does not read entire file to memory + * @note Derivative of http://tekkie.flashbit.net/php/tail-functionality-in-php + */ + public function tail($filename, $numLines) + { + \OC_FileProxy::$enabled = false; - + $text = ''; $pos = -1; - $handle = $this->view->fopen( $filename, 'r' ); + $handle = $this->view->fopen($filename, 'r'); + + while ($numLines > 0) { - while ( $numLines > 0 ) { - --$pos; - if( fseek( $handle, $pos, SEEK_END ) !== 0 ) { - - rewind( $handle ); + if (fseek($handle, $pos, SEEK_END) !== 0) { + + rewind($handle); $numLines = 0; - - } elseif ( fgetc( $handle ) === "\n" ) { - + + } elseif (fgetc($handle) === "\n") { + --$numLines; - + } - $block_size = ( -$pos ) % 8192; - if ( $block_size === 0 || $numLines === 0 ) { - - $text = fread( $handle, ( $block_size === 0 ? 8192 : $block_size ) ) . $text; - + $block_size = (-$pos) % 8192; + if ($block_size === 0 || $numLines === 0) { + + $text = fread($handle, ($block_size === 0 ? 8192 : $block_size)) . $text; + } } - fclose( $handle ); - + fclose($handle); + \OC_FileProxy::$enabled = true; - + return $text; } - + /** - * @brief Check if a given path identifies an encrypted file - * @return true / false - */ - public function isEncryptedPath( $path ) { - + * @brief Check if a given path identifies an encrypted file + * @param $path + * @return boolean + */ + public function isEncryptedPath($path) + { + // Disable encryption proxy so data retrieved is in its // original form - $proxyStatus = \OC_FileProxy::$enabled; + $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; - // we only need 24 byte from the last chunk - $data = ''; - $handle = $this->view->fopen( $path, 'r' ); - if(!fseek($handle, -24, SEEK_END)) { - $data = fgets($handle); - } + // we only need 24 byte from the last chunk + $data = ''; + $handle = $this->view->fopen($path, 'r'); + if (!fseek($handle, -24, SEEK_END)) { + $data = fgets($handle); + } - // re-enable proxy + // re-enable proxy \OC_FileProxy::$enabled = $proxyStatus; - - return Crypt::isCatfileContent( $data ); - + + return Crypt::isCatfileContent($data); + } /** - * @brief get the file size of the unencrypted file - * @param $path absolute path - * @return bool - */ + * @brief get the file size of the unencrypted file + * @param string $path absolute path + * @return bool + */ + public function getFileSize($path) + { - public function getFileSize( $path ) { - $result = 0; // Disable encryption proxy to prevent recursive calls @@ -514,8 +536,8 @@ class Util { \OC_FileProxy::$enabled = false; // Reformat path for use with OC_FSV - $pathSplit = explode( '/', $path ); - $pathRelative = implode( '/', array_slice( $pathSplit, 3 ) ); + $pathSplit = explode('/', $path); + $pathRelative = implode('/', array_slice($pathSplit, 3)); if ($pathSplit[2] == 'files' && $this->view->file_exists($path) && $this->isEncryptedPath($path)) { @@ -529,7 +551,7 @@ class Util { // open stream $stream = fopen('crypt://' . $pathRelative, "r"); - if(is_resource($stream)) { + if (is_resource($stream)) { // calculate last chunk position $lastChunckPos = ($lastChunckNr * 8192); @@ -551,36 +573,36 @@ class Util { return $result; } - + /** * @brief fix the file size of the encrypted file * @param $path absolute path * @return true / false if file is encrypted */ + public function fixFileSize($path) + { - public function fixFileSize( $path ) { - $result = false; // Disable encryption proxy to prevent recursive calls $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; - $realSize = $this->getFileSize( $path ); - - if ( $realSize > 0 ) { - - $cached = $this->view->getFileInfo( $path ); + $realSize = $this->getFileSize($path); + + if ($realSize > 0) { + + $cached = $this->view->getFileInfo($path); $cached['encrypted'] = true; // set the size $cached['unencrypted_size'] = $realSize; // put file info - $this->view->putFileInfo( $path, $cached ); + $this->view->putFileInfo($path, $cached); $result = true; - + } \OC_FileProxy::$enabled = $proxyStatus; @@ -592,70 +614,82 @@ class Util { * @brief Format a path to be relative to the /user/files/ directory * @note e.g. turns '/admin/files/test.txt' into 'test.txt' */ - public function stripUserFilesPath( $path ) { - - $trimmed = ltrim( $path, '/' ); - $split = explode( '/', $trimmed ); - $sliced = array_slice( $split, 2 ); - $relPath = implode( '/', $sliced ); - + public function stripUserFilesPath($path) + { + + $trimmed = ltrim($path, '/'); + $split = explode('/', $trimmed); + $sliced = array_slice($split, 2); + $relPath = implode('/', $sliced); + return $relPath; - + } - + /** * @brief Format a path to be relative to the /user directory * @note e.g. turns '/admin/files/test.txt' into 'files/test.txt' */ - public function stripFilesPath( $path ) { - - $trimmed = ltrim( $path, '/' ); - $split = explode( '/', $trimmed ); - $sliced = array_slice( $split, 1 ); - $relPath = implode( '/', $sliced ); - + public function stripFilesPath($path) + { + + $trimmed = ltrim($path, '/'); + $split = explode('/', $trimmed); + $sliced = array_slice($split, 1); + $relPath = implode('/', $sliced); + return $relPath; - + } - + /** * @brief Format a shared path to be relative to the /user/files/ directory * @note Expects a path like /uid/files/Shared/filepath */ - public function stripSharedFilePath( $path ) { - - $trimmed = ltrim( $path, '/' ); - $split = explode( '/', $trimmed ); - $sliced = array_slice( $split, 3 ); - $relPath = implode( '/', $sliced ); - + public function stripSharedFilePath($path) + { + + $trimmed = ltrim($path, '/'); + $split = explode('/', $trimmed); + $sliced = array_slice($split, 3); + $relPath = implode('/', $sliced); + return $relPath; - + } - - public function isSharedPath( $path ) { - - $trimmed = ltrim( $path, '/' ); - $split = explode( '/', $trimmed ); - - if ( $split[2] == "Shared" ) { - + + /** + * @param $path + * @return bool + */ + public function isSharedPath($path) + { + + $trimmed = ltrim($path, '/'); + $split = explode('/', $trimmed); + + if ($split[2] == "Shared") { + return true; - + } else { - + return false; - + } - + } - + /** * @brief Encrypt all files in a directory * @param string $dirPath the directory whose files will be encrypted + * @param null $legacyPassphrase + * @param null $newPassphrase + * @return bool * @note Encryption is recursive */ - public function encryptAll($dirPath, $legacyPassphrase = null, $newPassphrase = null) { + public function encryptAll($dirPath, $legacyPassphrase = null, $newPassphrase = null) + { if ($found = $this->findEncFiles($dirPath)) { @@ -762,174 +796,180 @@ class Util { * @param string $pathName Name of the directory to return the path of * @return string path */ - public function getPath( $pathName ) { - - switch ( $pathName ) { - + public function getPath($pathName) + { + + switch ($pathName) { + case 'publicKeyDir': - + return $this->publicKeyDir; - + break; - + case 'encryptionDir': - + return $this->encryptionDir; - + break; - + case 'keyfilesPath': - + return $this->keyfilesPath; - + break; - + case 'publicKeyPath': - + return $this->publicKeyPath; - + break; - + case 'privateKeyPath': - + return $this->privateKeyPath; - + break; - + } - + } - + /** * @brief get path of a file. - * @param $fileId id of the file - * @return path of the file + * @param int $fileId id of the file + * @return string path of the file */ - public static function fileIdToPath( $fileId ) { - - $query = \OC_DB::prepare( 'SELECT `path`' - .' FROM `*PREFIX*filecache`' - .' WHERE `fileid` = ?' ); - - $result = $query->execute( array( $fileId ) ); - + public static function fileIdToPath($fileId) + { + + $query = \OC_DB::prepare('SELECT `path`' + . ' FROM `*PREFIX*filecache`' + . ' WHERE `fileid` = ?'); + + $result = $query->execute(array($fileId)); + $row = $result->fetchRow(); - - return substr( $row['path'], 5 ); - + + return substr($row['path'], 5); + } - + /** * @brief Filter an array of UIDs to return only ones ready for sharing * @param array $unfilteredUsers users to be checked for sharing readiness * @return multi-dimensional array. keys: ready, unready */ - public function filterShareReadyUsers( $unfilteredUsers ) { - + public function filterShareReadyUsers($unfilteredUsers) + { + // This array will collect the filtered IDs $readyIds = $unreadyIds = array(); - + // Loop through users and create array of UIDs that need new keyfiles - foreach ( $unfilteredUsers as $user ) { - - $util = new Util( $this->view, $user ); - + foreach ($unfilteredUsers as $user) { + + $util = new Util($this->view, $user); + // Check that the user is encryption capable, or is the // public system user 'ownCloud' (for public shares) - if ( + if ( $user == $this->publicShareKeyId or $user == $this->recoveryKeyId - or $util->ready() + or $util->ready() ) { - + // Construct array of ready UIDs for Keymanager{} $readyIds[] = $user; - + } else { - + // Construct array of unready UIDs for Keymanager{} $unreadyIds[] = $user; - + // Log warning; we can't do necessary setup here // because we don't have the user passphrase - \OC_Log::write( 'Encryption library', '"'.$user.'" is not setup for encryption', \OC_Log::WARN ); - + \OC_Log::write('Encryption library', '"' . $user . '" is not setup for encryption', \OC_Log::WARN); + } - + } - - return array ( + + return array( 'ready' => $readyIds - , 'unready' => $unreadyIds + , 'unready' => $unreadyIds ); - + } - + /** * @brief Decrypt a keyfile without knowing how it was encrypted * @param string $filePath * @param string $fileOwner * @param string $privateKey - * @note Checks whether file was encrypted with openssl_seal or + * @note Checks whether file was encrypted with openssl_seal or * openssl_encrypt, and decrypts accrdingly - * @note This was used when 2 types of encryption for keyfiles was used, + * @note This was used when 2 types of encryption for keyfiles was used, * but now we've switched to exclusively using openssl_seal() */ - public function decryptUnknownKeyfile( $filePath, $fileOwner, $privateKey ) { + public function decryptUnknownKeyfile($filePath, $fileOwner, $privateKey) + { // Get the encrypted keyfile // NOTE: the keyfile format depends on how it was encrypted! At // this stage we don't know how it was encrypted - $encKeyfile = Keymanager::getFileKey( $this->view, $this->userId, $filePath ); - + $encKeyfile = Keymanager::getFileKey($this->view, $this->userId, $filePath); + // We need to decrypt the keyfile // Has the file been shared yet? - if ( + if ( $this->userId == $fileOwner - && ! Keymanager::getShareKey( $this->view, $this->userId, $filePath ) // NOTE: we can't use isShared() here because it's a post share hook so it always returns true + && !Keymanager::getShareKey($this->view, $this->userId, $filePath) // NOTE: we can't use isShared() here because it's a post share hook so it always returns true ) { - + // The file has no shareKey, and its keyfile must be // decrypted conventionally - $plainKeyfile = Crypt::keyDecrypt( $encKeyfile, $privateKey ); - - + $plainKeyfile = Crypt::keyDecrypt($encKeyfile, $privateKey); + + } else { - + // The file has a shareKey and must use it for decryption - $shareKey = Keymanager::getShareKey( $this->view, $this->userId, $filePath ); - - $plainKeyfile = Crypt::multiKeyDecrypt( $encKeyfile, $shareKey, $privateKey ); - + $shareKey = Keymanager::getShareKey($this->view, $this->userId, $filePath); + + $plainKeyfile = Crypt::multiKeyDecrypt($encKeyfile, $shareKey, $privateKey); + } - + return $plainKeyfile; } - + /** * @brief Encrypt keyfile to multiple users + * @param Session $session * @param array $users list of users which should be able to access the file * @param string $filePath path of the file to be shared - * @return bool + * @return bool */ - public function setSharedFileKeyfiles( Session $session, array $users, $filePath ) { - + public function setSharedFileKeyfiles(Session $session, array $users, $filePath) + { + // Make sure users are capable of sharing - $filteredUids = $this->filterShareReadyUsers( $users ); - + $filteredUids = $this->filterShareReadyUsers($users); + // If we're attempting to share to unready users - if ( ! empty( $filteredUids['unready'] ) ) { - - \OC_Log::write( 'Encryption library', 'Sharing to these user(s) failed as they are unready for encryption:"'.print_r( $filteredUids['unready'], 1 ), \OC_Log::WARN ); - + if (!empty($filteredUids['unready'])) { + + \OC_Log::write('Encryption library', 'Sharing to these user(s) failed as they are unready for encryption:"' . print_r($filteredUids['unready'], 1), \OC_Log::WARN); + return false; - + } - + // Get public keys for each user, ready for generating sharekeys - $userPubKeys = Keymanager::getPublicKeys( $this->view, $filteredUids['ready'] ); - + $userPubKeys = Keymanager::getPublicKeys($this->view, $filteredUids['ready']); + // Note proxy status then disable it $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; @@ -937,273 +977,279 @@ class Util { // Get the current users's private key for decrypting existing keyfile $privateKey = $session->getPrivateKey(); - $fileOwner = \OC\Files\Filesystem::getOwner( $filePath ); - + $fileOwner = \OC\Files\Filesystem::getOwner($filePath); + // Decrypt keyfile - $plainKeyfile = $this->decryptUnknownKeyfile( $filePath, $fileOwner, $privateKey ); - + $plainKeyfile = $this->decryptUnknownKeyfile($filePath, $fileOwner, $privateKey); + // Re-enc keyfile to (additional) sharekeys - $multiEncKey = Crypt::multiKeyEncrypt( $plainKeyfile, $userPubKeys ); - + $multiEncKey = Crypt::multiKeyEncrypt($plainKeyfile, $userPubKeys); + // Save the recrypted key to it's owner's keyfiles directory // Save new sharekeys to all necessary user directory - if ( - ! Keymanager::setFileKey( $this->view, $filePath, $fileOwner, $multiEncKey['data'] ) - || ! Keymanager::setShareKeys( $this->view, $filePath, $multiEncKey['keys'] ) + if ( + !Keymanager::setFileKey($this->view, $filePath, $fileOwner, $multiEncKey['data']) + || !Keymanager::setShareKeys($this->view, $filePath, $multiEncKey['keys']) ) { - \OC_Log::write( 'Encryption library', 'Keyfiles could not be saved for users sharing ' . $filePath, \OC_Log::ERROR ); - + \OC_Log::write('Encryption library', 'Keyfiles could not be saved for users sharing ' . $filePath, \OC_Log::ERROR); + return false; } - + // Return proxy to original status \OC_FileProxy::$enabled = $proxyStatus; return true; } - + /** * @brief Find, sanitise and format users sharing a file * @note This wraps other methods into a portable bundle */ - public function getSharingUsersArray( $sharingEnabled, $filePath, $currentUserId = false ) { + public function getSharingUsersArray($sharingEnabled, $filePath, $currentUserId = false) + { // Check if key recovery is enabled if ( - \OC_Appconfig::getValue( 'files_encryption', 'recoveryAdminEnabled' ) + \OC_Appconfig::getValue('files_encryption', 'recoveryAdminEnabled') && $this->recoveryEnabledForUser() ) { - - $recoveryEnabled = true; - - } else { - - $recoveryEnabled = false; - - } - - // Make sure that a share key is generated for the owner too - list( $owner, $ownerPath ) = $this->getUidAndFilename( $filePath ); - if ( $sharingEnabled ) { - + $recoveryEnabled = true; + + } else { + + $recoveryEnabled = false; + + } + + // Make sure that a share key is generated for the owner too + list($owner, $ownerPath) = $this->getUidAndFilename($filePath); + + if ($sharingEnabled) { + // Find out who, if anyone, is sharing the file - $result = \OCP\Share::getUsersSharingFile( $ownerPath, $owner,true, true, true ); + $result = \OCP\Share::getUsersSharingFile($ownerPath, $owner, true, true, true); $userIds = $result['users']; - if ( $result['public'] ) { + if ($result['public']) { $userIds[] = $this->publicShareKeyId; } - + } - + // If recovery is enabled, add the // Admin UID to list of users to share to - if ( $recoveryEnabled ) { - + if ($recoveryEnabled) { + // Find recoveryAdmin user ID - $recoveryKeyId = \OC_Appconfig::getValue( 'files_encryption', 'recoveryKeyId' ); - + $recoveryKeyId = \OC_Appconfig::getValue('files_encryption', 'recoveryKeyId'); + // Add recoveryAdmin to list of users sharing $userIds[] = $recoveryKeyId; - + } // add current user if given - if ( $currentUserId != false ) { - + if ($currentUserId != false) { + $userIds[] = $currentUserId; - + } // Remove duplicate UIDs - $uniqueUserIds = array_unique ( $userIds ); - + $uniqueUserIds = array_unique($userIds); + return $uniqueUserIds; } - + /** * @brief Set file migration status for user + * @param $status * @return bool */ - public function setMigrationStatus( $status ) { - + public function setMigrationStatus($status) + { + $sql = 'UPDATE *PREFIX*encryption SET migration_status = ? WHERE uid = ?'; - - $args = array( $status, $this->userId ); - - $query = \OCP\DB::prepare( $sql ); - - if ( $query->execute( $args ) ) { - + + $args = array($status, $this->userId); + + $query = \OCP\DB::prepare($sql); + + if ($query->execute($args)) { + return true; - + } else { - + return false; - + } - + } - + /** * @brief Check whether pwd recovery is enabled for a given user - * @return 1 = yes, 0 = no, false = no record - * @note If records are not being returned, check for a hidden space + * @return bool 1 = yes, 0 = no, false = no record + * @note If records are not being returned, check for a hidden space * at the start of the uid in db */ - public function getMigrationStatus() { - + public function getMigrationStatus() + { + $sql = 'SELECT migration_status FROM `*PREFIX*encryption` WHERE uid = ?'; - - $args = array( $this->userId ); - $query = \OCP\DB::prepare( $sql ); - - $result = $query->execute( $args ); - + $args = array($this->userId); + + $query = \OCP\DB::prepare($sql); + + $result = $query->execute($args); + $migrationStatus = array(); - - while( $row = $result->fetchRow() ) { - + + while ($row = $result->fetchRow()) { + $migrationStatus[] = $row['migration_status']; - + } - + // If no record is found - if ( empty( $migrationStatus ) ) { - + if (empty($migrationStatus)) { + return false; - - // If a record is found + + // If a record is found } else { - + return $migrationStatus[0]; - + } - + } - + /** * @brief get uid of the owners of the file and the path to the file - * @param $path Path of the file to check - * @note $shareFilePath must be relative to data/UID/files. Files + * @param string $path Path of the file to check + * @note $shareFilePath must be relative to data/UID/files. Files * relative to /Shared are also acceptable * @return array */ - public function getUidAndFilename( $path ) { + public function getUidAndFilename($path) + { - $view = new \OC\Files\View($this->userFilesDir); - $fileOwnerUid = $view->getOwner( $path ); + $view = new \OC\Files\View($this->userFilesDir); + $fileOwnerUid = $view->getOwner($path); - // handle public access - if($fileOwnerUid === false && $this->isPublic) { - $filename = $path; - $fileOwnerUid = $GLOBALS['fileOwner']; + // handle public access + if ($fileOwnerUid === false && $this->isPublic) { + $filename = $path; + $fileOwnerUid = $GLOBALS['fileOwner']; - return array ( $fileOwnerUid, $filename ); - } else { + return array($fileOwnerUid, $filename); + } else { - // Check that UID is valid - if ( ! \OCP\User::userExists( $fileOwnerUid ) ) { - throw new \Exception( 'Could not find owner (UID = "' . var_export( $fileOwnerUid, 1 ) . '") of file "' . $path . '"' ); - } + // Check that UID is valid + if (!\OCP\User::userExists($fileOwnerUid)) { + throw new \Exception('Could not find owner (UID = "' . var_export($fileOwnerUid, 1) . '") of file "' . $path . '"'); + } - // NOTE: Bah, this dependency should be elsewhere - \OC\Files\Filesystem::initMountPoints( $fileOwnerUid ); + // NOTE: Bah, this dependency should be elsewhere + \OC\Files\Filesystem::initMountPoints($fileOwnerUid); - // If the file owner is the currently logged in user - if ( $fileOwnerUid == $this->userId ) { + // If the file owner is the currently logged in user + if ($fileOwnerUid == $this->userId) { - // Assume the path supplied is correct - $filename = $path; + // Assume the path supplied is correct + $filename = $path; - } else { + } else { - $info = $view->getFileInfo( $path ); - $ownerView = new \OC\Files\View( '/' . $fileOwnerUid . '/files' ); + $info = $view->getFileInfo($path); + $ownerView = new \OC\Files\View('/' . $fileOwnerUid . '/files'); - // Fetch real file path from DB - $filename = $ownerView->getPath( $info['fileid'] ); // TODO: Check that this returns a path without including the user data dir + // Fetch real file path from DB + $filename = $ownerView->getPath($info['fileid']); // TODO: Check that this returns a path without including the user data dir - } + } + + return array($fileOwnerUid, $filename); + } - return array ( $fileOwnerUid, $filename ); - } - } /** * @brief geo recursively through a dir and collect all files and sub files. - * @param type $dir relative to the users files folder + * @param string $dir relative to the users files folder * @return array with list of files relative to the users files folder */ - public function getAllFiles( $dir ) { - + public function getAllFiles($dir) + { + $result = array(); - $content = $this->view->getDirectoryContent( $this->userFilesDir . $dir ); + $content = $this->view->getDirectoryContent($this->userFilesDir . $dir); // handling for re shared folders - $path_split = explode( '/', $dir ); + $path_split = explode('/', $dir); $shared = ''; - - if( $path_split[1] === 'Shared' ) { - + + if ($path_split[1] === 'Shared') { + $shared = '/Shared'; - + } - foreach ( $content as $c ) { - - $sharedPart = $path_split[sizeof( $path_split )-1]; - $targetPathSplit = array_reverse( explode( '/', $c['path'] ) ); + foreach ($content as $c) { + + $sharedPart = $path_split[sizeof($path_split) - 1]; + $targetPathSplit = array_reverse(explode('/', $c['path'])); $path = ''; // rebuild path - foreach ( $targetPathSplit as $pathPart ) { - - if ( $pathPart !== $sharedPart ) { - + foreach ($targetPathSplit as $pathPart) { + + if ($pathPart !== $sharedPart) { + $path = '/' . $pathPart . $path; - + } else { - + break; - + } - + } - $path = $dir.$path; + $path = $dir . $path; + + if ($c['type'] === "dir") { + + $result = array_merge($result, $this->getAllFiles($path)); - if ($c['type'] === "dir" ) { - - $result = array_merge( $result, $this->getAllFiles( $path ) ); - } else { - + $result[] = $path; - + } } - + return $result; - + } /** @@ -1211,13 +1257,14 @@ class Util { * @param int $id of the current share * @return array of the parent */ - public static function getShareParent( $id ) { + public static function getShareParent($id) + { - $query = \OC_DB::prepare( 'SELECT `file_target`, `item_type`' - .' FROM `*PREFIX*share`' - .' WHERE `id` = ?' ); + $query = \OC_DB::prepare('SELECT `file_target`, `item_type`' + . ' FROM `*PREFIX*share`' + . ' WHERE `id` = ?'); - $result = $query->execute( array( $id ) ); + $result = $query->execute(array($id)); $row = $result->fetchRow(); @@ -1230,13 +1277,14 @@ class Util { * @param int $id of the current share * @return array of the parent */ - public static function getParentFromShare( $id ) { + public static function getParentFromShare($id) + { - $query = \OC_DB::prepare( 'SELECT `parent`' - .' FROM `*PREFIX*share`' - .' WHERE `id` = ?' ); + $query = \OC_DB::prepare('SELECT `parent`' + . ' FROM `*PREFIX*share`' + . ' WHERE `id` = ?'); - $result = $query->execute( array( $id ) ); + $result = $query->execute(array($id)); $row = $result->fetchRow(); @@ -1246,57 +1294,70 @@ class Util { /** * @brief get owner of the shared files. - * @param int $Id of a share - * @return owner + * @param $id + * @internal param int $Id of a share + * @return string owner */ - public function getOwnerFromSharedFile( $id ) { - - $query = \OC_DB::prepare( 'SELECT `parent`, `uid_owner` FROM `*PREFIX*share` WHERE `id` = ?', 1 ); - $source = $query->execute( array( $id ) )->fetchRow(); + public function getOwnerFromSharedFile($id) + { + + $query = \OC_DB::prepare('SELECT `parent`, `uid_owner` FROM `*PREFIX*share` WHERE `id` = ?', 1); + $source = $query->execute(array($id))->fetchRow(); + + if (isset($source['parent'])) { - if ( isset($source['parent'] ) ) { - $parent = $source['parent']; - - while ( isset( $parent ) ) { - - $query = \OC_DB::prepare( 'SELECT `parent`, `uid_owner` FROM `*PREFIX*share` WHERE `id` = ?', 1 ); - $item = $query->execute( array( $parent ) )->fetchRow(); - - if ( isset( $item['parent'] ) ) { - + + while (isset($parent)) { + + $query = \OC_DB::prepare('SELECT `parent`, `uid_owner` FROM `*PREFIX*share` WHERE `id` = ?', 1); + $item = $query->execute(array($parent))->fetchRow(); + + if (isset($item['parent'])) { + $parent = $item['parent']; - + } else { - + $fileOwner = $item['uid_owner']; - + break; - + } } - + } else { - + $fileOwner = $source['uid_owner']; - + } return $fileOwner; - + } - public function getUserId() - { - return $this->userId; - } + /** + * @return string + */ + public function getUserId() + { + return $this->userId; + } - public function getUserFilesDir() - { - return $this->userFilesDir; - } + /** + * @return string + */ + public function getUserFilesDir() + { + return $this->userFilesDir; + } - public function checkRecoveryPassword($password) { + /** + * @param $password + * @return bool + */ + public function checkRecoveryPassword($password) + { $pathKey = '/owncloud_private_key/' . $this->recoveryKeyId . ".private.key"; $pathControlData = '/control-file/controlfile.enc'; @@ -1315,30 +1376,35 @@ class Util { if ($decryptedControlData === 'ownCloud') { return true; - } - + } + return false; } - public function getRecoveryKeyId() { + /** + * @return string + */ + public function getRecoveryKeyId() + { return $this->recoveryKeyId; } /** * @brief add recovery key to all encrypted files */ - public function addRecoveryKeys($path = '/') { - $dirContent = $this->view->getDirectoryContent($this->keyfilesPath.$path); + public function addRecoveryKeys($path = '/') + { + $dirContent = $this->view->getDirectoryContent($this->keyfilesPath . $path); foreach ($dirContent as $item) { $filePath = substr($item['path'], 25); if ($item['type'] == 'dir') { - $this->addRecoveryKeys($filePath.'/'); + $this->addRecoveryKeys($filePath . '/'); } else { $session = new Session(new \OC_FilesystemView('/')); $sharingEnabled = \OCP\Share::isEnabled(); $file = substr($filePath, 0, -4); $usersSharing = $this->getSharingUsersArray($sharingEnabled, $file); - $this->setSharedFileKeyfiles( $session, $usersSharing, $file ); + $this->setSharedFileKeyfiles($session, $usersSharing, $file); } } } @@ -1346,25 +1412,27 @@ class Util { /** * @brief remove recovery key to all encrypted files */ - public function removeRecoveryKeys($path = '/') { - $dirContent = $this->view->getDirectoryContent($this->keyfilesPath.$path); + public function removeRecoveryKeys($path = '/') + { + $dirContent = $this->view->getDirectoryContent($this->keyfilesPath . $path); foreach ($dirContent as $item) { $filePath = substr($item['path'], 25); if ($item['type'] == 'dir') { - $this->removeRecoveryKeys($filePath.'/'); + $this->removeRecoveryKeys($filePath . '/'); } else { $file = substr($filePath, 0, -4); - $this->view->unlink($this->shareKeysPath.'/'.$file.'.'.$this->recoveryKeyId.'.shareKey'); + $this->view->unlink($this->shareKeysPath . '/' . $file . '.' . $this->recoveryKeyId . '.shareKey'); } } } /** * @brief decrypt given file with recovery key and encrypt it again to the owner and his new key - * @param type $file - * @param type $privateKey recovery key to decrypt the file + * @param string $file + * @param string $privateKey recovery key to decrypt the file */ - private function recoverFile($file, $privateKey) { + private function recoverFile($file, $privateKey) + { $sharingEnabled = \OCP\Share::isEnabled(); @@ -1385,17 +1453,17 @@ class Util { \OC_FileProxy::$enabled = false; //decrypt file key - $encKeyfile = $this->view->file_get_contents($this->keyfilesPath.$file.".key"); - $shareKey = $this->view->file_get_contents($this->shareKeysPath.$file.".".$this->recoveryKeyId.".shareKey"); + $encKeyfile = $this->view->file_get_contents($this->keyfilesPath . $file . ".key"); + $shareKey = $this->view->file_get_contents($this->shareKeysPath . $file . "." . $this->recoveryKeyId . ".shareKey"); $plainKeyfile = Crypt::multiKeyDecrypt($encKeyfile, $shareKey, $privateKey); // encrypt file key again to all users, this time with the new public key for the recovered use $userPubKeys = Keymanager::getPublicKeys($this->view, $filteredUids['ready']); $multiEncKey = Crypt::multiKeyEncrypt($plainKeyfile, $userPubKeys); // write new keys to filesystem TDOO! - $this->view->file_put_contents($this->keyfilesPath.$file.'.key', $multiEncKey['data']); + $this->view->file_put_contents($this->keyfilesPath . $file . '.key', $multiEncKey['data']); foreach ($multiEncKey['keys'] as $userId => $shareKey) { - $shareKeyPath = $this->shareKeysPath.$file.'.'.$userId.'.shareKey'; + $shareKeyPath = $this->shareKeysPath . $file . '.' . $userId . '.shareKey'; $this->view->file_put_contents($shareKeyPath, $shareKey); } @@ -1405,10 +1473,11 @@ class Util { /** * @brief collect all files and recover them one by one - * @param type $path to look for files keys - * @param type $privateKey private recovery key which is used to decrypt the files + * @param string $path to look for files keys + * @param string $privateKey private recovery key which is used to decrypt the files */ - private function recoverAllFiles($path, $privateKey) { + private function recoverAllFiles($path, $privateKey) + { $dirContent = $this->view->getDirectoryContent($this->keyfilesPath . $path); foreach ($dirContent as $item) { $filePath = substr($item['path'], 25); @@ -1423,16 +1492,17 @@ class Util { /** * @brief recover users files in case of password lost - * @param type $recoveryPassword + * @param string $recoveryPassword */ - public function recoverUsersFiles($recoveryPassword) { + public function recoverUsersFiles($recoveryPassword) + { // Disable encryption proxy to prevent recursive calls $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; - $encryptedKey = $this->view->file_get_contents( '/owncloud_private_key/'.$this->recoveryKeyId.'.private.key' ); - $privateKey = Crypt::symmetricDecryptFileContent( $encryptedKey, $recoveryPassword ); + $encryptedKey = $this->view->file_get_contents('/owncloud_private_key/' . $this->recoveryKeyId . '.private.key'); + $privateKey = Crypt::symmetricDecryptFileContent($encryptedKey, $recoveryPassword); \OC_FileProxy::$enabled = $proxyStatus; diff --git a/apps/files_encryption/tests/crypt.php b/apps/files_encryption/tests/crypt.php index c669aec122..5b5a2189a4 100755 --- a/apps/files_encryption/tests/crypt.php +++ b/apps/files_encryption/tests/crypt.php @@ -7,22 +7,23 @@ * See the COPYING-README file. */ -require_once realpath( dirname(__FILE__).'/../../../3rdparty/Crypt_Blowfish/Blowfish.php' ); -require_once realpath( dirname(__FILE__).'/../../../lib/base.php' ); -require_once realpath( dirname(__FILE__).'/../lib/crypt.php' ); -require_once realpath( dirname(__FILE__).'/../lib/keymanager.php' ); -require_once realpath( dirname(__FILE__).'/../lib/proxy.php' ); -require_once realpath( dirname(__FILE__).'/../lib/stream.php' ); -require_once realpath( dirname(__FILE__).'/../lib/util.php' ); -require_once realpath( dirname(__FILE__).'/../lib/helper.php' ); -require_once realpath( dirname(__FILE__).'/../appinfo/app.php' ); +require_once realpath(dirname(__FILE__) . '/../../../3rdparty/Crypt_Blowfish/Blowfish.php'); +require_once realpath(dirname(__FILE__) . '/../../../lib/base.php'); +require_once realpath(dirname(__FILE__) . '/../lib/crypt.php'); +require_once realpath(dirname(__FILE__) . '/../lib/keymanager.php'); +require_once realpath(dirname(__FILE__) . '/../lib/proxy.php'); +require_once realpath(dirname(__FILE__) . '/../lib/stream.php'); +require_once realpath(dirname(__FILE__) . '/../lib/util.php'); +require_once realpath(dirname(__FILE__) . '/../lib/helper.php'); +require_once realpath(dirname(__FILE__) . '/../appinfo/app.php'); use OCA\Encryption; /** * Class Test_Encryption_Crypt */ -class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase { +class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase +{ public $userId; public $pass; @@ -38,39 +39,40 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase { public $genPrivateKey; public $genPublicKey; - function setUp() { - // reset backend - \OC_User::clearBackends(); - \OC_User::useBackend('database'); + function setUp() + { + // reset backend + \OC_User::clearBackends(); + \OC_User::useBackend('database'); - // set content for encrypting / decrypting in tests - $this->dataLong = file_get_contents( realpath( dirname(__FILE__).'/../lib/crypt.php' ) ); + // set content for encrypting / decrypting in tests + $this->dataLong = file_get_contents(realpath(dirname(__FILE__) . '/../lib/crypt.php')); $this->dataShort = 'hats'; - $this->dataUrl = realpath( dirname(__FILE__).'/../lib/crypt.php' ); - $this->legacyData = realpath( dirname(__FILE__).'/legacy-text.txt' ); - $this->legacyEncryptedData = realpath( dirname(__FILE__).'/legacy-encrypted-text.txt' ); + $this->dataUrl = realpath(dirname(__FILE__) . '/../lib/crypt.php'); + $this->legacyData = realpath(dirname(__FILE__) . '/legacy-text.txt'); + $this->legacyEncryptedData = realpath(dirname(__FILE__) . '/legacy-encrypted-text.txt'); $this->randomKey = Encryption\Crypt::generateKey(); - + $keypair = Encryption\Crypt::createKeypair(); - $this->genPublicKey = $keypair['publicKey']; + $this->genPublicKey = $keypair['publicKey']; $this->genPrivateKey = $keypair['privateKey']; - - $this->view = new \OC_FilesystemView( '/' ); - - \OC_User::setUserId( 'admin' ); + + $this->view = new \OC_FilesystemView('/'); + + \OC_User::setUserId('admin'); $this->userId = 'admin'; $this->pass = 'admin'; - $userHome = \OC_User::getHome($this->userId); - $this->dataDir = str_replace('/'.$this->userId, '', $userHome); + $userHome = \OC_User::getHome($this->userId); + $this->dataDir = str_replace('/' . $this->userId, '', $userHome); - // Filesystem related hooks - \OCA\Encryption\Helper::registerFilesystemHooks(); + // Filesystem related hooks + \OCA\Encryption\Helper::registerFilesystemHooks(); // Filesystem related hooks \OCA\Encryption\Helper::registerUserHooks(); - \OC_FileProxy::register(new OCA\Encryption\Proxy()); + \OC_FileProxy::register(new OCA\Encryption\Proxy()); // remember files_trashbin state $this->stateFilesTrashbin = OC_App::isEnabled('files_trashbin'); @@ -78,19 +80,20 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase { // we don't want to tests with app files_trashbin enabled \OC_App::disable('files_trashbin'); - \OC_Util::tearDownFS(); - \OC_User::setUserId(''); - \OC\Files\Filesystem::tearDown(); - \OC_Util::setupFS($this->userId); - \OC_User::setUserId($this->userId); + \OC_Util::tearDownFS(); + \OC_User::setUserId(''); + \OC\Files\Filesystem::tearDown(); + \OC_Util::setupFS($this->userId); + \OC_User::setUserId($this->userId); - $params['uid'] = $this->userId; - $params['password'] = $this->pass; - OCA\Encryption\Hooks::login($params); + $params['uid'] = $this->userId; + $params['password'] = $this->pass; + OCA\Encryption\Hooks::login($params); } - - function tearDown() { + + function tearDown() + { \OC_FileProxy::clearProxies(); // reset app files_trashbin @@ -99,285 +102,297 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase { } else { OC_App::disable('files_trashbin'); } - } + } + + function testGenerateKey() + { - function testGenerateKey() { - # TODO: use more accurate (larger) string length for test confirmation - + $key = Encryption\Crypt::generateKey(); - - $this->assertTrue( strlen( $key ) > 16 ); - + + $this->assertTrue(strlen($key) > 16); + } /** * @return String */ - function testGenerateIv() { - + function testGenerateIv() + { + $iv = Encryption\Crypt::generateIv(); - - $this->assertEquals( 16, strlen( $iv ) ); - + + $this->assertEquals(16, strlen($iv)); + return $iv; - + } - + /** * @depends testGenerateIv */ - function testConcatIv( $iv ) { - - $catFile = Encryption\Crypt::concatIv( $this->dataLong, $iv ); - + function testConcatIv($iv) + { + + $catFile = Encryption\Crypt::concatIv($this->dataLong, $iv); + // Fetch encryption metadata from end of file - $meta = substr( $catFile, -22 ); - - $identifier = substr( $meta, 0, 6); - + $meta = substr($catFile, -22); + + $identifier = substr($meta, 0, 6); + // Fetch IV from end of file - $foundIv = substr( $meta, 6 ); - - $this->assertEquals( '00iv00', $identifier ); - - $this->assertEquals( $iv, $foundIv ); - + $foundIv = substr($meta, 6); + + $this->assertEquals('00iv00', $identifier); + + $this->assertEquals($iv, $foundIv); + // Remove IV and IV identifier text to expose encrypted content - $data = substr( $catFile, 0, -22 ); - - $this->assertEquals( $this->dataLong, $data ); - + $data = substr($catFile, 0, -22); + + $this->assertEquals($this->dataLong, $data); + return array( 'iv' => $iv - , 'catfile' => $catFile + , 'catfile' => $catFile ); - + } - + /** * @depends testConcatIv */ - function testSplitIv( $testConcatIv ) { - + function testSplitIv($testConcatIv) + { + // Split catfile into components - $splitCatfile = Encryption\Crypt::splitIv( $testConcatIv['catfile'] ); - + $splitCatfile = Encryption\Crypt::splitIv($testConcatIv['catfile']); + // Check that original IV and split IV match - $this->assertEquals( $testConcatIv['iv'], $splitCatfile['iv'] ); - + $this->assertEquals($testConcatIv['iv'], $splitCatfile['iv']); + // Check that original data and split data match - $this->assertEquals( $this->dataLong, $splitCatfile['encrypted'] ); - + $this->assertEquals($this->dataLong, $splitCatfile['encrypted']); + } /** * @return string padded */ - function testAddPadding() { - - $padded = Encryption\Crypt::addPadding( $this->dataLong ); - - $padding = substr( $padded, -2 ); - - $this->assertEquals( 'xx' , $padding ); - + function testAddPadding() + { + + $padded = Encryption\Crypt::addPadding($this->dataLong); + + $padding = substr($padded, -2); + + $this->assertEquals('xx', $padding); + return $padded; - + } - + /** * @depends testAddPadding */ - function testRemovePadding( $padded ) { - - $noPadding = Encryption\Crypt::RemovePadding( $padded ); - - $this->assertEquals( $this->dataLong, $noPadding ); - + function testRemovePadding($padded) + { + + $noPadding = Encryption\Crypt::RemovePadding($padded); + + $this->assertEquals($this->dataLong, $noPadding); + } - - function testEncrypt() { - - $random = openssl_random_pseudo_bytes( 13 ); - $iv = substr( base64_encode( $random ), 0, -4 ); // i.e. E5IG033j+mRNKrht + function testEncrypt() + { - $crypted = Encryption\Crypt::encrypt( $this->dataUrl, $iv, 'hat' ); + $random = openssl_random_pseudo_bytes(13); + + $iv = substr(base64_encode($random), 0, -4); // i.e. E5IG033j+mRNKrht + + $crypted = Encryption\Crypt::encrypt($this->dataUrl, $iv, 'hat'); + + $this->assertNotEquals($this->dataUrl, $crypted); - $this->assertNotEquals( $this->dataUrl, $crypted ); - } - - function testDecrypt() { - - $random = openssl_random_pseudo_bytes( 13 ); - $iv = substr( base64_encode( $random ), 0, -4 ); // i.e. E5IG033j+mRNKrht + function testDecrypt() + { - $crypted = Encryption\Crypt::encrypt( $this->dataUrl, $iv, 'hat' ); - - $decrypt = Encryption\Crypt::decrypt( $crypted, $iv, 'hat' ); + $random = openssl_random_pseudo_bytes(13); + + $iv = substr(base64_encode($random), 0, -4); // i.e. E5IG033j+mRNKrht + + $crypted = Encryption\Crypt::encrypt($this->dataUrl, $iv, 'hat'); + + $decrypt = Encryption\Crypt::decrypt($crypted, $iv, 'hat'); + + $this->assertEquals($this->dataUrl, $decrypt); - $this->assertEquals( $this->dataUrl, $decrypt ); - } - - function testSymmetricEncryptFileContent() { - + + function testSymmetricEncryptFileContent() + { + # TODO: search in keyfile for actual content as IV will ensure this test always passes - - $crypted = Encryption\Crypt::symmetricEncryptFileContent( $this->dataShort, 'hat' ); - $this->assertNotEquals( $this->dataShort, $crypted ); - + $crypted = Encryption\Crypt::symmetricEncryptFileContent($this->dataShort, 'hat'); - $decrypt = Encryption\Crypt::symmetricDecryptFileContent( $crypted, 'hat' ); + $this->assertNotEquals($this->dataShort, $crypted); + + + $decrypt = Encryption\Crypt::symmetricDecryptFileContent($crypted, 'hat'); + + $this->assertEquals($this->dataShort, $decrypt); - $this->assertEquals( $this->dataShort, $decrypt ); - } - function testSymmetricStreamEncryptShortFileContent() { - - $filename = 'tmp-'.time().'.test'; + function testSymmetricStreamEncryptShortFileContent() + { + + $filename = 'tmp-' . time() . '.test'; + + $cryptedFile = file_put_contents('crypt://' . $filename, $this->dataShort); - $cryptedFile = file_put_contents( 'crypt://' . $filename, $this->dataShort ); - // Test that data was successfully written - $this->assertTrue( is_int( $cryptedFile ) ); + $this->assertTrue(is_int($cryptedFile)); - // Disable encryption proxy to prevent recursive calls - $proxyStatus = \OC_FileProxy::$enabled; - \OC_FileProxy::$enabled = false; + // Disable encryption proxy to prevent recursive calls + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; - // Get file contents without using any wrapper to get it's actual contents on disk - $retreivedCryptedFile = $this->view->file_get_contents($this->userId . '/files/' . $filename); + // Get file contents without using any wrapper to get it's actual contents on disk + $retreivedCryptedFile = $this->view->file_get_contents($this->userId . '/files/' . $filename); - // Re-enable proxy - our work is done - \OC_FileProxy::$enabled = $proxyStatus; + // Re-enable proxy - our work is done + \OC_FileProxy::$enabled = $proxyStatus; // Check that the file was encrypted before being written to disk - $this->assertNotEquals( $this->dataShort, $retreivedCryptedFile ); + $this->assertNotEquals($this->dataShort, $retreivedCryptedFile); - // Get the encrypted keyfile - $encKeyfile = Encryption\Keymanager::getFileKey( $this->view, $this->userId, $filename ); + // Get the encrypted keyfile + $encKeyfile = Encryption\Keymanager::getFileKey($this->view, $this->userId, $filename); - // Attempt to fetch the user's shareKey - $shareKey = Encryption\Keymanager::getShareKey( $this->view, $this->userId, $filename ); + // Attempt to fetch the user's shareKey + $shareKey = Encryption\Keymanager::getShareKey($this->view, $this->userId, $filename); - // get session - $session = new Encryption\Session( $this->view ); + // get session + $session = new Encryption\Session($this->view); - // get private key - $privateKey = $session->getPrivateKey( $this->userId ); + // get private key + $privateKey = $session->getPrivateKey($this->userId); - // Decrypt keyfile with shareKey - $plainKeyfile = Encryption\Crypt::multiKeyDecrypt( $encKeyfile, $shareKey, $privateKey ); + // Decrypt keyfile with shareKey + $plainKeyfile = Encryption\Crypt::multiKeyDecrypt($encKeyfile, $shareKey, $privateKey); - // Manually decrypt - $manualDecrypt = Encryption\Crypt::symmetricDecryptFileContent( $retreivedCryptedFile, $plainKeyfile ); + // Manually decrypt + $manualDecrypt = Encryption\Crypt::symmetricDecryptFileContent($retreivedCryptedFile, $plainKeyfile); // Check that decrypted data matches - $this->assertEquals( $this->dataShort, $manualDecrypt ); + $this->assertEquals($this->dataShort, $manualDecrypt); - // Teardown - $this->view->unlink( $this->userId . '/files/' . $filename ); + // Teardown + $this->view->unlink($this->userId . '/files/' . $filename); - Encryption\Keymanager::deleteFileKey( $this->view, $this->userId, $filename ); + Encryption\Keymanager::deleteFileKey($this->view, $this->userId, $filename); } - + /** * @brief Test that data that is written by the crypto stream wrapper * @note Encrypted data is manually prepared and decrypted here to avoid dependency on success of stream_read - * @note If this test fails with truncate content, check that enough array slices are being rejoined to form $e, as the crypt.php file may have gotten longer and broken the manual + * @note If this test fails with truncate content, check that enough array slices are being rejoined to form $e, as the crypt.php file may have gotten longer and broken the manual * reassembly of its data */ - function testSymmetricStreamEncryptLongFileContent() { - + function testSymmetricStreamEncryptLongFileContent() + { + // Generate a a random filename - $filename = 'tmp-'.time().'.test'; - + $filename = 'tmp-' . time() . '.test'; + // Save long data as encrypted file using stream wrapper - $cryptedFile = file_put_contents( 'crypt://' . $filename, $this->dataLong.$this->dataLong ); - + $cryptedFile = file_put_contents('crypt://' . $filename, $this->dataLong . $this->dataLong); + // Test that data was successfully written - $this->assertTrue( is_int( $cryptedFile ) ); - + $this->assertTrue(is_int($cryptedFile)); + // Disable encryption proxy to prevent recursive calls - $proxyStatus = \OC_FileProxy::$enabled; - \OC_FileProxy::$enabled = false; + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; - // Get file contents without using any wrapper to get it's actual contents on disk - $retreivedCryptedFile = $this->view->file_get_contents($this->userId . '/files/' . $filename); + // Get file contents without using any wrapper to get it's actual contents on disk + $retreivedCryptedFile = $this->view->file_get_contents($this->userId . '/files/' . $filename); - // Re-enable proxy - our work is done - \OC_FileProxy::$enabled = $proxyStatus; + // Re-enable proxy - our work is done + \OC_FileProxy::$enabled = $proxyStatus; - // Check that the file was encrypted before being written to disk - $this->assertNotEquals( $this->dataLong.$this->dataLong, $retreivedCryptedFile ); - + // Check that the file was encrypted before being written to disk + $this->assertNotEquals($this->dataLong . $this->dataLong, $retreivedCryptedFile); + // Manuallly split saved file into separate IVs and encrypted chunks $r = preg_split('/(00iv00.{16,18})/', $retreivedCryptedFile, NULL, PREG_SPLIT_DELIM_CAPTURE); - + //print_r($r); - + // Join IVs and their respective data chunks - $e = array( $r[0].$r[1], $r[2].$r[3], $r[4].$r[5], $r[6].$r[7], $r[8].$r[9], $r[10].$r[11]);//.$r[11], $r[12].$r[13], $r[14] ); - + $e = array($r[0] . $r[1], $r[2] . $r[3], $r[4] . $r[5], $r[6] . $r[7], $r[8] . $r[9], $r[10] . $r[11]); //.$r[11], $r[12].$r[13], $r[14] ); + //print_r($e); - // Get the encrypted keyfile - $encKeyfile = Encryption\Keymanager::getFileKey( $this->view, $this->userId, $filename ); + // Get the encrypted keyfile + $encKeyfile = Encryption\Keymanager::getFileKey($this->view, $this->userId, $filename); - // Attempt to fetch the user's shareKey - $shareKey = Encryption\Keymanager::getShareKey( $this->view, $this->userId, $filename ); + // Attempt to fetch the user's shareKey + $shareKey = Encryption\Keymanager::getShareKey($this->view, $this->userId, $filename); - // get session - $session = new Encryption\Session( $this->view ); + // get session + $session = new Encryption\Session($this->view); - // get private key - $privateKey = $session->getPrivateKey( $this->userId ); + // get private key + $privateKey = $session->getPrivateKey($this->userId); - // Decrypt keyfile with shareKey - $plainKeyfile = Encryption\Crypt::multiKeyDecrypt( $encKeyfile, $shareKey, $privateKey ); + // Decrypt keyfile with shareKey + $plainKeyfile = Encryption\Crypt::multiKeyDecrypt($encKeyfile, $shareKey, $privateKey); // Set var for reassembling decrypted content $decrypt = ''; - + // Manually decrypt chunk foreach ($e as $chunk) { - - $chunkDecrypt = Encryption\Crypt::symmetricDecryptFileContent( $chunk, $plainKeyfile ); - + + $chunkDecrypt = Encryption\Crypt::symmetricDecryptFileContent($chunk, $plainKeyfile); + // Assemble decrypted chunks $decrypt .= $chunkDecrypt; - + } - - $this->assertEquals( $this->dataLong.$this->dataLong, $decrypt ); - + + $this->assertEquals($this->dataLong . $this->dataLong, $decrypt); + // Teardown - - $this->view->unlink( $this->userId . '/files/' . $filename ); - - Encryption\Keymanager::deleteFileKey( $this->view, $this->userId, $filename ); - + + $this->view->unlink($this->userId . '/files/' . $filename); + + Encryption\Keymanager::deleteFileKey($this->view, $this->userId, $filename); + } - + /** * @brief Test that data that is read by the crypto stream wrapper */ - function testSymmetricStreamDecryptShortFileContent() { - - $filename = 'tmp-'.time(); - + function testSymmetricStreamDecryptShortFileContent() + { + + $filename = 'tmp-' . time(); + // Save long data as encrypted file using stream wrapper - $cryptedFile = file_put_contents( 'crypt://' . $filename, $this->dataShort ); - + $cryptedFile = file_put_contents('crypt://' . $filename, $this->dataShort); + // Test that data was successfully written - $this->assertTrue( is_int( $cryptedFile ) ); + $this->assertTrue(is_int($cryptedFile)); // Disable encryption proxy to prevent recursive calls $proxyStatus = \OC_FileProxy::$enabled; @@ -387,34 +402,35 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase { \OC_FileProxy::$enabled = $proxyStatus; - // Get file decrypted contents - $decrypt = file_get_contents( 'crypt://' . $filename ); - - $this->assertEquals( $this->dataShort, $decrypt ); + // Get file decrypted contents + $decrypt = file_get_contents('crypt://' . $filename); - // tear down - $this->view->unlink( $this->userId . '/files/' . $filename ); + $this->assertEquals($this->dataShort, $decrypt); + + // tear down + $this->view->unlink($this->userId . '/files/' . $filename); } - - function testSymmetricStreamDecryptLongFileContent() { - - $filename = 'tmp-'.time(); - + + function testSymmetricStreamDecryptLongFileContent() + { + + $filename = 'tmp-' . time(); + // Save long data as encrypted file using stream wrapper - $cryptedFile = file_put_contents( 'crypt://' . $filename, $this->dataLong ); - + $cryptedFile = file_put_contents('crypt://' . $filename, $this->dataLong); + // Test that data was successfully written - $this->assertTrue( is_int( $cryptedFile ) ); + $this->assertTrue(is_int($cryptedFile)); - // Get file decrypted contents - $decrypt = file_get_contents( 'crypt://' . $filename ); + // Get file decrypted contents + $decrypt = file_get_contents('crypt://' . $filename); - $this->assertEquals( $this->dataLong, $decrypt ); + $this->assertEquals($this->dataLong, $decrypt); - // tear down - $this->view->unlink( $this->userId . '/files/' . $filename ); + // tear down + $this->view->unlink($this->userId . '/files/' . $filename); } - + // Is this test still necessary? // function testSymmetricBlockStreamDecryptFileContent() { // @@ -438,260 +454,274 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase { // // } - function testSymmetricEncryptFileContentKeyfile() { - - # TODO: search in keyfile for actual content as IV will ensure this test always passes - - $crypted = Encryption\Crypt::symmetricEncryptFileContentKeyfile( $this->dataUrl ); - - $this->assertNotEquals( $this->dataUrl, $crypted['encrypted'] ); - - - $decrypt = Encryption\Crypt::symmetricDecryptFileContent( $crypted['encrypted'], $crypted['key'] ); - - $this->assertEquals( $this->dataUrl, $decrypt ); - - } - - function testIsEncryptedContent() { - - $this->assertFalse( Encryption\Crypt::isCatfileContent( $this->dataUrl ) ); - - $this->assertFalse( Encryption\Crypt::isCatfileContent( $this->legacyEncryptedData ) ); - - $keyfileContent = Encryption\Crypt::symmetricEncryptFileContent( $this->dataUrl, 'hat' ); + function testSymmetricEncryptFileContentKeyfile() + { - $this->assertTrue( Encryption\Crypt::isCatfileContent( $keyfileContent ) ); - - } - - function testMultiKeyEncrypt() { - # TODO: search in keyfile for actual content as IV will ensure this test always passes - + + $crypted = Encryption\Crypt::symmetricEncryptFileContentKeyfile($this->dataUrl); + + $this->assertNotEquals($this->dataUrl, $crypted['encrypted']); + + + $decrypt = Encryption\Crypt::symmetricDecryptFileContent($crypted['encrypted'], $crypted['key']); + + $this->assertEquals($this->dataUrl, $decrypt); + + } + + function testIsEncryptedContent() + { + + $this->assertFalse(Encryption\Crypt::isCatfileContent($this->dataUrl)); + + $this->assertFalse(Encryption\Crypt::isCatfileContent($this->legacyEncryptedData)); + + $keyfileContent = Encryption\Crypt::symmetricEncryptFileContent($this->dataUrl, 'hat'); + + $this->assertTrue(Encryption\Crypt::isCatfileContent($keyfileContent)); + + } + + function testMultiKeyEncrypt() + { + + # TODO: search in keyfile for actual content as IV will ensure this test always passes + $pair1 = Encryption\Crypt::createKeypair(); - - $this->assertEquals( 2, count( $pair1 ) ); - - $this->assertTrue( strlen( $pair1['publicKey'] ) > 1 ); - - $this->assertTrue( strlen( $pair1['privateKey'] ) > 1 ); - - $crypted = Encryption\Crypt::multiKeyEncrypt( $this->dataShort, array( $pair1['publicKey'] ) ); - - $this->assertNotEquals( $this->dataShort, $crypted['data'] ); - + $this->assertEquals(2, count($pair1)); + + $this->assertTrue(strlen($pair1['publicKey']) > 1); + + $this->assertTrue(strlen($pair1['privateKey']) > 1); + + + $crypted = Encryption\Crypt::multiKeyEncrypt($this->dataShort, array($pair1['publicKey'])); + + $this->assertNotEquals($this->dataShort, $crypted['data']); + + + $decrypt = Encryption\Crypt::multiKeyDecrypt($crypted['data'], $crypted['keys'][0], $pair1['privateKey']); + + $this->assertEquals($this->dataShort, $decrypt); - $decrypt = Encryption\Crypt::multiKeyDecrypt( $crypted['data'], $crypted['keys'][0], $pair1['privateKey'] ); - - $this->assertEquals( $this->dataShort, $decrypt ); - } - - function testKeyEncrypt() { - + + function testKeyEncrypt() + { + // Generate keypair $pair1 = Encryption\Crypt::createKeypair(); - + // Encrypt data - $crypted = Encryption\Crypt::keyEncrypt( $this->dataUrl, $pair1['publicKey'] ); - - $this->assertNotEquals( $this->dataUrl, $crypted ); - + $crypted = Encryption\Crypt::keyEncrypt($this->dataUrl, $pair1['publicKey']); + + $this->assertNotEquals($this->dataUrl, $crypted); + // Decrypt data - $decrypt = Encryption\Crypt::keyDecrypt( $crypted, $pair1['privateKey'] ); - - $this->assertEquals( $this->dataUrl, $decrypt ); - + $decrypt = Encryption\Crypt::keyDecrypt($crypted, $pair1['privateKey']); + + $this->assertEquals($this->dataUrl, $decrypt); + } - + /** * @brief test encryption using legacy blowfish method */ - function testLegacyEncryptShort() { - - $crypted = Encryption\Crypt::legacyEncrypt( $this->dataShort, $this->pass ); + function testLegacyEncryptShort() + { + + $crypted = Encryption\Crypt::legacyEncrypt($this->dataShort, $this->pass); + + $this->assertNotEquals($this->dataShort, $crypted); - $this->assertNotEquals( $this->dataShort, $crypted ); - # TODO: search inencrypted text for actual content to ensure it # genuine transformation - + return $crypted; - + } - + /** * @brief test decryption using legacy blowfish method * @depends testLegacyEncryptShort */ - function testLegacyDecryptShort( $crypted ) { - - $decrypted = Encryption\Crypt::legacyDecrypt( $crypted, $this->pass ); - - $this->assertEquals( $this->dataShort, $decrypted ); - + function testLegacyDecryptShort($crypted) + { + + $decrypted = Encryption\Crypt::legacyDecrypt($crypted, $this->pass); + + $this->assertEquals($this->dataShort, $decrypted); + } /** * @brief test encryption using legacy blowfish method */ - function testLegacyEncryptLong() { - - $crypted = Encryption\Crypt::legacyEncrypt( $this->dataLong, $this->pass ); + function testLegacyEncryptLong() + { + + $crypted = Encryption\Crypt::legacyEncrypt($this->dataLong, $this->pass); + + $this->assertNotEquals($this->dataLong, $crypted); - $this->assertNotEquals( $this->dataLong, $crypted ); - # TODO: search inencrypted text for actual content to ensure it # genuine transformation - + return $crypted; - + } - + /** * @brief test decryption using legacy blowfish method * @depends testLegacyEncryptLong */ - function testLegacyDecryptLong( $crypted ) { - - $decrypted = Encryption\Crypt::legacyDecrypt( $crypted, $this->pass ); - - $this->assertEquals( $this->dataLong, $decrypted ); - + function testLegacyDecryptLong($crypted) + { + + $decrypted = Encryption\Crypt::legacyDecrypt($crypted, $this->pass); + + $this->assertEquals($this->dataLong, $decrypted); + } - + /** * @brief test generation of legacy encryption key * @depends testLegacyDecryptShort */ - function testLegacyCreateKey() { - + function testLegacyCreateKey() + { + // Create encrypted key - $encKey = Encryption\Crypt::legacyCreateKey( $this->pass ); - + $encKey = Encryption\Crypt::legacyCreateKey($this->pass); + // Decrypt key - $key = Encryption\Crypt::legacyDecrypt( $encKey, $this->pass ); - - $this->assertTrue( is_numeric( $key ) ); - + $key = Encryption\Crypt::legacyDecrypt($encKey, $this->pass); + + $this->assertTrue(is_numeric($key)); + // Check that key is correct length - $this->assertEquals( 20, strlen( $key ) ); - + $this->assertEquals(20, strlen($key)); + } /** * @brief test decryption using legacy blowfish method * @depends testLegacyEncryptLong */ - function testLegacyKeyRecryptKeyfileEncrypt( $crypted ) { - - $recrypted = Encryption\Crypt::LegacyKeyRecryptKeyfile( $crypted, $this->pass, array($this->genPublicKey), $this->pass, ''); - - $this->assertNotEquals( $this->dataLong, $recrypted['data'] ); - + function testLegacyKeyRecryptKeyfileEncrypt($crypted) + { + + $recrypted = Encryption\Crypt::LegacyKeyRecryptKeyfile($crypted, $this->pass, array($this->genPublicKey), $this->pass, ''); + + $this->assertNotEquals($this->dataLong, $recrypted['data']); + return $recrypted; - + # TODO: search inencrypted text for actual content to ensure it # genuine transformation - + } - function testRenameFile() { + function testRenameFile() + { - $filename = 'tmp-'.time(); + $filename = 'tmp-' . time(); - // Save long data as encrypted file using stream wrapper - $cryptedFile = file_put_contents( 'crypt://' . $filename, $this->dataLong ); + // Save long data as encrypted file using stream wrapper + $cryptedFile = file_put_contents('crypt://' . $filename, $this->dataLong); - // Test that data was successfully written - $this->assertTrue( is_int( $cryptedFile ) ); + // Test that data was successfully written + $this->assertTrue(is_int($cryptedFile)); // Get file decrypted contents - $decrypt = file_get_contents( 'crypt://' . $filename ); + $decrypt = file_get_contents('crypt://' . $filename); - $this->assertEquals( $this->dataLong, $decrypt ); + $this->assertEquals($this->dataLong, $decrypt); - $newFilename = 'tmp-new-'.time(); - $view = new \OC\Files\View('/' . $this->userId . '/files'); - $view->rename( $filename, $newFilename ); + $newFilename = 'tmp-new-' . time(); + $view = new \OC\Files\View('/' . $this->userId . '/files'); + $view->rename($filename, $newFilename); - // Get file decrypted contents - $newDecrypt = file_get_contents( 'crypt://' . $newFilename ); + // Get file decrypted contents + $newDecrypt = file_get_contents('crypt://' . $newFilename); - $this->assertEquals( $this->dataLong, $newDecrypt ); + $this->assertEquals($this->dataLong, $newDecrypt); - // tear down - $view->unlink( $newFilename ); - } + // tear down + $view->unlink($newFilename); + } - function testMoveFileIntoFolder() { + function testMoveFileIntoFolder() + { - $filename = 'tmp-'.time(); + $filename = 'tmp-' . time(); - // Save long data as encrypted file using stream wrapper - $cryptedFile = file_put_contents( 'crypt://' . $filename, $this->dataLong ); + // Save long data as encrypted file using stream wrapper + $cryptedFile = file_put_contents('crypt://' . $filename, $this->dataLong); - // Test that data was successfully written - $this->assertTrue( is_int( $cryptedFile ) ); + // Test that data was successfully written + $this->assertTrue(is_int($cryptedFile)); - // Get file decrypted contents - $decrypt = file_get_contents( 'crypt://' . $filename ); + // Get file decrypted contents + $decrypt = file_get_contents('crypt://' . $filename); - $this->assertEquals( $this->dataLong, $decrypt ); + $this->assertEquals($this->dataLong, $decrypt); - $newFolder = '/newfolder'.time(); - $newFilename = 'tmp-new-'.time(); - $view = new \OC\Files\View('/' . $this->userId . '/files'); - $view->mkdir($newFolder); - $view->rename( $filename, $newFolder . '/' . $newFilename ); + $newFolder = '/newfolder' . time(); + $newFilename = 'tmp-new-' . time(); + $view = new \OC\Files\View('/' . $this->userId . '/files'); + $view->mkdir($newFolder); + $view->rename($filename, $newFolder . '/' . $newFilename); - // Get file decrypted contents - $newDecrypt = file_get_contents( 'crypt://' . $newFolder . '/' . $newFilename ); + // Get file decrypted contents + $newDecrypt = file_get_contents('crypt://' . $newFolder . '/' . $newFilename); - $this->assertEquals( $this->dataLong, $newDecrypt ); + $this->assertEquals($this->dataLong, $newDecrypt); - // tear down - $view->unlink( $newFolder ); - } + // tear down + $view->unlink($newFolder); + } - function testMoveFolder() { + function testMoveFolder() + { $view = new \OC\Files\View('/' . $this->userId . '/files'); - $filename = '/tmp-'.time(); - $folder = '/folder'.time(); + $filename = '/tmp-' . time(); + $folder = '/folder' . time(); $view->mkdir($folder); // Save long data as encrypted file using stream wrapper - $cryptedFile = file_put_contents( 'crypt://' . $folder . $filename, $this->dataLong ); + $cryptedFile = file_put_contents('crypt://' . $folder . $filename, $this->dataLong); // Test that data was successfully written - $this->assertTrue( is_int( $cryptedFile ) ); + $this->assertTrue(is_int($cryptedFile)); // Get file decrypted contents - $decrypt = file_get_contents( 'crypt://' . $folder . $filename ); + $decrypt = file_get_contents('crypt://' . $folder . $filename); - $this->assertEquals( $this->dataLong, $decrypt ); + $this->assertEquals($this->dataLong, $decrypt); - $newFolder = '/newfolder'.time(); + $newFolder = '/newfolder' . time(); - $view->rename( $folder, $newFolder ); + $view->rename($folder, $newFolder); // Get file decrypted contents - $newDecrypt = file_get_contents( 'crypt://' . $newFolder . $filename ); + $newDecrypt = file_get_contents('crypt://' . $newFolder . $filename); - $this->assertEquals( $this->dataLong, $newDecrypt ); + $this->assertEquals($this->dataLong, $newDecrypt); // tear down - $view->unlink( $newFolder ); + $view->unlink($newFolder); } - function testRenameFolder() { + function testRenameFolder() + { - $filename = '/tmp-'.time(); + $filename = '/tmp-' . time(); $folder = '/folder'; $newFolder = '/newfolder'; @@ -699,42 +729,43 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase { $view->mkdir($folder); // Save long data as encrypted file using stream wrapper - $cryptedFile = file_put_contents( 'crypt://' . $folder . $filename, $this->dataLong ); + $cryptedFile = file_put_contents('crypt://' . $folder . $filename, $this->dataLong); // Test that data was successfully written - $this->assertTrue( is_int( $cryptedFile ) ); + $this->assertTrue(is_int($cryptedFile)); // Get file decrypted contents - $decrypt = file_get_contents( 'crypt://' . $folder . $filename ); + $decrypt = file_get_contents('crypt://' . $folder . $filename); - $this->assertEquals( $this->dataLong, $decrypt ); + $this->assertEquals($this->dataLong, $decrypt); // rename folder $view->rename($folder, $newFolder); // Get file decrypted contents - $newDecrypt = file_get_contents( 'crypt://' . $newFolder . $filename ); + $newDecrypt = file_get_contents('crypt://' . $newFolder . $filename); - $this->assertEquals( $this->dataLong, $newDecrypt ); + $this->assertEquals($this->dataLong, $newDecrypt); // tear down - $view->unlink( $newFolder ); + $view->unlink($newFolder); } - function testChangePassphrase() { + function testChangePassphrase() + { - $filename = 'tmp-'.time(); + $filename = 'tmp-' . time(); // Save long data as encrypted file using stream wrapper - $cryptedFile = file_put_contents( 'crypt://' . $filename, $this->dataLong ); + $cryptedFile = file_put_contents('crypt://' . $filename, $this->dataLong); // Test that data was successfully written - $this->assertTrue( is_int( $cryptedFile ) ); + $this->assertTrue(is_int($cryptedFile)); // Get file decrypted contents - $decrypt = file_get_contents( 'crypt://' . $filename ); + $decrypt = file_get_contents('crypt://' . $filename); - $this->assertEquals( $this->dataLong, $decrypt ); + $this->assertEquals($this->dataLong, $decrypt); // change password \OC_User::setPassword($this->userId, 'test', null); @@ -745,109 +776,113 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase { OCA\Encryption\Hooks::login($params); // Get file decrypted contents - $newDecrypt = file_get_contents( 'crypt://' . $filename ); + $newDecrypt = file_get_contents('crypt://' . $filename); - $this->assertEquals( $this->dataLong, $newDecrypt ); + $this->assertEquals($this->dataLong, $newDecrypt); // tear down // change password back \OC_User::setPassword($this->userId, $this->pass); $view = new \OC\Files\View('/' . $this->userId . '/files'); - $view->unlink( $filename ); + $view->unlink($filename); } - function testViewFilePutAndGetContents() { + function testViewFilePutAndGetContents() + { - $filename = '/tmp-'.time(); + $filename = '/tmp-' . time(); $view = new \OC\Files\View('/' . $this->userId . '/files'); // Save short data as encrypted file using stream wrapper - $cryptedFile = $view->file_put_contents( $filename, $this->dataShort ); + $cryptedFile = $view->file_put_contents($filename, $this->dataShort); // Test that data was successfully written - $this->assertTrue( is_int( $cryptedFile ) ); + $this->assertTrue(is_int($cryptedFile)); // Get file decrypted contents - $decrypt = $view->file_get_contents( $filename ); + $decrypt = $view->file_get_contents($filename); - $this->assertEquals( $this->dataShort, $decrypt ); + $this->assertEquals($this->dataShort, $decrypt); // Save long data as encrypted file using stream wrapper - $cryptedFileLong = $view->file_put_contents( $filename, $this->dataLong ); + $cryptedFileLong = $view->file_put_contents($filename, $this->dataLong); // Test that data was successfully written - $this->assertTrue( is_int( $cryptedFileLong ) ); + $this->assertTrue(is_int($cryptedFileLong)); // Get file decrypted contents - $decryptLong = $view->file_get_contents( $filename ); + $decryptLong = $view->file_get_contents($filename); - $this->assertEquals( $this->dataLong, $decryptLong ); + $this->assertEquals($this->dataLong, $decryptLong); // tear down - $view->unlink( $filename ); + $view->unlink($filename); } - function testTouchExistingFile() { - $filename = '/tmp-'.time(); + function testTouchExistingFile() + { + $filename = '/tmp-' . time(); $view = new \OC\Files\View('/' . $this->userId . '/files'); // Save short data as encrypted file using stream wrapper - $cryptedFile = $view->file_put_contents( $filename, $this->dataShort ); + $cryptedFile = $view->file_put_contents($filename, $this->dataShort); // Test that data was successfully written - $this->assertTrue( is_int( $cryptedFile ) ); + $this->assertTrue(is_int($cryptedFile)); $view->touch($filename); // Get file decrypted contents - $decrypt = $view->file_get_contents( $filename ); + $decrypt = $view->file_get_contents($filename); - $this->assertEquals( $this->dataShort, $decrypt ); + $this->assertEquals($this->dataShort, $decrypt); // tear down - $view->unlink( $filename ); + $view->unlink($filename); } - function testTouchFile() { - $filename = '/tmp-'.time(); + function testTouchFile() + { + $filename = '/tmp-' . time(); $view = new \OC\Files\View('/' . $this->userId . '/files'); $view->touch($filename); // Save short data as encrypted file using stream wrapper - $cryptedFile = $view->file_put_contents( $filename, $this->dataShort ); + $cryptedFile = $view->file_put_contents($filename, $this->dataShort); // Test that data was successfully written - $this->assertTrue( is_int( $cryptedFile ) ); + $this->assertTrue(is_int($cryptedFile)); // Get file decrypted contents - $decrypt = $view->file_get_contents( $filename ); + $decrypt = $view->file_get_contents($filename); - $this->assertEquals( $this->dataShort, $decrypt ); + $this->assertEquals($this->dataShort, $decrypt); // tear down - $view->unlink( $filename ); + $view->unlink($filename); } - function testFopenFile() { - $filename = '/tmp-'.time(); + function testFopenFile() + { + $filename = '/tmp-' . time(); $view = new \OC\Files\View('/' . $this->userId . '/files'); // Save short data as encrypted file using stream wrapper - $cryptedFile = $view->file_put_contents( $filename, $this->dataShort ); + $cryptedFile = $view->file_put_contents($filename, $this->dataShort); // Test that data was successfully written - $this->assertTrue( is_int( $cryptedFile ) ); + $this->assertTrue(is_int($cryptedFile)); $handle = $view->fopen($filename, 'r'); // Get file decrypted contents $decrypt = fgets($handle); - $this->assertEquals( $this->dataShort, $decrypt ); + $this->assertEquals($this->dataShort, $decrypt); // tear down - $view->unlink( $filename ); + $view->unlink($filename); } // function testEncryption(){ // @@ -912,5 +947,5 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase { // $decrypted=OC_Encryption\Crypt::blockDecrypt($encrypted,$key,strlen($source)); // $this->assertEquals($decrypted,$source); // } - + } diff --git a/apps/files_encryption/tests/keymanager.php b/apps/files_encryption/tests/keymanager.php index 8ca8b0287e..334cc743f2 100644 --- a/apps/files_encryption/tests/keymanager.php +++ b/apps/files_encryption/tests/keymanager.php @@ -6,21 +6,22 @@ * See the COPYING-README file. */ -require_once realpath( dirname(__FILE__).'/../../../lib/base.php' ); -require_once realpath( dirname(__FILE__).'/../lib/crypt.php' ); -require_once realpath( dirname(__FILE__).'/../lib/keymanager.php' ); -require_once realpath( dirname(__FILE__).'/../lib/proxy.php' ); -require_once realpath( dirname(__FILE__).'/../lib/stream.php' ); -require_once realpath( dirname(__FILE__).'/../lib/util.php' ); -require_once realpath( dirname(__FILE__).'/../lib/helper.php' ); -require_once realpath( dirname(__FILE__).'/../appinfo/app.php' ); +require_once realpath(dirname(__FILE__) . '/../../../lib/base.php'); +require_once realpath(dirname(__FILE__) . '/../lib/crypt.php'); +require_once realpath(dirname(__FILE__) . '/../lib/keymanager.php'); +require_once realpath(dirname(__FILE__) . '/../lib/proxy.php'); +require_once realpath(dirname(__FILE__) . '/../lib/stream.php'); +require_once realpath(dirname(__FILE__) . '/../lib/util.php'); +require_once realpath(dirname(__FILE__) . '/../lib/helper.php'); +require_once realpath(dirname(__FILE__) . '/../appinfo/app.php'); use OCA\Encryption; /** * Class Test_Encryption_Keymanager */ -class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase { +class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase +{ public $userId; public $pass; @@ -31,38 +32,39 @@ class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase { public $view; public $randomKey; - function setUp() { - // reset backend - \OC_User::clearBackends(); - \OC_User::useBackend('database'); + function setUp() + { + // reset backend + \OC_User::clearBackends(); + \OC_User::useBackend('database'); \OC_FileProxy::$enabled = false; - + // set content for encrypting / decrypting in tests - $this->dataLong = file_get_contents( realpath( dirname(__FILE__).'/../lib/crypt.php' ) ); + $this->dataLong = file_get_contents(realpath(dirname(__FILE__) . '/../lib/crypt.php')); $this->dataShort = 'hats'; - $this->dataUrl = realpath( dirname(__FILE__).'/../lib/crypt.php' ); - $this->legacyData = realpath( dirname(__FILE__).'/legacy-text.txt' ); - $this->legacyEncryptedData = realpath( dirname(__FILE__).'/legacy-encrypted-text.txt' ); + $this->dataUrl = realpath(dirname(__FILE__) . '/../lib/crypt.php'); + $this->legacyData = realpath(dirname(__FILE__) . '/legacy-text.txt'); + $this->legacyEncryptedData = realpath(dirname(__FILE__) . '/legacy-encrypted-text.txt'); $this->randomKey = Encryption\Crypt::generateKey(); - + $keypair = Encryption\Crypt::createKeypair(); - $this->genPublicKey = $keypair['publicKey']; + $this->genPublicKey = $keypair['publicKey']; $this->genPrivateKey = $keypair['privateKey']; - $this->view = new \OC_FilesystemView( '/' ); + $this->view = new \OC_FilesystemView('/'); - \OC_User::setUserId( 'admin' ); - $this->userId = 'admin'; - $this->pass = 'admin'; + \OC_User::setUserId('admin'); + $this->userId = 'admin'; + $this->pass = 'admin'; - $userHome = \OC_User::getHome($this->userId); - $this->dataDir = str_replace('/'.$this->userId, '', $userHome); + $userHome = \OC_User::getHome($this->userId); + $this->dataDir = str_replace('/' . $this->userId, '', $userHome); - // Filesystem related hooks - \OCA\Encryption\Helper::registerFilesystemHooks(); + // Filesystem related hooks + \OCA\Encryption\Helper::registerFilesystemHooks(); - \OC_FileProxy::register(new OCA\Encryption\Proxy()); + \OC_FileProxy::register(new OCA\Encryption\Proxy()); // remember files_trashbin state $this->stateFilesTrashbin = OC_App::isEnabled('files_trashbin'); @@ -70,19 +72,20 @@ class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase { // we don't want to tests with app files_trashbin enabled \OC_App::disable('files_trashbin'); - \OC_Util::tearDownFS(); - \OC_User::setUserId(''); - \OC\Files\Filesystem::tearDown(); - \OC_Util::setupFS($this->userId); - \OC_User::setUserId($this->userId); + \OC_Util::tearDownFS(); + \OC_User::setUserId(''); + \OC\Files\Filesystem::tearDown(); + \OC_Util::setupFS($this->userId); + \OC_User::setUserId($this->userId); - $params['uid'] = $this->userId; - $params['password'] = $this->pass; - OCA\Encryption\Hooks::login($params); + $params['uid'] = $this->userId; + $params['password'] = $this->pass; + OCA\Encryption\Hooks::login($params); } - - function tearDown(){ - + + function tearDown() + { + \OC_FileProxy::$enabled = true; \OC_FileProxy::clearProxies(); @@ -94,11 +97,12 @@ class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase { } } - function testGetPrivateKey() { - - $key = Encryption\Keymanager::getPrivateKey( $this->view, $this->userId ); + function testGetPrivateKey() + { - $privateKey = Encryption\Crypt::symmetricDecryptFileContent( $key, $this->pass); + $key = Encryption\Keymanager::getPrivateKey($this->view, $this->userId); + + $privateKey = Encryption\Crypt::symmetricDecryptFileContent($key, $this->pass); $res = openssl_pkey_get_private($privateKey); @@ -107,12 +111,13 @@ class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase { $sslInfo = openssl_pkey_get_details($res); $this->assertArrayHasKey('key', $sslInfo); - - } - - function testGetPublicKey() { - $publiceKey = Encryption\Keymanager::getPublicKey( $this->view, $this->userId ); + } + + function testGetPublicKey() + { + + $publiceKey = Encryption\Keymanager::getPublicKey($this->view, $this->userId); $res = openssl_pkey_get_public($publiceKey); @@ -122,40 +127,41 @@ class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase { $this->assertArrayHasKey('key', $sslInfo); } - - function testSetFileKey() { - + + function testSetFileKey() + { + # NOTE: This cannot be tested until we are able to break out # of the FileSystemView data directory root - - $key = Encryption\Crypt::symmetricEncryptFileContentKeyfile( $this->randomKey, 'hat' ); - - $file = 'unittest-'.time().'.txt'; - // Disable encryption proxy to prevent recursive calls - $proxyStatus = \OC_FileProxy::$enabled; - \OC_FileProxy::$enabled = false; + $key = Encryption\Crypt::symmetricEncryptFileContentKeyfile($this->randomKey, 'hat'); - $this->view->file_put_contents($this->userId . '/files/' . $file, $key['encrypted']); + $file = 'unittest-' . time() . '.txt'; - // Re-enable proxy - our work is done - \OC_FileProxy::$enabled = $proxyStatus; + // Disable encryption proxy to prevent recursive calls + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; + + $this->view->file_put_contents($this->userId . '/files/' . $file, $key['encrypted']); + + // Re-enable proxy - our work is done + \OC_FileProxy::$enabled = $proxyStatus; //$view = new \OC_FilesystemView( '/' . $this->userId . '/files_encryption/keyfiles' ); - Encryption\Keymanager::setFileKey( $this->view, $file, $this->userId, $key['key'] ); + Encryption\Keymanager::setFileKey($this->view, $file, $this->userId, $key['key']); // Disable encryption proxy to prevent recursive calls $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = true; // cleanup - $this->view->unlink('/'.$this->userId . '/files/' . $file); + $this->view->unlink('/' . $this->userId . '/files/' . $file); // Re-enable proxy - our work is done \OC_FileProxy::$enabled = $proxyStatus; - + } - + // /** // * @depends testGetPrivateKey // */ @@ -171,10 +177,11 @@ class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase { // $this->assertEquals( '-----BEGIN PRIVATE KEY-----', substr( $decrypted, 0, 27 ) ); // // } - - function testGetUserKeys() { - - $keys = Encryption\Keymanager::getUserKeys( $this->view, $this->userId ); + + function testGetUserKeys() + { + + $keys = Encryption\Keymanager::getUserKeys($this->view, $this->userId); $resPublic = openssl_pkey_get_public($keys['publicKey']); @@ -184,7 +191,7 @@ class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase { $this->assertArrayHasKey('key', $sslInfoPublic); - $privateKey = Encryption\Crypt::symmetricDecryptFileContent( $keys['privateKey'], $this->pass); + $privateKey = Encryption\Crypt::symmetricDecryptFileContent($keys['privateKey'], $this->pass); $resPrivate = openssl_pkey_get_private($privateKey); diff --git a/apps/files_encryption/tests/share.php b/apps/files_encryption/tests/share.php index efff8e322e..a9ee8d0023 100755 --- a/apps/files_encryption/tests/share.php +++ b/apps/files_encryption/tests/share.php @@ -50,446 +50,446 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase public $subsubfolder; function setUp() - { - // reset backend - \OC_User::clearBackends(); - \OC_User::useBackend('database'); + { + // reset backend + \OC_User::clearBackends(); + \OC_User::useBackend('database'); - $this->dataShort = 'hats'; - $this->view = new \OC_FilesystemView('/'); + $this->dataShort = 'hats'; + $this->view = new \OC_FilesystemView('/'); - $userHome = \OC_User::getHome('admin'); - $this->dataDir = str_replace('/admin', '', $userHome); + $userHome = \OC_User::getHome('admin'); + $this->dataDir = str_replace('/admin', '', $userHome); - $this->folder1 = '/folder1'; - $this->subfolder = '/subfolder1'; - $this->subsubfolder = '/subsubfolder1'; + $this->folder1 = '/folder1'; + $this->subfolder = '/subfolder1'; + $this->subsubfolder = '/subsubfolder1'; - $this->filename = 'share-tmp.test'; + $this->filename = 'share-tmp.test'; - // enable resharing - \OC_Appconfig::setValue('core', 'shareapi_allow_resharing', 'yes'); + // enable resharing + \OC_Appconfig::setValue('core', 'shareapi_allow_resharing', 'yes'); - // clear share hooks - \OC_Hook::clear('OCP\\Share'); - \OC::registerShareHooks(); - \OCP\Util::connectHook('OC_Filesystem', 'setup', '\OC\Files\Storage\Shared', 'setup'); + // clear share hooks + \OC_Hook::clear('OCP\\Share'); + \OC::registerShareHooks(); + \OCP\Util::connectHook('OC_Filesystem', 'setup', '\OC\Files\Storage\Shared', 'setup'); - // Sharing related hooks - \OCA\Encryption\Helper::registerShareHooks(); + // Sharing related hooks + \OCA\Encryption\Helper::registerShareHooks(); - // Filesystem related hooks - \OCA\Encryption\Helper::registerFilesystemHooks(); + // Filesystem related hooks + \OCA\Encryption\Helper::registerFilesystemHooks(); - \OC_FileProxy::register(new OCA\Encryption\Proxy()); + \OC_FileProxy::register(new OCA\Encryption\Proxy()); - // remember files_trashbin state - $this->stateFilesTrashbin = OC_App::isEnabled('files_trashbin'); + // remember files_trashbin state + $this->stateFilesTrashbin = OC_App::isEnabled('files_trashbin'); - // we don't want to tests with app files_trashbin enabled - \OC_App::disable('files_trashbin'); + // we don't want to tests with app files_trashbin enabled + \OC_App::disable('files_trashbin'); - // create users - $this->loginHelper('user1', true); - $this->loginHelper('user2', true); - $this->loginHelper('user3', true); + // create users + $this->loginHelper('user1', true); + $this->loginHelper('user2', true); + $this->loginHelper('user3', true); // create group and assign users \OC_Group::createGroup('group1'); \OC_Group::addToGroup('user2', 'group1'); \OC_Group::addToGroup('user3', 'group1'); - } + } - function tearDown() - { - // reset app files_trashbin - if ($this->stateFilesTrashbin) { - OC_App::enable('files_trashbin'); - } else { - OC_App::disable('files_trashbin'); - } + function tearDown() + { + // reset app files_trashbin + if ($this->stateFilesTrashbin) { + OC_App::enable('files_trashbin'); + } else { + OC_App::disable('files_trashbin'); + } // clean group \OC_Group::deleteGroup('group1'); - // cleanup users - \OC_User::deleteUser('user1'); - \OC_User::deleteUser('user2'); - \OC_User::deleteUser('user3'); + // cleanup users + \OC_User::deleteUser('user1'); + \OC_User::deleteUser('user2'); + \OC_User::deleteUser('user3'); \OC_FileProxy::clearProxies(); - } + } /** * @param bool $withTeardown */ function testShareFile($withTeardown = true) - { - // login as admin - $this->loginHelper('admin'); + { + // login as admin + $this->loginHelper('admin'); - // save file with content - $cryptedFile = file_put_contents('crypt://' . $this->filename, $this->dataShort); + // save file with content + $cryptedFile = file_put_contents('crypt://' . $this->filename, $this->dataShort); - // test that data was successfully written - $this->assertTrue(is_int($cryptedFile)); + // test that data was successfully written + $this->assertTrue(is_int($cryptedFile)); - // disable encryption proxy to prevent recursive calls - $proxyStatus = \OC_FileProxy::$enabled; - \OC_FileProxy::$enabled = false; + // disable encryption proxy to prevent recursive calls + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; - // get the file info from previous created file - $fileInfo = $this->view->getFileInfo('/admin/files/' . $this->filename); + // get the file info from previous created file + $fileInfo = $this->view->getFileInfo('/admin/files/' . $this->filename); - // check if we have a valid file info - $this->assertTrue(is_array($fileInfo)); + // check if we have a valid file info + $this->assertTrue(is_array($fileInfo)); - // check if the unencrypted file size is stored - $this->assertGreaterThan(0, $fileInfo['unencrypted_size']); + // check if the unencrypted file size is stored + $this->assertGreaterThan(0, $fileInfo['unencrypted_size']); - // re-enable the file proxy - \OC_FileProxy::$enabled = $proxyStatus; + // re-enable the file proxy + \OC_FileProxy::$enabled = $proxyStatus; - // share the file - \OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user1', OCP\PERMISSION_ALL); + // share the file + \OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user1', OCP\PERMISSION_ALL); - // login as admin - $this->loginHelper('admin'); + // login as admin + $this->loginHelper('admin'); - // check if share key for user1 exists - $this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.user1.shareKey')); + // check if share key for user1 exists + $this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.user1.shareKey')); - // login as user1 - $this->loginHelper('user1'); + // login as user1 + $this->loginHelper('user1'); - // get file contents - $retrievedCryptedFile = $this->view->file_get_contents('/user1/files/Shared/' . $this->filename); + // get file contents + $retrievedCryptedFile = $this->view->file_get_contents('/user1/files/Shared/' . $this->filename); - // check if data is the same as we previously written - $this->assertEquals($this->dataShort, $retrievedCryptedFile); + // check if data is the same as we previously written + $this->assertEquals($this->dataShort, $retrievedCryptedFile); - // cleanup - if ($withTeardown) { + // cleanup + if ($withTeardown) { - // login as admin - $this->loginHelper('admin'); + // login as admin + $this->loginHelper('admin'); - // unshare the file - \OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user1'); + // unshare the file + \OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user1'); - // check if share key not exists - $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.user1.shareKey')); + // check if share key not exists + $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.user1.shareKey')); - // cleanup - $this->view->unlink('/admin/files/' . $this->filename); + // cleanup + $this->view->unlink('/admin/files/' . $this->filename); - // check if share key not exists - $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.admin.shareKey')); - } - } + // check if share key not exists + $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.admin.shareKey')); + } + } /** * @param bool $withTeardown */ function testReShareFile($withTeardown = true) - { - $this->testShareFile(false); + { + $this->testShareFile(false); - // login as user1 - $this->loginHelper('user1'); + // login as user1 + $this->loginHelper('user1'); - // get the file info - $fileInfo = $this->view->getFileInfo('/user1/files/Shared/' . $this->filename); + // get the file info + $fileInfo = $this->view->getFileInfo('/user1/files/Shared/' . $this->filename); - // share the file with user2 - \OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user2', OCP\PERMISSION_ALL); + // share the file with user2 + \OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user2', OCP\PERMISSION_ALL); - // login as admin - $this->loginHelper('admin'); + // login as admin + $this->loginHelper('admin'); - // check if share key for user2 exists - $this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.user2.shareKey')); + // check if share key for user2 exists + $this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.user2.shareKey')); - // login as user2 - $this->loginHelper('user2'); + // login as user2 + $this->loginHelper('user2'); - // get file contents - $retrievedCryptedFile = $this->view->file_get_contents('/user2/files/Shared/' . $this->filename); + // get file contents + $retrievedCryptedFile = $this->view->file_get_contents('/user2/files/Shared/' . $this->filename); - // check if data is the same as previously written - $this->assertEquals($this->dataShort, $retrievedCryptedFile); + // check if data is the same as previously written + $this->assertEquals($this->dataShort, $retrievedCryptedFile); - // cleanup - if ($withTeardown) { + // cleanup + if ($withTeardown) { - // login as user1 - $this->loginHelper('user1'); + // login as user1 + $this->loginHelper('user1'); - // unshare the file with user2 - \OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user2'); + // unshare the file with user2 + \OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user2'); - // login as admin - $this->loginHelper('admin'); + // login as admin + $this->loginHelper('admin'); - // check if share key not exists - $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.user2.shareKey')); + // check if share key not exists + $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.user2.shareKey')); - // unshare the file with user1 - \OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user1'); + // unshare the file with user1 + \OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user1'); - // check if share key not exists - $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.user1.shareKey')); + // check if share key not exists + $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.user1.shareKey')); - // cleanup - $this->view->unlink('/admin/files/' . $this->filename); + // cleanup + $this->view->unlink('/admin/files/' . $this->filename); - // check if share key not exists - $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.admin.shareKey')); - } - } + // check if share key not exists + $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.admin.shareKey')); + } + } /** * @param bool $withTeardown * @return array */ function testShareFolder($withTeardown = true) - { - // login as admin - $this->loginHelper('admin'); + { + // login as admin + $this->loginHelper('admin'); - // create folder structure - $this->view->mkdir('/admin/files' . $this->folder1); - $this->view->mkdir('/admin/files' . $this->folder1 . $this->subfolder); - $this->view->mkdir('/admin/files' . $this->folder1 . $this->subfolder . $this->subsubfolder); + // create folder structure + $this->view->mkdir('/admin/files' . $this->folder1); + $this->view->mkdir('/admin/files' . $this->folder1 . $this->subfolder); + $this->view->mkdir('/admin/files' . $this->folder1 . $this->subfolder . $this->subsubfolder); - // save file with content - $cryptedFile = file_put_contents('crypt://' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename, $this->dataShort); + // save file with content + $cryptedFile = file_put_contents('crypt://' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename, $this->dataShort); - // test that data was successfully written - $this->assertTrue(is_int($cryptedFile)); + // test that data was successfully written + $this->assertTrue(is_int($cryptedFile)); - // disable encryption proxy to prevent recursive calls - $proxyStatus = \OC_FileProxy::$enabled; - \OC_FileProxy::$enabled = false; + // disable encryption proxy to prevent recursive calls + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; - // get the file info from previous created folder - $fileInfo = $this->view->getFileInfo('/admin/files' . $this->folder1); + // get the file info from previous created folder + $fileInfo = $this->view->getFileInfo('/admin/files' . $this->folder1); - // check if we have a valid file info - $this->assertTrue(is_array($fileInfo)); + // check if we have a valid file info + $this->assertTrue(is_array($fileInfo)); - // re-enable the file proxy - \OC_FileProxy::$enabled = $proxyStatus; + // re-enable the file proxy + \OC_FileProxy::$enabled = $proxyStatus; - // share the folder with user1 - \OCP\Share::shareItem('folder', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user1', OCP\PERMISSION_ALL); + // share the folder with user1 + \OCP\Share::shareItem('folder', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user1', OCP\PERMISSION_ALL); - // login as admin - $this->loginHelper('admin'); + // login as admin + $this->loginHelper('admin'); - // check if share key for user1 exists - $this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.user1.shareKey')); + // check if share key for user1 exists + $this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.user1.shareKey')); - // login as user1 - $this->loginHelper('user1'); + // login as user1 + $this->loginHelper('user1'); - // get file contents - $retrievedCryptedFile = $this->view->file_get_contents('/user1/files/Shared' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename); + // get file contents + $retrievedCryptedFile = $this->view->file_get_contents('/user1/files/Shared' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename); - // check if data is the same - $this->assertEquals($this->dataShort, $retrievedCryptedFile); + // check if data is the same + $this->assertEquals($this->dataShort, $retrievedCryptedFile); - // cleanup - if ($withTeardown) { + // cleanup + if ($withTeardown) { - // login as admin - $this->loginHelper('admin'); + // login as admin + $this->loginHelper('admin'); - // unshare the folder with user1 - \OCP\Share::unshare('folder', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user1'); + // unshare the folder with user1 + \OCP\Share::unshare('folder', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user1'); - // check if share key not exists - $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.user1.shareKey')); + // check if share key not exists + $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.user1.shareKey')); - // cleanup - $this->view->unlink('/admin/files' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename); + // cleanup + $this->view->unlink('/admin/files' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename); - // check if share key not exists - $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.admin.shareKey')); - } + // check if share key not exists + $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.admin.shareKey')); + } - return $fileInfo; - } + return $fileInfo; + } /** * @param bool $withTeardown */ function testReShareFolder($withTeardown = true) - { - $fileInfoFolder1 = $this->testShareFolder(false); + { + $fileInfoFolder1 = $this->testShareFolder(false); - // login as user1 - $this->loginHelper('user1'); + // login as user1 + $this->loginHelper('user1'); - // disable encryption proxy to prevent recursive calls - $proxyStatus = \OC_FileProxy::$enabled; - \OC_FileProxy::$enabled = false; + // disable encryption proxy to prevent recursive calls + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; - // get the file info from previous created folder - $fileInfoSubFolder = $this->view->getFileInfo('/user1/files/Shared' . $this->folder1 . $this->subfolder); + // get the file info from previous created folder + $fileInfoSubFolder = $this->view->getFileInfo('/user1/files/Shared' . $this->folder1 . $this->subfolder); - // check if we have a valid file info - $this->assertTrue(is_array($fileInfoSubFolder)); + // check if we have a valid file info + $this->assertTrue(is_array($fileInfoSubFolder)); - // re-enable the file proxy - \OC_FileProxy::$enabled = $proxyStatus; + // re-enable the file proxy + \OC_FileProxy::$enabled = $proxyStatus; - // share the file with user2 - \OCP\Share::shareItem('folder', $fileInfoSubFolder['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user2', OCP\PERMISSION_ALL); + // share the file with user2 + \OCP\Share::shareItem('folder', $fileInfoSubFolder['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user2', OCP\PERMISSION_ALL); - // login as admin - $this->loginHelper('admin'); + // login as admin + $this->loginHelper('admin'); - // check if share key for user2 exists - $this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.user2.shareKey')); + // check if share key for user2 exists + $this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.user2.shareKey')); - // login as user2 - $this->loginHelper('user2'); + // login as user2 + $this->loginHelper('user2'); - // get file contents - $retrievedCryptedFile = $this->view->file_get_contents('/user2/files/Shared' . $this->subfolder . $this->subsubfolder . '/' . $this->filename); + // get file contents + $retrievedCryptedFile = $this->view->file_get_contents('/user2/files/Shared' . $this->subfolder . $this->subsubfolder . '/' . $this->filename); - // check if data is the same - $this->assertEquals($this->dataShort, $retrievedCryptedFile); + // check if data is the same + $this->assertEquals($this->dataShort, $retrievedCryptedFile); - // get the file info - $fileInfo = $this->view->getFileInfo('/user2/files/Shared' . $this->subfolder . $this->subsubfolder . '/' . $this->filename); + // get the file info + $fileInfo = $this->view->getFileInfo('/user2/files/Shared' . $this->subfolder . $this->subsubfolder . '/' . $this->filename); - // check if we have fileInfos - $this->assertTrue(is_array($fileInfo)); + // check if we have fileInfos + $this->assertTrue(is_array($fileInfo)); - // share the file with user3 - \OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user3', OCP\PERMISSION_ALL); + // share the file with user3 + \OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user3', OCP\PERMISSION_ALL); - // login as admin - $this->loginHelper('admin'); + // login as admin + $this->loginHelper('admin'); - // check if share key for user3 exists - $this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.user3.shareKey')); + // check if share key for user3 exists + $this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.user3.shareKey')); - // login as user3 - $this->loginHelper('user3'); + // login as user3 + $this->loginHelper('user3'); - // get file contents - $retrievedCryptedFile = $this->view->file_get_contents('/user3/files/Shared/' . $this->filename); + // get file contents + $retrievedCryptedFile = $this->view->file_get_contents('/user3/files/Shared/' . $this->filename); - // check if data is the same - $this->assertEquals($this->dataShort, $retrievedCryptedFile); + // check if data is the same + $this->assertEquals($this->dataShort, $retrievedCryptedFile); - // cleanup - if ($withTeardown) { + // cleanup + if ($withTeardown) { - // login as user2 - $this->loginHelper('user2'); + // login as user2 + $this->loginHelper('user2'); - // unshare the file with user3 - \OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user3'); + // unshare the file with user3 + \OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user3'); - // check if share key not exists - $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.user3.shareKey')); + // check if share key not exists + $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.user3.shareKey')); - // login as user1 - $this->loginHelper('user1'); + // login as user1 + $this->loginHelper('user1'); - // unshare the folder with user2 - \OCP\Share::unshare('folder', $fileInfoSubFolder['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user2'); + // unshare the folder with user2 + \OCP\Share::unshare('folder', $fileInfoSubFolder['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user2'); - // check if share key not exists - $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.user2.shareKey')); + // check if share key not exists + $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.user2.shareKey')); - // login as admin - $this->loginHelper('admin'); + // login as admin + $this->loginHelper('admin'); - // unshare the folder1 with user1 - \OCP\Share::unshare('folder', $fileInfoFolder1['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user1'); + // unshare the folder1 with user1 + \OCP\Share::unshare('folder', $fileInfoFolder1['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user1'); - // check if share key not exists - $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.user1.shareKey')); + // check if share key not exists + $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.user1.shareKey')); - // cleanup - $this->view->unlink('/admin/files' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename); + // cleanup + $this->view->unlink('/admin/files' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename); - // check if share key not exists - $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.admin.shareKey')); - } - } + // check if share key not exists + $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.admin.shareKey')); + } + } - function testPublicShareFile() - { - // login as admin - $this->loginHelper('admin'); + function testPublicShareFile() + { + // login as admin + $this->loginHelper('admin'); - // save file with content - $cryptedFile = file_put_contents('crypt://' . $this->filename, $this->dataShort); + // save file with content + $cryptedFile = file_put_contents('crypt://' . $this->filename, $this->dataShort); - // test that data was successfully written - $this->assertTrue(is_int($cryptedFile)); + // test that data was successfully written + $this->assertTrue(is_int($cryptedFile)); - // disable encryption proxy to prevent recursive calls - $proxyStatus = \OC_FileProxy::$enabled; - \OC_FileProxy::$enabled = false; + // disable encryption proxy to prevent recursive calls + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; - // get the file info from previous created file - $fileInfo = $this->view->getFileInfo('/admin/files/' . $this->filename); + // get the file info from previous created file + $fileInfo = $this->view->getFileInfo('/admin/files/' . $this->filename); - // check if we have a valid file info - $this->assertTrue(is_array($fileInfo)); + // check if we have a valid file info + $this->assertTrue(is_array($fileInfo)); - // check if the unencrypted file size is stored - $this->assertGreaterThan(0, $fileInfo['unencrypted_size']); + // check if the unencrypted file size is stored + $this->assertGreaterThan(0, $fileInfo['unencrypted_size']); - // re-enable the file proxy - \OC_FileProxy::$enabled = $proxyStatus; + // re-enable the file proxy + \OC_FileProxy::$enabled = $proxyStatus; - // share the file - \OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_LINK, false, OCP\PERMISSION_ALL); + // share the file + \OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_LINK, false, OCP\PERMISSION_ALL); - // login as admin - $this->loginHelper('admin'); + // login as admin + $this->loginHelper('admin'); - $publicShareKeyId = \OC_Appconfig::getValue('files_encryption', 'publicShareKeyId'); + $publicShareKeyId = \OC_Appconfig::getValue('files_encryption', 'publicShareKeyId'); - // check if share key for public exists - $this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.' . $publicShareKeyId . '.shareKey')); + // check if share key for public exists + $this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.' . $publicShareKeyId . '.shareKey')); - // some hacking to simulate public link - $GLOBALS['app'] = 'files_sharing'; - $GLOBALS['fileOwner'] = 'admin'; - \OC_User::setUserId(''); + // some hacking to simulate public link + $GLOBALS['app'] = 'files_sharing'; + $GLOBALS['fileOwner'] = 'admin'; + \OC_User::setUserId(''); - // get file contents - $retrievedCryptedFile = file_get_contents('crypt://' . $this->filename); + // get file contents + $retrievedCryptedFile = file_get_contents('crypt://' . $this->filename); - // check if data is the same as we previously written - $this->assertEquals($this->dataShort, $retrievedCryptedFile); + // check if data is the same as we previously written + $this->assertEquals($this->dataShort, $retrievedCryptedFile); - // tear down + // tear down - // login as admin - $this->loginHelper('admin'); + // login as admin + $this->loginHelper('admin'); - // unshare the file - \OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_LINK, null); + // unshare the file + \OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_LINK, null); - // check if share key not exists - $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.' . $publicShareKeyId . '.shareKey')); + // check if share key not exists + $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.' . $publicShareKeyId . '.shareKey')); - // cleanup - $this->view->unlink('/admin/files/' . $this->filename); + // cleanup + $this->view->unlink('/admin/files/' . $this->filename); - // check if share key not exists - $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.admin.shareKey')); - } + // check if share key not exists + $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.admin.shareKey')); + } function testShareFileWithGroup() { @@ -581,7 +581,7 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase // save file with content $cryptedFile1 = file_put_contents('crypt://' . $this->filename, $this->dataShort); - $cryptedFile2 = file_put_contents('crypt://' . $this->folder1 . $this->subfolder . $this->subsubfolder .'/'. $this->filename, $this->dataShort); + $cryptedFile2 = file_put_contents('crypt://' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename, $this->dataShort); // test that data was successfully written $this->assertTrue(is_int($cryptedFile1)); @@ -589,9 +589,9 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase // check if share key for admin and recovery exists $this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.admin.shareKey')); - $this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.'.$recoveryKeyId.'.shareKey')); - $this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder .'/'. $this->filename . '.admin.shareKey')); - $this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder .'/'. $this->filename . '.'.$recoveryKeyId.'.shareKey')); + $this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.' . $recoveryKeyId . '.shareKey')); + $this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.admin.shareKey')); + $this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.' . $recoveryKeyId . '.shareKey')); // disable recovery for admin $this->assertTrue($util->setRecoveryForUser(0)); @@ -600,8 +600,8 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase $util->removeRecoveryKeys('/'); // check if share key for recovery not exists - $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.'.$recoveryKeyId.'.shareKey')); - $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder .'/'. $this->filename . '.'.$recoveryKeyId.'.shareKey')); + $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.' . $recoveryKeyId . '.shareKey')); + $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.' . $recoveryKeyId . '.shareKey')); // enable recovery for admin $this->assertTrue($util->setRecoveryForUser(1)); @@ -610,16 +610,16 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase $util->addRecoveryKeys('/'); // check if share key for admin and recovery exists - $this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.'.$recoveryKeyId.'.shareKey')); - $this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder .'/'. $this->filename . '.'.$recoveryKeyId.'.shareKey')); + $this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.' . $recoveryKeyId . '.shareKey')); + $this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.' . $recoveryKeyId . '.shareKey')); // cleanup $this->view->unlink('/admin/files/' . $this->filename); - $this->view->unlink('/admin/files/' . $this->folder1 . $this->subfolder . $this->subsubfolder .'/'. $this->filename); + $this->view->unlink('/admin/files/' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename); // check if share key for recovery not exists - $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.'.$recoveryKeyId.'.shareKey')); - $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder .'/'. $this->filename . '.'.$recoveryKeyId.'.shareKey')); + $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.' . $recoveryKeyId . '.shareKey')); + $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.' . $recoveryKeyId . '.shareKey')); } function testRecoveryForUser() @@ -648,7 +648,7 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase // save file with content $cryptedFile1 = file_put_contents('crypt://' . $this->filename, $this->dataShort); - $cryptedFile2 = file_put_contents('crypt://' . $this->folder1 . $this->subfolder . $this->subsubfolder .'/'. $this->filename, $this->dataShort); + $cryptedFile2 = file_put_contents('crypt://' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename, $this->dataShort); // test that data was successfully written $this->assertTrue(is_int($cryptedFile1)); @@ -656,9 +656,9 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase // check if share key for user and recovery exists $this->assertTrue($this->view->file_exists('/user1/files_encryption/share-keys/' . $this->filename . '.user1.shareKey')); - $this->assertTrue($this->view->file_exists('/user1/files_encryption/share-keys/' . $this->filename . '.'.$recoveryKeyId.'.shareKey')); - $this->assertTrue($this->view->file_exists('/user1/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder .'/'. $this->filename . '.user1.shareKey')); - $this->assertTrue($this->view->file_exists('/user1/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder .'/'. $this->filename . '.'.$recoveryKeyId.'.shareKey')); + $this->assertTrue($this->view->file_exists('/user1/files_encryption/share-keys/' . $this->filename . '.' . $recoveryKeyId . '.shareKey')); + $this->assertTrue($this->view->file_exists('/user1/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.user1.shareKey')); + $this->assertTrue($this->view->file_exists('/user1/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.' . $recoveryKeyId . '.shareKey')); // login as admin $this->loginHelper('admin'); @@ -671,7 +671,7 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase // get file contents $retrievedCryptedFile1 = file_get_contents('crypt://' . $this->filename); - $retrievedCryptedFile2 = file_get_contents('crypt://' . $this->folder1 . $this->subfolder . $this->subsubfolder .'/'. $this->filename); + $retrievedCryptedFile2 = file_get_contents('crypt://' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename); // check if data is the same as we previously written $this->assertEquals($this->dataShort, $retrievedCryptedFile1); @@ -683,9 +683,9 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase // check if share key for user and recovery exists $this->assertFalse($this->view->file_exists('/user1/files_encryption/share-keys/' . $this->filename . '.user1.shareKey')); - $this->assertFalse($this->view->file_exists('/user1/files_encryption/share-keys/' . $this->filename . '.'.$recoveryKeyId.'.shareKey')); - $this->assertFalse($this->view->file_exists('/user1/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder .'/'. $this->filename . '.user1.shareKey')); - $this->assertFalse($this->view->file_exists('/user1/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder .'/'. $this->filename . '.'.$recoveryKeyId.'.shareKey')); + $this->assertFalse($this->view->file_exists('/user1/files_encryption/share-keys/' . $this->filename . '.' . $recoveryKeyId . '.shareKey')); + $this->assertFalse($this->view->file_exists('/user1/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.user1.shareKey')); + $this->assertFalse($this->view->file_exists('/user1/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.' . $recoveryKeyId . '.shareKey')); // enable recovery for admin $this->assertTrue($util->setRecoveryForUser(0)); @@ -697,23 +697,23 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase * @param bool $password */ function loginHelper($user, $create = false, $password = false) - { - if ($create) { - \OC_User::createUser($user, $user); - } + { + if ($create) { + \OC_User::createUser($user, $user); + } - if($password === false) { + if ($password === false) { $password = $user; } - \OC_Util::tearDownFS(); - \OC_User::setUserId(''); - \OC\Files\Filesystem::tearDown(); - \OC_Util::setupFS($user); - \OC_User::setUserId($user); + \OC_Util::tearDownFS(); + \OC_User::setUserId(''); + \OC\Files\Filesystem::tearDown(); + \OC_Util::setupFS($user); + \OC_User::setUserId($user); - $params['uid'] = $user; - $params['password'] = $password; - OCA\Encryption\Hooks::login($params); - } + $params['uid'] = $user; + $params['password'] = $password; + OCA\Encryption\Hooks::login($params); + } } diff --git a/apps/files_encryption/tests/util.php b/apps/files_encryption/tests/util.php index 53ac8ee8d6..57ec395342 100755 --- a/apps/files_encryption/tests/util.php +++ b/apps/files_encryption/tests/util.php @@ -6,20 +6,21 @@ * See the COPYING-README file. */ -require_once realpath( dirname(__FILE__).'/../../../lib/base.php' ); -require_once realpath( dirname(__FILE__).'/../lib/crypt.php' ); -require_once realpath( dirname(__FILE__).'/../lib/keymanager.php' ); -require_once realpath( dirname(__FILE__).'/../lib/proxy.php' ); -require_once realpath( dirname(__FILE__).'/../lib/stream.php' ); -require_once realpath( dirname(__FILE__).'/../lib/util.php' ); -require_once realpath( dirname(__FILE__).'/../appinfo/app.php' ); +require_once realpath(dirname(__FILE__) . '/../../../lib/base.php'); +require_once realpath(dirname(__FILE__) . '/../lib/crypt.php'); +require_once realpath(dirname(__FILE__) . '/../lib/keymanager.php'); +require_once realpath(dirname(__FILE__) . '/../lib/proxy.php'); +require_once realpath(dirname(__FILE__) . '/../lib/stream.php'); +require_once realpath(dirname(__FILE__) . '/../lib/util.php'); +require_once realpath(dirname(__FILE__) . '/../appinfo/app.php'); use OCA\Encryption; /** * Class Test_Encryption_Util */ -class Test_Encryption_Util extends \PHPUnit_Framework_TestCase { +class Test_Encryption_Util extends \PHPUnit_Framework_TestCase +{ public $userId; public $encryptionDir; @@ -38,132 +39,139 @@ class Test_Encryption_Util extends \PHPUnit_Framework_TestCase { public $util; public $dataShort; - function setUp() { - // reset backend - \OC_User::useBackend('database'); + function setUp() + { + // reset backend + \OC_User::useBackend('database'); - \OC_User::setUserId( 'admin' ); - $this->userId = 'admin'; - $this->pass = 'admin'; + \OC_User::setUserId('admin'); + $this->userId = 'admin'; + $this->pass = 'admin'; - // set content for encrypting / decrypting in tests - $this->dataUrl = realpath( dirname(__FILE__).'/../lib/crypt.php' ); + // set content for encrypting / decrypting in tests + $this->dataUrl = realpath(dirname(__FILE__) . '/../lib/crypt.php'); $this->dataShort = 'hats'; - $this->dataLong = file_get_contents( realpath( dirname(__FILE__).'/../lib/crypt.php' ) ); - $this->legacyData = realpath( dirname(__FILE__).'/legacy-text.txt' ); - $this->legacyEncryptedData = realpath( dirname(__FILE__).'/legacy-encrypted-text.txt' ); + $this->dataLong = file_get_contents(realpath(dirname(__FILE__) . '/../lib/crypt.php')); + $this->legacyData = realpath(dirname(__FILE__) . '/legacy-text.txt'); + $this->legacyEncryptedData = realpath(dirname(__FILE__) . '/legacy-encrypted-text.txt'); $keypair = Encryption\Crypt::createKeypair(); - - $this->genPublicKey = $keypair['publicKey']; + + $this->genPublicKey = $keypair['publicKey']; $this->genPrivateKey = $keypair['privateKey']; - - $this->publicKeyDir = '/' . 'public-keys'; - $this->encryptionDir = '/' . $this->userId . '/' . 'files_encryption'; + + $this->publicKeyDir = '/' . 'public-keys'; + $this->encryptionDir = '/' . $this->userId . '/' . 'files_encryption'; $this->keyfilesPath = $this->encryptionDir . '/' . 'keyfiles'; $this->publicKeyPath = $this->publicKeyDir . '/' . $this->userId . '.public.key'; // e.g. data/public-keys/admin.public.key $this->privateKeyPath = $this->encryptionDir . '/' . $this->userId . '.private.key'; // e.g. data/admin/admin.private.key - $this->view = new \OC_FilesystemView( '/' ); + $this->view = new \OC_FilesystemView('/'); - $userHome = \OC_User::getHome($this->userId); - $this->dataDir = str_replace('/'.$this->userId, '', $userHome); + $userHome = \OC_User::getHome($this->userId); + $this->dataDir = str_replace('/' . $this->userId, '', $userHome); - // Filesystem related hooks - \OCA\Encryption\Helper::registerFilesystemHooks(); + // Filesystem related hooks + \OCA\Encryption\Helper::registerFilesystemHooks(); - \OC_FileProxy::register(new OCA\Encryption\Proxy()); + \OC_FileProxy::register(new OCA\Encryption\Proxy()); - \OC_Util::tearDownFS(); - \OC_User::setUserId(''); - \OC\Files\Filesystem::tearDown(); - \OC_Util::setupFS($this->userId); - \OC_User::setUserId($this->userId); + \OC_Util::tearDownFS(); + \OC_User::setUserId(''); + \OC\Files\Filesystem::tearDown(); + \OC_Util::setupFS($this->userId); + \OC_User::setUserId($this->userId); - $params['uid'] = $this->userId; - $params['password'] = $this->pass; - OCA\Encryption\Hooks::login($params); + $params['uid'] = $this->userId; + $params['password'] = $this->pass; + OCA\Encryption\Hooks::login($params); - $this->util = new Encryption\Util( $this->view, $this->userId ); + $this->util = new Encryption\Util($this->view, $this->userId); } - - function tearDown(){ - + + function tearDown() + { + \OC_FileProxy::clearProxies(); } - + /** * @brief test that paths set during User construction are correct */ - function testKeyPaths() { - - $util = new Encryption\Util( $this->view, $this->userId ); - - $this->assertEquals( $this->publicKeyDir, $util->getPath( 'publicKeyDir' ) ); - $this->assertEquals( $this->encryptionDir, $util->getPath( 'encryptionDir' ) ); - $this->assertEquals( $this->keyfilesPath, $util->getPath( 'keyfilesPath' ) ); - $this->assertEquals( $this->publicKeyPath, $util->getPath( 'publicKeyPath' ) ); - $this->assertEquals( $this->privateKeyPath, $util->getPath( 'privateKeyPath' ) ); - + function testKeyPaths() + { + + $util = new Encryption\Util($this->view, $this->userId); + + $this->assertEquals($this->publicKeyDir, $util->getPath('publicKeyDir')); + $this->assertEquals($this->encryptionDir, $util->getPath('encryptionDir')); + $this->assertEquals($this->keyfilesPath, $util->getPath('keyfilesPath')); + $this->assertEquals($this->publicKeyPath, $util->getPath('publicKeyPath')); + $this->assertEquals($this->privateKeyPath, $util->getPath('privateKeyPath')); + } - + /** * @brief test setup of encryption directories */ - function testSetupServerSide() { - - $this->assertEquals( true, $this->util->setupServerSide( $this->pass ) ); + function testSetupServerSide() + { + + $this->assertEquals(true, $this->util->setupServerSide($this->pass)); } - + /** * @brief test checking whether account is ready for encryption, */ - function testUserIsReady() { - - $this->assertEquals( true, $this->util->ready() ); + function testUserIsReady() + { + + $this->assertEquals(true, $this->util->ready()); } - - function testRecoveryEnabledForUser() { - - $util = new Encryption\Util( $this->view, $this->userId ); - + + function testRecoveryEnabledForUser() + { + + $util = new Encryption\Util($this->view, $this->userId); + // Record the value so we can return it to it's original state later $enabled = $util->recoveryEnabledForUser(); - - $this->assertTrue( $util->setRecoveryForUser( 1 ) ); - - $this->assertEquals( 1, $util->recoveryEnabledForUser() ); - - $this->assertTrue( $util->setRecoveryForUser( 0 ) ); - - $this->assertEquals( 0, $util->recoveryEnabledForUser() ); - + + $this->assertTrue($util->setRecoveryForUser(1)); + + $this->assertEquals(1, $util->recoveryEnabledForUser()); + + $this->assertTrue($util->setRecoveryForUser(0)); + + $this->assertEquals(0, $util->recoveryEnabledForUser()); + // Return the setting to it's previous state - $this->assertTrue( $util->setRecoveryForUser( $enabled ) ); - + $this->assertTrue($util->setRecoveryForUser($enabled)); + } - - function testGetUidAndFilename() { - - \OC_User::setUserId( 'admin' ); - $filename = 'tmp-'.time().'.test'; + function testGetUidAndFilename() + { - // Disable encryption proxy to prevent recursive calls - $proxyStatus = \OC_FileProxy::$enabled; - \OC_FileProxy::$enabled = false; + \OC_User::setUserId('admin'); - $this->view->file_put_contents($this->userId . '/files/' . $filename, $this->dataShort); + $filename = 'tmp-' . time() . '.test'; - // Re-enable proxy - our work is done - \OC_FileProxy::$enabled = $proxyStatus; + // Disable encryption proxy to prevent recursive calls + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; - $util = new Encryption\Util( $this->view, $this->userId ); + $this->view->file_put_contents($this->userId . '/files/' . $filename, $this->dataShort); - list($fileOwnerUid, $file) = $util->getUidAndFilename( $filename ); + // Re-enable proxy - our work is done + \OC_FileProxy::$enabled = $proxyStatus; - $this->assertEquals('admin', $fileOwnerUid); + $util = new Encryption\Util($this->view, $this->userId); - $this->assertEquals($file, $filename); + list($fileOwnerUid, $file) = $util->getUidAndFilename($filename); + + $this->assertEquals('admin', $fileOwnerUid); + + $this->assertEquals($file, $filename); } } \ No newline at end of file