From c56fb905d1a300b2fe6c011848ea520031ea0df1 Mon Sep 17 00:00:00 2001 From: Sam Tuke Date: Wed, 5 Dec 2012 18:57:44 +0000 Subject: Development snapshot Read/write interoperability working through web UI and WebDAV New class Session for handling session data A few new unit tests Some additional unit tests are now failing, esp. legacy enc related ones --- apps/files_encryption/lib/crypt.php | 25 ++++++------ apps/files_encryption/lib/keymanager.php | 20 ++++++++-- apps/files_encryption/lib/proxy.php | 27 +++++++++---- apps/files_encryption/lib/session.php | 66 ++++++++++++++++++++++++++++++++ apps/files_encryption/lib/stream.php | 54 ++++++++++++++++++-------- apps/files_encryption/lib/util.php | 4 +- 6 files changed, 157 insertions(+), 39 deletions(-) create mode 100644 apps/files_encryption/lib/session.php (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/crypt.php b/apps/files_encryption/lib/crypt.php index 8df3cd43270..5e1078c9e1b 100755 --- a/apps/files_encryption/lib/crypt.php +++ b/apps/files_encryption/lib/crypt.php @@ -305,9 +305,9 @@ class Crypt { if ( $encryptedContent = self::encrypt( $plainContent, $iv, $passphrase ) ) { // Combine content to encrypt with IV identifier and actual IV - $combinedKeyfile = self::concatIv( $encryptedContent, $iv ); + $catfile = self::concatIv( $encryptedContent, $iv ); - $padded = self::addPadding( $combinedKeyfile ); + $padded = self::addPadding( $catfile ); return $padded; @@ -468,7 +468,8 @@ class Crypt { /** * @brief Encrypts content symmetrically and generates keyfile asymmetrically - * @returns array keys: encrypted, key + * @returns array containing catfile and new keyfile. + * keys: data, key * @note this method is a wrapper for combining other crypt class methods */ public static function keyEncryptKeyfile( $plainContent, $publicKey ) { @@ -484,18 +485,20 @@ class Crypt { } /** - * @brief Takes encrypted data, encrypted catfile, and private key, and + * @brief Takes catfile, keyfile, and private key, and * performs decryption * @returns decrypted content * @note this method is a wrapper for combining other crypt class methods */ - public static function keyDecryptKeyfile( $encryptedData, $encryptedKey, $privateKey ) { + public static function keyDecryptKeyfile( $catfile, $keyfile, $privateKey ) { - // Decrypt keyfile - $decryptedKey = self::keyDecrypt( $encryptedKey, $privateKey ); + // Decrypt the keyfile with the user's private key + $decryptedKey = self::keyDecrypt( $keyfile, $privateKey ); - // Decrypt encrypted file - $decryptedData = self::symmetricDecryptFileContent( $encryptedData, $decryptedKey ); +// trigger_error( "\$keyfile = ".var_export($keyfile, 1)); + + // Decrypt the catfile symmetrically using the decrypted keyfile + $decryptedData = self::symmetricDecryptFileContent( $catfile, $decryptedKey ); return $decryptedData; @@ -684,7 +687,7 @@ class Crypt { */ public static function legacyEncrypt( $content, $passphrase = '' ) { - trigger_error("OC2 enc \$content = $content \$passphrase = ".var_export($passphrase, 1) ); + //trigger_error("OC2 enc \$content = $content \$passphrase = ".var_export($passphrase, 1) ); $bf = self::getBlowfish( $passphrase ); @@ -708,7 +711,7 @@ class Crypt { $bf = self::getBlowfish( "67362885833455692562" ); - trigger_error(var_export($bf, 1) ); +// trigger_error(var_export($bf, 1) ); $decrypted = $bf->decrypt( $content ); diff --git a/apps/files_encryption/lib/keymanager.php b/apps/files_encryption/lib/keymanager.php index 02fb6acbaa1..9eb9bad3db4 100755 --- a/apps/files_encryption/lib/keymanager.php +++ b/apps/files_encryption/lib/keymanager.php @@ -46,11 +46,19 @@ class Keymanager { * @brief retrieve public key for a specified user * @return string public key or false */ - public static function getPublicKey() { + public static function getPublicKey( $userId = NULL ) { - $user = \OCP\User::getUser(); + // If the username wasn't specified, fetch it + if ( ! $userId ) { + + $userId = \OCP\User::getUser(); + + } + + // Create new view with the right $view = new \OC_FilesystemView( '/public-keys/' ); - return $view->file_get_contents( '/' . $user . '.public.key' ); + + return $view->file_get_contents( '/' . $userId . '.public.key' ); } @@ -119,10 +127,12 @@ class Keymanager { } /** - * @brief retrieve file encryption key + * @brief retrieve keyfile for an encrypted file * * @param string file name * @return string file key or false + * @note The keyfile returned is asymmetrically encrypted. Decryption + * of the keyfile must be performed by client code */ public static function getFileKey( $path, $staticUserClass = 'OCP\User' ) { @@ -228,6 +238,8 @@ class Keymanager { * @param string $path relative path of the file, including filename * @param string $key * @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 setFileKey( $path, $key, $view = Null, $dbClassName = '\OC_DB') { diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index 914632d3387..85664734d7a 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -131,6 +131,10 @@ class Proxy extends \OC_FileProxy { } + /** + * @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 ) { # TODO: Use dependency injection to add required args for view and user etc. to this method @@ -138,24 +142,27 @@ class Proxy extends \OC_FileProxy { // Disable encryption proxy to prevent recursive calls \OC_FileProxy::$enabled = false; + // If data is a catfile if ( Crypt::mode() == 'server' && Crypt::isEncryptedContent( $data ) ) { - //trigger_error("bong"); +// trigger_error("bong"); - $filePath = explode( '/', $path ); + $split = explode( '/', $path ); - $filePath = array_slice( $filePath, 3 ); + $filePath = array_slice( $split, 3 ); $filePath = '/' . implode( '/', $filePath ); //$cached = \OC_FileCache_Cached::get( $path, '' ); $keyFile = Keymanager::getFileKey( $filePath ); + + $session = new Session(); + + $decrypted = Crypt::keyDecryptKeyfile( $data, $keyFile, $session->getPrivateKey( $split[1] ) ); - $data = Crypt::keyDecryptKeyfile( $data, $keyFile, $_SESSION['enckey'] ); - } elseif ( Crypt::mode() == 'server' && isset( $_SESSION['legacyenckey'] ) @@ -163,14 +170,20 @@ class Proxy extends \OC_FileProxy { ) { trigger_error("mong"); - $data = Crypt::legacyDecrypt( $data, $_SESSION['legacyenckey'] ); + $decrypted = Crypt::legacyDecrypt( $data, $_SESSION['legacyenckey'] ); //trigger_error($data); } \OC_FileProxy::$enabled = true; - return $data; + if ( ! isset( $decrypted ) ) { + + $decrypted = $data; + + } + + return $decrypted; } diff --git a/apps/files_encryption/lib/session.php b/apps/files_encryption/lib/session.php new file mode 100644 index 00000000000..946e5a6eddd --- /dev/null +++ b/apps/files_encryption/lib/session.php @@ -0,0 +1,66 @@ +. + * + */ + +namespace OCA\Encryption; + +/** + * Class for handling encryption related session data + */ + +class Session { + + /** + * @brief Sets user id for session and triggers emit + * @return bool + * + */ + public static function setPrivateKey( $privateKey, $userId ) { + + $_SESSION['privateKey'] = $privateKey; + + return true; + + } + + /** + * @brief Gets user id for session and triggers emit + * @returns string $privateKey The user's plaintext private key + * + */ + public static function getPrivateKey( $userId ) { + + if ( + isset( $_SESSION['privateKey'] ) + && !empty( $_SESSION['privateKey'] ) + ) { + + return $_SESSION['privateKey']; + + } 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 74dff1531a9..ac5fadd4e03 100644 --- a/apps/files_encryption/lib/stream.php +++ b/apps/files_encryption/lib/stream.php @@ -59,7 +59,9 @@ class Stream { private $count; private $writeCache; public $size; + private $publicKey; private $keyfile; + private $encKeyfile; private static $view; public function stream_open( $path, $mode, $options, &$opened_path ) { @@ -246,7 +248,7 @@ class Stream { * @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( $generate = true ) { + public function getKey() { //echo "\n\$this->rawPath = {$this->rawPath}"; @@ -256,23 +258,37 @@ class Stream { # TODO: add error handling for when file exists but no keyfile // Fetch existing keyfile - $this->keyfile = Keymanager::getFileKey( $this->rawPath ); + $this->encKeyfile = Keymanager::getFileKey( $this->rawPath ); + + $this->getUser(); + + $session = new Session(); + + $this->keyfile = Crypt::keyDecrypt( $this->encKeyfile, $session->getPrivateKey( $this->userId ) ); return true; } else { - if ( $generate ) { - - // If the data is to be written to a new file, generate a new keyfile - $this->keyfile = Crypt::generateKey(); - - return false; - - } - + return false; + + } + + } + + public function getuser() { + + // Only get the user again if it isn't already set + 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?) + } /** @@ -306,15 +322,23 @@ class Stream { //echo "\$pointer = $pointer\n"; - # TODO: Move this user call out of here - it belongs elsewhere - $user = \OCP\User::getUser(); + // Make sure the userId is set + $this->getuser(); // 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->keyfile = Crypt::generateKey(); + + $this->publicKey = Keymanager::getPublicKey( $this->userId ); + + $this->encKeyfile = Crypt::keyEncrypt( $this->keyfile, $this->publicKey ); + + // Save the new encrypted file key + Keymanager::setFileKey( $this->rawPath, $this->encKeyfile, new \OC_FilesystemView( '/' ) ); - // Save keyfile in parallel directory structure - Keymanager::setFileKey( $this->rawPath, $this->keyfile, new \OC_FilesystemView( '/' ) ); + # TODO: move this new OCFSV out of here some how, use DI } diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 907a04e5c00..77f8dffe00f 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -45,6 +45,7 @@ class Util { ## 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: @@ -52,8 +53,7 @@ class Util { ## 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 - - # TODO: files created & encrypted via web ui are readable via webdav + ## DONE: files created & encrypted via web ui are readable via webdav # Legacy support: -- cgit v1.2.3