aboutsummaryrefslogtreecommitdiffstats
path: root/apps/files_encryption
diff options
context:
space:
mode:
Diffstat (limited to 'apps/files_encryption')
-rw-r--r--apps/files_encryption/hooks/hooks.php47
-rwxr-xr-xapps/files_encryption/lib/crypt.php41
-rwxr-xr-xapps/files_encryption/lib/keymanager.php97
-rw-r--r--apps/files_encryption/lib/proxy.php113
-rwxr-xr-xapps/files_encryption/test/crypt.php8
5 files changed, 208 insertions, 98 deletions
diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php
index c6d4c16115a..9252a341fb7 100644
--- a/apps/files_encryption/hooks/hooks.php
+++ b/apps/files_encryption/hooks/hooks.php
@@ -82,8 +82,12 @@ class Hooks {
}
+ \OC_FileProxy::$enabled = false;
+
$publicKey = Keymanager::getPublicKey( $view, $params['uid'] );
+ \OC_FileProxy::$enabled = false;
+
// Encrypt existing user files:
// This serves to upgrade old versions of the encryption
// app (see appinfo/spec.txt)
@@ -175,8 +179,9 @@ class Hooks {
$view = new \OC_FilesystemView( '/' );
$userId = \OCP\User::getUser();
$util = new Util( $view, $userId );
+ $session = new Session();
- $shares = \OCP\Share::getUsersSharingFile( $params['fileTarget'] );
+ $shares = \OCP\Share::getUsersSharingFile( $params['fileTarget'], 1 );
$userIds = array();
@@ -202,41 +207,35 @@ class Hooks {
}
- trigger_error("UIDS = ".var_export($userIds, 1));
-
$userPubKeys = Keymanager::getPublicKeys( $view, $userIds );
-// trigger_error("PUB KEYS = ".var_export($userPubKeys, 1));
-
- // TODO: Fetch path from Crypt{} getter
- $plainContent = $view->file_get_contents( $userId . '/' . 'files'. '/' . $params['fileTarget'] );
+ \OC_FileProxy::$enabled = false;
- // Generate new catfile and share keys
- if ( ! $encrypted = Crypt::multiKeyEncrypt( $plainContent, $userPubKeys ) ) {
+ // get the keyfile
+ $encKeyfile = Keymanager::getFileKey( $view, $userId, $params['fileTarget'] );
- // If the re-encryption failed, don't risk deleting data
- return false;
-
- }
+ $privateKey = $session->getPrivateKey();
- trigger_error("ENCRYPTED = ". var_export($encrypted, 1));
+ // decrypt the keyfile
+ $plainKeyfile = Crypt::keyDecrypt( $encKeyfile, $privateKey );
- // Save env keys to user folders
- foreach ( $encrypted['keys'] as $key ) {
+ // re-enc keyfile to sharekeys
+ $shareKeys = Crypt::multiKeyEncrypt( $plainKeyfile, $userPubKeys );
-// Keymanager::setShareKey( $view, $params['fileTarget'], $userId, $key );
+ // save sharekeys
+ if ( ! Keymanager::setShareKeys( $view, $params['fileTarget'], $shareKeys['keys'] ) ) {
+ trigger_error( "SET Share keys failed" );
+
}
- // Delete existing catfile
- // Check if keyfile exists (it won't if file has been shared before)
+ // Delete existing keyfile
// Do this last to ensure file is recoverable in case of error
- if ( $util->isEncryptedPath( $params['fileTarget'] ) ) {
-
- // NOTE: This will trigger an error if keyfile isn't found
-// Keymanager::deleteFileKey( $params['fileTarget'] );
+// Keymanager::deleteFileKey( $view, $userId, $params['fileTarget'] );
- }
+ \OC_FileProxy::$enabled = true;
+
+ return true;
}
diff --git a/apps/files_encryption/lib/crypt.php b/apps/files_encryption/lib/crypt.php
index e3d23023db3..fdee03eeaf5 100755
--- a/apps/files_encryption/lib/crypt.php
+++ b/apps/files_encryption/lib/crypt.php
@@ -370,22 +370,41 @@ class Crypt {
/**
* @brief Create asymmetrically encrypted 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
+ * @param array $publicKeys array keys must be the userId of corresponding user
+ * @returns array keys: keys (array, key = userId), encrypted
+ * @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' );
+
+ }
+
// Set empty vars to be set by openssl by reference
$sealed = '';
- $envKeys = array();
+ $shareKeys = array();
- if( openssl_seal( $plainContent, $sealed, $envKeys, $publicKeys ) ) {
+ if( openssl_seal( $plainContent, $sealed, $shareKeys, $publicKeys ) ) {
+
+ $i = 0;
+
+ // Ensure each shareKey is labelled with its
+ // corresponding userId
+ foreach ( $publicKeys as $userId => $publicKey ) {
+
+ $mappedShareKeys[$userId] = $shareKeys[$i];
+ $i++;
+
+ }
return array(
- 'keys' => $envKeys
- , 'encrypted' => $sealed
+ 'keys' => $mappedShareKeys
+ , 'data' => $sealed
);
} else {
@@ -404,7 +423,7 @@ class Crypt {
*
* This function decrypts a file
*/
- public static function multiKeyDecrypt( $encryptedContent, $envKey, $privateKey ) {
+ public static function multiKeyDecrypt( $encryptedContent, $shareKey, $privateKey ) {
if ( !$encryptedContent ) {
@@ -412,7 +431,7 @@ class Crypt {
}
- if ( openssl_open( $encryptedContent, $plainContent, $envKey, $privateKey ) ) {
+ if ( openssl_open( $encryptedContent, $plainContent, $shareKey, $privateKey ) ) {
return $plainContent;
diff --git a/apps/files_encryption/lib/keymanager.php b/apps/files_encryption/lib/keymanager.php
index 3160572ba1b..5f9eea1a0bc 100755
--- a/apps/files_encryption/lib/keymanager.php
+++ b/apps/files_encryption/lib/keymanager.php
@@ -52,8 +52,11 @@ class Keymanager {
*/
public static function getPublicKey( \OC_FilesystemView $view, $userId ) {
+ \OC_FileProxy::$enabled = false;
+
return $view->file_get_contents( '/public-keys/' . '/' . $userId . '.public.key' );
+ \OC_FileProxy::$enabled = true;
}
/**
@@ -77,20 +80,16 @@ class Keymanager {
* @param array $userIds
* @return array of public keys for the specified users
*/
- public static function getPublicKeys( \OC_FilesystemView $view, $userIds ) {
+ public static function getPublicKeys( \OC_FilesystemView $view, array $userIds ) {
- $i = 0;
$keys = array();
foreach ( $userIds as $userId ) {
- $i++;
$keys[$userId] = self::getPublicKey( $view, $userId );
}
- $keys['total'] = $i;
-
return $keys;
}
@@ -137,11 +136,11 @@ class Keymanager {
$filePath_f = ltrim( $filePath, '/' );
- $catfilePath = '/' . $userId . '/files_encryption/keyfiles/' . $filePath_f . '.key';
+ $keyfilePath = '/' . $userId . '/files_encryption/keyfiles/' . $filePath_f . '.key';
- if ( $view->file_exists( $catfilePath ) ) {
+ if ( $view->file_exists( $keyfilePath ) ) {
- return $view->file_get_contents( $catfilePath );
+ return $view->file_get_contents( $keyfilePath );
} else {
@@ -239,7 +238,7 @@ class Keymanager {
}
/**
- * @brief store file encryption key
+ * @brief store share key
*
* @param string $path relative path of the file, including filename
* @param string $key
@@ -255,7 +254,85 @@ class Keymanager {
$shareKeyPath = self::keySetPreparation( $view, $path, $basePath, $userId );
- return $view->file_put_contents( $basePath . '/' . $shareKeyPath . '.shareKey', $shareKey );
+ $writePath = $basePath . '/' . $shareKeyPath . '.shareKey';
+
+ \OC_FileProxy::$enabled = false;
+
+ $result = $view->file_put_contents( $writePath, $shareKey );
+
+ if (
+ is_int( $result )
+ && $result > 0
+ ) {
+
+ return true;
+
+ } else {
+
+ return false;
+
+ }
+
+ }
+
+ /**
+ * @brief store multiple share keys for a single file
+ * @return bool
+ */
+ 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 ) ) {
+
+ // 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
+ * @param $userId
+ * @param $filePath
+ * @internal param \OCA\Encryption\file $string name
+ * @return string file key or false
+ * @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 ) {
+
+ \OC_FileProxy::$enabled = false;
+
+ $filePath_f = ltrim( $filePath, '/' );
+
+ $shareKeyPath = '/' . $userId . '/files_encryption/share-keys/' . $filePath_f . '.shareKey';
+
+ if ( $view->file_exists( $shareKeyPath ) ) {
+
+ $result = $view->file_get_contents( $shareKeyPath );
+
+ } else {
+
+ $result = false;
+
+ }
+
+ \OC_FileProxy::$enabled = true;
+
+ return $result;
}
diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php
index 58b9bc0725b..b5e59e89b9e 100644
--- a/apps/files_encryption/lib/proxy.php
+++ b/apps/files_encryption/lib/proxy.php
@@ -99,58 +99,65 @@ class Proxy extends \OC_FileProxy {
if ( !is_resource( $data ) ) {
$userId = \OCP\USER::getUser();
-
$rootView = new \OC_FilesystemView( '/' );
-
+ $util = new Util( $rootView, $userId );
+ $filePath = $util->stripUserFilesPath( $path );
// Set the filesize for userland, before encrypting
$size = strlen( $data );
// Disable encryption proxy to prevent recursive calls
\OC_FileProxy::$enabled = false;
- $fileOwner = \OC\Files\Filesystem::getOwner( $path );
+ // Encrypt data
+ $encData = Crypt::symmetricEncryptFileContentKeyfile( $data );
// Check if the keyfile needs to be shared
- if (
- $fileOwner !== true
- or $fileOwner !== $userId
- ) {
+ if ( \OCP\Share::isSharedFile( $filePath ) ) {
+
+// $fileOwner = \OC\Files\Filesystem::getOwner( $path );
+
+ // List everyone sharing the file
+ $shares = \OCP\Share::getUsersSharingFile( $filePath, 1 );
+
+ $userIds = array();
+
+ foreach ( $shares as $share ) {
+
+ $userIds[] = $share['userId'];
+
+ }
+
+ $publicKeys = Keymanager::getPublicKeys( $rootView, $userIds );
+
+ \OC_FileProxy::$enabled = false;
+
+ // Encrypt plain keyfile to multiple sharefiles
+ $multiEncrypted = Crypt::multiKeyEncrypt( $encData['key'], $publicKeys );
+
+ // Save sharekeys to user folders
+ Keymanager::setShareKeys( $rootView, $filePath, $multiEncrypted['keys'] );
+
+ // Set encrypted keyfile as common varname
+ $encKey = $multiEncrypted['encrypted'];
- // Shared storage backend isn't loaded
- $users = \OCP\Share::getItemShared( 'file', $path, \OC_Share_backend_File::FORMAT_SHARED_STORAGE );
-//
- trigger_error("SHARE USERS = ". var_export($users, 1));
-//
-// $publicKeys = Keymanager::getPublicKeys( $rootView, $users);
-//
-// // Encrypt plain data to multiple users
-// $encrypted = Crypt::multiKeyEncrypt( $data, $publicKeys );
} else {
$publicKey = Keymanager::getPublicKey( $rootView, $userId );
// Encrypt plain data to a single user
- $encrypted = Crypt::keyEncryptKeyfile( $data, $publicKey );
+ $encKey = Crypt::keyEncrypt( $encData['key'], $publicKey );
}
- // Replace plain content with encrypted content by reference
- $data = $encrypted['data'];
-
- $filePath = explode( '/', $path );
-
- $filePath = array_slice( $filePath, 3 );
-
- $filePath = '/' . implode( '/', $filePath );
-
- // TODO: make keyfile dir dynamic from app config
-
- $view = new \OC_FilesystemView( '/' );
+ // TODO: Replace userID with ownerId so keyfile is saved centrally
// Save keyfile for newly encrypted file in parallel directory tree
- Keymanager::setFileKey( $view, $filePath, $userId, $encrypted['key'] );
+ Keymanager::setFileKey( $rootView, $filePath, $userId, $encKey );
+
+ // Replace plain content with encrypted content by reference
+ $data = $encData['encrypted'];
// Update the file cache with file info
\OC\Files\Filesystem::putFileInfo( $path, array( 'encrypted'=>true, 'size' => $size ), '' );
@@ -168,8 +175,6 @@ class Proxy extends \OC_FileProxy {
* @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
// Disable encryption proxy to prevent recursive calls
\OC_FileProxy::$enabled = false;
@@ -180,45 +185,55 @@ class Proxy extends \OC_FileProxy {
&& Crypt::isCatfile( $data )
) {
- $split = explode( '/', $path );
-
- $filePath = array_slice( $split, 3 );
+ $view = new \OC_FilesystemView( '/' );
+ $userId = \OCP\USER::getUser();
+ $session = new Session();
+ $util = new Util( $view, $userId );
+ $filePath = $util->stripUserFilesPath( $path );
+ $privateKey = $session->getPrivateKey( $userId );
- $filePath = '/' . implode( '/', $filePath );
+ // Get the encrypted keyfile
+ $encKeyfile = Keymanager::getFileKey( $view, $userId, $filePath );
- //$cached = \OC\Files\Filesystem::getFileInfo( $path, '' );
+ // Check if key is shared or not
+ if ( \OCP\Share::isSharedFile( $filePath ) ) {
- $view = new \OC_FilesystemView( '' );
+ // If key is shared, fetch the user's shareKey
+ $shareKey = Keymanager::getShareKey( $view, $userId, $filePath );
+
+ \OC_FileProxy::$enabled = false;
+
+ // Decrypt keyfile with shareKey
+ $plainKeyfile = Crypt::multiKeyDecrypt( $encKeyfile, $shareKey, $privateKey );
- $userId = \OCP\USER::getUser();
+ } else {
+
+ // If key is unshared, decrypt with user private key
+ $plainKeyfile = Crypt::keyDecrypt( $encKeyfile, $privateKey );
- // TODO: Check if file is shared, if so, use multiKeyDecrypt
+ }
- $encryptedKeyfile = Keymanager::getFileKey( $view, $userId, $filePath );
+ $plainData = Crypt::symmetricDecryptFileContent( $data, $plainKeyfile );
- $session = new Session();
-
- $decrypted = Crypt::keyDecryptKeyfile( $data, $encryptedKeyfile, $session->getPrivateKey( $split[1] ) );
-
} elseif (
Crypt::mode() == 'server'
&& isset( $_SESSION['legacyenckey'] )
&& Crypt::isEncryptedMeta( $path )
) {
- $decrypted = Crypt::legacyDecrypt( $data, $_SESSION['legacyenckey'] );
+ $plainData = Crypt::legacyDecrypt( $data, $session->getLegacyKey() );
}
\OC_FileProxy::$enabled = true;
- if ( ! isset( $decrypted ) ) {
+ if ( ! isset( $plainData ) ) {
- $decrypted = $data;
+ $plainData = $data;
}
- return $decrypted;
+ return $plainData;
}
diff --git a/apps/files_encryption/test/crypt.php b/apps/files_encryption/test/crypt.php
index aa87ec32821..48ad2ee0075 100755
--- a/apps/files_encryption/test/crypt.php
+++ b/apps/files_encryption/test/crypt.php
@@ -439,14 +439,14 @@ class Test_Crypt extends \PHPUnit_Framework_TestCase {
$this->assertTrue( strlen( $pair1['privateKey'] ) > 1 );
- $crypted = Encryption\Crypt::multiKeyEncrypt( $this->dataUrl, array( $pair1['publicKey'] ) );
+ $crypted = Encryption\Crypt::multiKeyEncrypt( $this->dataShort, array( $pair1['publicKey'] ) );
- $this->assertNotEquals( $this->dataUrl, $crypted['encrypted'] );
+ $this->assertNotEquals( $this->dataShort, $crypted['data'] );
- $decrypt = Encryption\Crypt::multiKeyDecrypt( $crypted['encrypted'], $crypted['keys'][0], $pair1['privateKey'] );
+ $decrypt = Encryption\Crypt::multiKeyDecrypt( $crypted['data'], $crypted['keys'][0], $pair1['privateKey'] );
- $this->assertEquals( $this->dataUrl, $decrypt );
+ $this->assertEquals( $this->dataShort, $decrypt );
}