Merge branch 'files_encryption'

This commit is contained in:
Sam Tuke 2013-01-23 12:54:09 +00:00
commit cd832935e8
8 changed files with 139 additions and 53 deletions

View File

@ -10,10 +10,18 @@ OC::$CLASSPATH['OCA\Encryption\Session'] = 'apps/files_encryption/lib/session.ph
OC_FileProxy::register( new OCA\Encryption\Proxy() ); OC_FileProxy::register( new OCA\Encryption\Proxy() );
// User-related hooks
OCP\Util::connectHook( 'OC_User','post_login', 'OCA\Encryption\Hooks', 'login' ); OCP\Util::connectHook( 'OC_User','post_login', 'OCA\Encryption\Hooks', 'login' );
OCP\Util::connectHook( 'OC_Webdav_Properties', 'update', 'OCA\Encryption\Hooks', 'updateKeyfile' );
OCP\Util::connectHook( 'OC_User','post_setPassword','OCA\Encryption\Hooks' ,'setPassphrase' ); OCP\Util::connectHook( 'OC_User','post_setPassword','OCA\Encryption\Hooks' ,'setPassphrase' );
// Sharing-related hooks
OCP\Util::connectHook( 'OCP\Share','post_shared','OCA\Encryption\Hooks' ,'postShared' );
OCP\Util::connectHook( 'OCP\Share','pre_unshare','OCA\Encryption\Hooks' ,'preUnshare' );
OCP\Util::connectHook( 'OCP\Share','pre_unshareAll','OCA\Encryption\Hooks' ,'preUnshareAll' );
// Webdav-related hooks
OCP\Util::connectHook( 'OC_Webdav_Properties', 'update', 'OCA\Encryption\Hooks', 'updateKeyfile' );
stream_wrapper_register( 'crypt', 'OCA\Encryption\Stream' ); stream_wrapper_register( 'crypt', 'OCA\Encryption\Stream' );
$session = new OCA\Encryption\Session(); $session = new OCA\Encryption\Session();
@ -24,7 +32,9 @@ if (
&& OCA\Encryption\Crypt::mode() == 'server' && OCA\Encryption\Crypt::mode() == 'server'
) { ) {
// Force the user to re-log in if the encryption key isn't unlocked (happens when a user is logged in before the encryption app is enabled) // Force the user to re-log in if the encryption key isn't unlocked
// (happens when a user is logged in before the encryption app is
// enabled)
OCP\User::logout(); OCP\User::logout();
header( "Location: " . OC::$WEBROOT.'/' ); header( "Location: " . OC::$WEBROOT.'/' );
@ -33,5 +43,5 @@ if (
} }
OCP\App::registerAdmin( 'files_encryption', 'settings'); OCP\App::registerAdmin( 'files_encryption', 'settings' );
OCP\App::registerPersonal( 'files_encryption', 'settings-personal' ); OCP\App::registerPersonal( 'files_encryption', 'settings-personal' );

View File

@ -121,8 +121,11 @@ class Hooks {
if ( isset( $params['properties']['key'] ) ) { if ( isset( $params['properties']['key'] ) ) {
Keymanager::setFileKey( $params['path'], $params['properties']['key'] ); $view = new \OC_FilesystemView( '/' );
$userId = \OCP\User::getUser();
Keymanager::setFileKey( $view, $params['path'], $userId, $params['properties']['key'] );
} else { } else {
\OC_Log::write( \OC_Log::write(
@ -138,6 +141,43 @@ class Hooks {
} }
/**
* @brief
*/
public static function postShared( $params ) {
// Delete existing catfile
Keymanager::deleteFileKey( );
// Generate new catfile and env keys
Crypt::multiKeyEncrypt( $plainContent, $publicKeys );
// Save env keys to user folders
}
/**
* @brief
*/
public static function preUnshare( $params ) {
// Delete existing catfile
// Generate new catfile and env keys
// Save env keys to user folders
}
/**
* @brief
*/
public static function preUnshareAll( $params ) {
trigger_error( "preUnshareAll" );
}
} }
?> ?>

View File

@ -390,6 +390,8 @@ class Crypt {
*/ */
public static function multiKeyEncrypt( $plainContent, array $publicKeys ) { public static function multiKeyEncrypt( $plainContent, array $publicKeys ) {
// Set empty vars to be set by openssl by reference
$sealed = '';
$envKeys = array(); $envKeys = array();
if( openssl_seal( $plainContent, $sealed, $envKeys, $publicKeys ) ) { if( openssl_seal( $plainContent, $sealed, $envKeys, $publicKeys ) ) {

View File

@ -238,7 +238,7 @@ class Keymanager {
*/ */
public static function setUserKeys($privatekey, $publickey) { public static function setUserKeys($privatekey, $publickey) {
return (self::setPrivateKey($privatekey) && self::setPublicKey($publickey)); return ( self::setPrivateKey( $privatekey ) && self::setPublicKey( $publickey ) );
} }
@ -262,6 +262,42 @@ class Keymanager {
} }
/**
* @note 'shareKey' is a more user-friendly name for env_key
*/
public static function setShareKey( \OC_FilesystemView $view, $path, $userId, $shareKey ) {
$basePath = '/' . $userId . '/files_encryption/share-keys';
$shareKeyPath = self::keySetPreparation( $view, $path, $basePath, $userId );
return $view->file_put_contents( $basePath . '/' . $shareKeyPath . '.shareKey', $shareKey );
}
/**
* @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 );
// If the file resides within a subdirectory, create it
if (
isset( $path_parts['dirname'] )
&& ! $view->file_exists( $basePath . $path_parts['dirname'] )
) {
$view->mkdir( $basePath . $path_parts['dirname'] );
}
return $targetPath;
}
/** /**
* @brief store file encryption key * @brief store file encryption key
* *
@ -271,15 +307,16 @@ class Keymanager {
* @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 * asymmetrically encrypt the keyfile before passing it to this method
*/ */
public static function setFileKey( $path, $key, $view = Null, $dbClassName = '\OC_DB') { public static function setFileKey( \OC_FilesystemView $view, $path, $userId, $catfile ) {
$targetPath = ltrim( $path, '/' );
$user = \OCP\User::getUser();
// // update $keytarget and $user if key belongs to a file shared by someone else $basePath = '/' . $userId . '/files_encryption/keyfiles';
$targetPath = self::keySetPreparation( $view, $path, $basePath, $userId );
// // update $keytarget and $userId if key belongs to a file shared by someone else
// $query = $dbClassName::prepare( "SELECT uid_owner, source, target FROM `*PREFIX*sharing` WHERE target = ? AND uid_shared_with = ?" ); // $query = $dbClassName::prepare( "SELECT uid_owner, source, target FROM `*PREFIX*sharing` WHERE target = ? AND uid_shared_with = ?" );
// //
// $result = $query->execute( array ( '/'.$user.'/files/'.$targetPath, $user ) ); // $result = $query->execute( array ( '/'.$userId.'/files/'.$targetPath, $userId ) );
// //
// if ( $row = $result->fetchRow( ) ) { // if ( $row = $result->fetchRow( ) ) {
// //
@ -287,7 +324,7 @@ class Keymanager {
// //
// $targetPath_parts = explode( '/', $targetPath ); // $targetPath_parts = explode( '/', $targetPath );
// //
// $user = $targetPath_parts[1]; // $userId = $targetPath_parts[1];
// //
// $rootview = new \OC_FilesystemView( '/' ); // $rootview = new \OC_FilesystemView( '/' );
// //
@ -299,34 +336,14 @@ class Keymanager {
// //
// } // }
// //
// $targetPath = str_replace( '/'.$user.'/files/', '', $targetPath ); // $targetPath = str_replace( '/'.$userId.'/files/', '', $targetPath );
// //
// //TODO: check for write permission on shared file once the new sharing API is in place // //TODO: check for write permission on shared file once the new sharing API is in place
// //
// } // }
$path_parts = pathinfo( $targetPath );
if ( !$view ) {
$view = new \OC_FilesystemView( '/' );
}
$view->chroot( '/' . $user . '/files_encryption/keyfiles' );
// If the file resides within a subdirectory, create it
if (
isset( $path_parts['dirname'] )
&& ! $view->file_exists( $path_parts['dirname'] )
) {
$view->mkdir( $path_parts['dirname'] );
}
// Save the keyfile in parallel directory // Save the keyfile in parallel directory
return $view->file_put_contents( '/' . $targetPath . '.key', $key ); return $view->file_put_contents( $basePath . '/' . $targetPath . '.key', $catfile );
} }

View File

@ -101,6 +101,8 @@ class Proxy extends \OC_FileProxy {
// Disable encryption proxy to prevent recursive calls // Disable encryption proxy to prevent recursive calls
\OC_FileProxy::$enabled = false; \OC_FileProxy::$enabled = false;
# TODO: Check if file is shared, if so, use multiKeyEncrypt
// Encrypt plain data and fetch key // Encrypt plain data and fetch key
$encrypted = Crypt::keyEncryptKeyfile( $data, Keymanager::getPublicKey( $rootView, $userId ) ); $encrypted = Crypt::keyEncryptKeyfile( $data, Keymanager::getPublicKey( $rootView, $userId ) );
@ -114,10 +116,11 @@ class Proxy extends \OC_FileProxy {
$filePath = '/' . implode( '/', $filePath ); $filePath = '/' . implode( '/', $filePath );
# TODO: make keyfile dir dynamic from app config # TODO: make keyfile dir dynamic from app config
$view = new \OC_FilesystemView( '/' . $userId . '/files_encryption/keyfiles' );
$view = new \OC_FilesystemView( '/' );
// Save keyfile for newly encrypted file in parallel directory tree // Save keyfile for newly encrypted file in parallel directory tree
Keymanager::setFileKey( $filePath, $encrypted['key'], $view, '\OC_DB' ); Keymanager::setFileKey( $view, $filePath, $userId, $encrypted['key'] );
// Update the file cache with file info // Update the file cache with file info
\OC_FileCache::put( $path, array( 'encrypted'=>true, 'size' => $size ), '' ); \OC_FileCache::put( $path, array( 'encrypted'=>true, 'size' => $size ), '' );
@ -159,6 +162,8 @@ class Proxy extends \OC_FileProxy {
$userId = \OCP\USER::getUser(); $userId = \OCP\USER::getUser();
# TODO: Check if file is shared, if so, use multiKeyDecrypt
$encryptedKeyfile = Keymanager::getFileKey( $view, $userId, $filePath ); $encryptedKeyfile = Keymanager::getFileKey( $view, $userId, $filePath );
$session = new Session(); $session = new Session();

View File

@ -302,8 +302,12 @@ class Stream {
// Make sure the userId is set // Make sure the userId is set
$this->getuser(); $this->getuser();
# TODO: Check if file is shared, if so, use multiKeyEncrypt and
# save shareKeys in necessary user directories
// Get / generate the keyfile for the file we're handling // 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 we're writing a new file (not overwriting an existing
// one), save the newly generated keyfile
if ( ! $this->getKey() ) { if ( ! $this->getKey() ) {
$this->keyfile = Crypt::generateKey(); $this->keyfile = Crypt::generateKey();
@ -312,10 +316,11 @@ class Stream {
$this->encKeyfile = Crypt::keyEncrypt( $this->keyfile, $this->publicKey ); $this->encKeyfile = Crypt::keyEncrypt( $this->keyfile, $this->publicKey );
// Save the new encrypted file key $view = new \OC_FilesystemView( '/' );
Keymanager::setFileKey( $this->rawPath, $this->encKeyfile, new \OC_FilesystemView( '/' ) ); $userId = \OCP\User::getUser();
# TODO: move this new OCFSV out of here some how, use DI // Save the new encrypted file key
Keymanager::setFileKey( $view, $this->rawPath, $userId, $this->encKeyfile );
} }

View File

@ -96,9 +96,10 @@ class Util {
private $view; // OC_FilesystemView object for filesystem operations private $view; // OC_FilesystemView object for filesystem operations
private $pwd; // User Password private $pwd; // User Password
private $client; // Client side encryption mode flag private $client; // Client side encryption mode flag
private $publicKeyDir; // Directory containing all public user keys private $publicKeyDir; // Dir containing all public user keys
private $encryptionDir; // Directory containing user's files_encryption private $encryptionDir; // Dir containing user's files_encryption
private $keyfilesPath; // Directory containing user's keyfiles private $keyfilesPath; // Dir containing user's keyfiles
private $shareKeysPath; // Dir containing env keys for shared files
private $publicKeyPath; // Path to user's public key private $publicKeyPath; // Path to user's public key
private $privateKeyPath; // Path to user's private key private $privateKeyPath; // Path to user's private key
@ -110,6 +111,7 @@ class Util {
$this->publicKeyDir = '/' . 'public-keys'; $this->publicKeyDir = '/' . 'public-keys';
$this->encryptionDir = '/' . $this->userId . '/' . 'files_encryption'; $this->encryptionDir = '/' . $this->userId . '/' . 'files_encryption';
$this->keyfilesPath = $this->encryptionDir . '/' . 'keyfiles'; $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->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->privateKeyPath = $this->encryptionDir . '/' . $this->userId . '.private.key'; // e.g. data/admin/admin.private.key
@ -159,6 +161,13 @@ class Util {
$this->view->mkdir( $this->keyfilesPath ); $this->view->mkdir( $this->keyfilesPath );
} }
// Create mirrored share env keys directory
if( !$this->view->file_exists( $this->shareKeysPath ) ) {
$this->view->mkdir( $this->shareKeysPath );
}
// Create user keypair // Create user keypair
if ( if (

View File

@ -79,15 +79,13 @@ class Test_Keymanager extends \PHPUnit_Framework_TestCase {
# NOTE: This cannot be tested until we are able to break out # NOTE: This cannot be tested until we are able to break out
# of the FileSystemView data directory root # of the FileSystemView data directory root
// $key = Crypt::symmetricEncryptFileContentKeyfile( $this->data, 'hat' ); $key = Encryption\Crypt::symmetricEncryptFileContentKeyfile( $this->randomKey, 'hat' );
//
// $tmpPath = sys_get_temp_dir(). '/' . 'testSetFileKey'; $path = 'unittest-'.time().'txt';
//
// $view = new \OC_FilesystemView( '/tmp/' ); //$view = new \OC_FilesystemView( '/' . $this->userId . '/files_encryption/keyfiles' );
//
// //$view = new \OC_FilesystemView( '/' . $this->userId . '/files_encryption/keyfiles' ); Encryption\Keymanager::setFileKey( $this->view, $path, $this->userId, $key['key'] );
//
// Encryption\Keymanager::setFileKey( $tmpPath, $key['key'], $view );
} }