added wrapper method in crypt class for encrypting asymmetric and symmetric simultaneously
fixed bugs with keymanager integration added unit tests
This commit is contained in:
parent
b1f6bb36b0
commit
6ce315fe58
|
@ -1,76 +1,77 @@
|
|||
<?php
|
||||
/**
|
||||
* ownCloud
|
||||
*
|
||||
* @author Sam Tuke
|
||||
* @copyright 2012 Sam Tuke samtuke@owncloud.org
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OCA_Encryption;
|
||||
|
||||
/**
|
||||
* Class for hook specific logic
|
||||
*/
|
||||
|
||||
class Hooks {
|
||||
|
||||
# TODO: use passphrase for encrypting private key that is separate to the login password
|
||||
|
||||
/**
|
||||
* @brief Startup encryption backend upon user login
|
||||
* @note This method should never be called for users using client side encryption
|
||||
*/
|
||||
|
||||
public static function login( $params ) {
|
||||
|
||||
if ( Crypt::mode( $params['uid'] ) == 'server' ) {
|
||||
|
||||
$view = new \OC_FilesystemView( '/' );
|
||||
|
||||
$util = new Util( $view, $params['uid'] );
|
||||
|
||||
if ( !$util->ready()) {
|
||||
|
||||
return $util->setupServerSide( $params['password'] );
|
||||
|
||||
}
|
||||
|
||||
$encryptedKey = Keymanager::getPrivateKey( $params['uid'] );
|
||||
|
||||
$_SESSION['enckey'] = Crypt::symmetricEncryptFileContent( $encryptedKey, $params['password'] );
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
<?php
|
||||
/**
|
||||
* ownCloud
|
||||
*
|
||||
* @author Sam Tuke
|
||||
* @copyright 2012 Sam Tuke samtuke@owncloud.org
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OCA_Encryption;
|
||||
|
||||
/**
|
||||
* Class for hook specific logic
|
||||
*/
|
||||
|
||||
class Hooks {
|
||||
|
||||
# TODO: use passphrase for encrypting private key that is separate to the login password
|
||||
|
||||
/**
|
||||
* @brief Startup encryption backend upon user login
|
||||
* @note This method should never be called for users using client side encryption
|
||||
*/
|
||||
|
||||
public static function login( $params ) {
|
||||
|
||||
if ( Crypt::mode( $params['uid'] ) == 'server' ) {
|
||||
|
||||
$view = new \OC_FilesystemView( '/' );
|
||||
|
||||
$util = new Util( $view, $params['uid'] );
|
||||
|
||||
if ( !$util->ready()) {
|
||||
|
||||
return $util->setupServerSide( $params['password'] );
|
||||
|
||||
}
|
||||
|
||||
$encryptedKey = Keymanager::getPrivateKey( $params['uid'] );
|
||||
|
||||
$_SESSION['enckey'] = Crypt::symmetricDecryptFileContent( $encryptedKey, $params['password'] );
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief update the encryption key of the file uploaded by the client
|
||||
*/
|
||||
public static function updateKeyfile( $params ) {
|
||||
if (Crypt::mode() == 'client')
|
||||
if (isset($params['properties']['key'])) {
|
||||
Keymanager::setFileKey($params['path'], $params['properties']['key']);
|
||||
} else {
|
||||
\OC_Log::write( 'Encryption library', "Client side encryption is enabled but the client doesn't provide a encryption key for the file!", \OC_Log::ERROR );
|
||||
error_log("Client side encryption is enabled but the client doesn't provide a encryption key for the file!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
public static function updateKeyfile( $params ) {
|
||||
if (Crypt::mode() == 'client')
|
||||
if (isset($params['properties']['key'])) {
|
||||
Keymanager::setFileKey($params['path'], $params['properties']['key']);
|
||||
} else {
|
||||
\OC_Log::write( 'Encryption library', "Client side encryption is enabled but the client doesn't provide a encryption key for the file!", \OC_Log::ERROR );
|
||||
error_log("Client side encryption is enabled but the client doesn't provide a encryption key for the file!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -38,19 +38,19 @@ class Crypt {
|
|||
public static function mode( $user = null ) {
|
||||
|
||||
$mode = \OC_Appconfig::getValue( 'files_encryption', 'mode', 'none' );
|
||||
|
||||
|
||||
if ( $mode == 'user') {
|
||||
if ( !$user ) {
|
||||
$user = \OCP\User::getUser();
|
||||
}
|
||||
$mode = 'none';
|
||||
if ( $user ) {
|
||||
}
|
||||
$mode = 'none';
|
||||
if ( $user ) {
|
||||
$query = \OC_DB::prepare( "SELECT mode FROM *PREFIX*encryption WHERE uid = ?" );
|
||||
$result = $query->execute(array($user));
|
||||
if ($row = $result->fetchRow()){
|
||||
$mode = $row['mode'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $mode;
|
||||
|
@ -217,6 +217,7 @@ class Crypt {
|
|||
* @param string $source
|
||||
* @param string $target
|
||||
* @param string $key the decryption key
|
||||
* @returns decrypted content
|
||||
*
|
||||
* This function decrypts a file
|
||||
*/
|
||||
|
@ -305,7 +306,7 @@ class Crypt {
|
|||
/**
|
||||
* @brief Asymmetrically encrypt a file using multiple public keys
|
||||
* @param string $plainContent content to be encrypted
|
||||
* @returns array keys: key, encrypted
|
||||
* @returns string $plainContent decrypted string
|
||||
* @note symmetricDecryptFileContent() can be used to decrypt files created using this method
|
||||
*
|
||||
* This function decrypts a file
|
||||
|
@ -355,6 +356,40 @@ class Crypt {
|
|||
return $plainContent;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Encrypts content symmetrically and generated keyfile asymmetrically
|
||||
* @returns array keys: data, key
|
||||
* @note this method is a wrapper for combining other crypt class methods
|
||||
*/
|
||||
public static function keyEncryptKeyfile( $plainContent, $publicKey ) {
|
||||
|
||||
// Encrypt plain data, generate keyfile & encrypted file
|
||||
$cryptedData = self::symmetricEncryptFileContentKeyfile( $plainContent );
|
||||
|
||||
// Encrypt keyfile
|
||||
$cryptedKey = self::keyEncrypt( $cryptedData['key'], $publicKey );
|
||||
|
||||
return array( 'data' => $cryptedData['encrypted'], 'key' => $cryptedKey );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Encrypts content symmetrically and generated keyfile asymmetrically
|
||||
* @returns decrypted content
|
||||
* @note this method is a wrapper for combining other crypt class methods
|
||||
*/
|
||||
public static function keyDecryptKeyfile( $encryptedData, $encryptedKey, $privateKey ) {
|
||||
|
||||
// Decrypt keyfile
|
||||
$decryptedKey = self::keyDecrypt( $encryptedKey, $privateKey );
|
||||
|
||||
// Decrypt encrypted file
|
||||
$decryptedData = self::symmetricDecryptFileContent( $encryptedData, $decryptedKey );
|
||||
|
||||
return $decryptedData;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Generate a pseudo random 1024kb ASCII key
|
||||
|
@ -392,7 +427,7 @@ class Crypt {
|
|||
// $key = mt_rand( 10000, 99999 ) . mt_rand( 10000, 99999 ) . mt_rand( 10000, 99999 ) . mt_rand( 10000, 99999 );
|
||||
|
||||
// Generate key
|
||||
if ( $key = base64_encode( openssl_random_pseudo_bytes( 768000, $strong ) ) ) {
|
||||
if ( $key = base64_encode( openssl_random_pseudo_bytes( 183, $strong ) ) ) {
|
||||
|
||||
if ( !$strong ) {
|
||||
|
||||
|
|
|
@ -41,6 +41,19 @@ class Keymanager {
|
|||
return $view->file_get_contents( '/' . $user.'.private.key' );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief retrieve public key for a specified user
|
||||
*
|
||||
* @return string public key or false
|
||||
*/
|
||||
public static function getPublicKey() {
|
||||
|
||||
$user = \OCP\User::getUser();
|
||||
$view = new \OC_FilesystemView( '/public-keys/' );
|
||||
return $view->file_get_contents( '/' . $user . '.public.key' );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief retrieve a list of the public key from all users with access to the file
|
||||
|
@ -94,22 +107,26 @@ class Keymanager {
|
|||
* @return string file key or false
|
||||
*/
|
||||
public static function getFileKey( $path ) {
|
||||
|
||||
trigger_error("div ".$path);
|
||||
$keypath = ltrim( $path, '/' );
|
||||
$user = \OCP\User::getUser();
|
||||
|
||||
// update $keypath and $user if path point to a file shared by someone else
|
||||
$query = \OC_DB::prepare( "SELECT uid_owner, source, target FROM `*PREFIX*sharing` WHERE target = ? AND uid_shared_with = ?" );
|
||||
|
||||
$result = $query->execute( array ('/'.$user.'/files/'.$keypath, $user));
|
||||
if ($row = $result->fetchRow()){
|
||||
|
||||
if ($row = $result->fetchRow()) {
|
||||
|
||||
$keypath = $row['source'];
|
||||
$keypath_parts=explode('/',$keypath);
|
||||
$keypath_parts = explode( '/', $keypath );
|
||||
$user = $keypath_parts[1];
|
||||
$keypath = str_replace('/'.$user.'/files/', '', $keypath);
|
||||
$keypath = str_replace( '/' . $user . '/files/', '', $keypath );
|
||||
|
||||
}
|
||||
|
||||
$view = new \OC_FilesystemView('/'.$user.'/files_encryption/keyfiles/');
|
||||
return $view->file_get_contents($keypath.'.key');
|
||||
return $view->file_get_contents( $keypath . '.key' );
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -103,11 +103,14 @@ class Proxy extends \OC_FileProxy {
|
|||
// Set the filesize for userland, before encrypting
|
||||
$size = strlen( $data );
|
||||
|
||||
// Disable encryption proxy to prevent recursive calls
|
||||
\OC_FileProxy::$enabled = false;
|
||||
|
||||
// Encrypt plain data and fetch key
|
||||
$encrypted = Crypt::symmetricEncryptFileContentKeyfile( $data, $_SESSION['enckey'] );
|
||||
$encrypted = Crypt::keyEncryptKeyfile( $data, Keymanager::getPublicKey() );
|
||||
|
||||
// Replace plain content with encrypted content by reference
|
||||
$data = $encrypted['encrypted'];
|
||||
$data = $encrypted['data'];
|
||||
|
||||
$filePath = explode( '/', $path );
|
||||
|
||||
|
@ -119,11 +122,13 @@ class Proxy extends \OC_FileProxy {
|
|||
$view = new \OC_FilesystemView( '/' . \OCP\USER::getUser() . '/files_encryption/keyfiles' );
|
||||
|
||||
// Save keyfile for newly encrypted file in parallel directory tree
|
||||
Keymanager::setFileKey( \OCP\USER::getUser(), $filePath, $encrypted['key'], $view, '\OC_DB', '\OC_FileProxy' );
|
||||
Keymanager::setFileKey( $filePath, $encrypted['key'], $view, '\OC_DB' );
|
||||
|
||||
// Update the file cache with file info
|
||||
\OC_FileCache::put( $path, array( 'encrypted'=>true, 'size' => $size ), '' );
|
||||
|
||||
\OC_FileProxy::$enabled = true;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -138,14 +143,18 @@ class Proxy extends \OC_FileProxy {
|
|||
|
||||
$filePath = '/' . implode( '/', $filePath );
|
||||
|
||||
trigger_error( "CAT " . $filePath);
|
||||
|
||||
$cached = \OC_FileCache_Cached::get( $path, '' );
|
||||
|
||||
// Get keyfile for encrypted file
|
||||
$keyFile = Keymanager::getFileKey( \OCP\USER::getUser(), $filePath );
|
||||
// Disable encryption proxy to prevent recursive calls
|
||||
\OC_FileProxy::$enabled = false;
|
||||
|
||||
$data = Crypt::symmetricDecryptFileContent( $data, $keyFile );
|
||||
$keyFile = Keymanager::getFileKey( $filePath );
|
||||
|
||||
$privateKey = Keymanager::getPrivateKey();
|
||||
|
||||
$data = Crypt::keyDecryptKeyfile( $data, $keyFile, $privateKey );
|
||||
|
||||
\OC_FileProxy::$enabled = true;
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -7,11 +7,11 @@
|
|||
* See the COPYING-README file.
|
||||
*/
|
||||
|
||||
require realpath( dirname(__FILE__).'/../lib/crypt.php' );
|
||||
require realpath( dirname(__FILE__).'/../lib/util.php' );
|
||||
require_once realpath( dirname(__FILE__).'/../lib/crypt.php' );
|
||||
require_once realpath( dirname(__FILE__).'/../lib/util.php' );
|
||||
//require realpath( dirname(__FILE__).'/../../../lib/filecache.php' );
|
||||
|
||||
class Test_Encryption extends UnitTestCase {
|
||||
class Test_Crypt extends UnitTestCase {
|
||||
|
||||
function setUp() {
|
||||
|
||||
|
@ -32,7 +32,7 @@ class Test_Encryption extends UnitTestCase {
|
|||
|
||||
$this->assertTrue( $key );
|
||||
|
||||
$this->assertTrue( strlen( $key ) > 1000 );
|
||||
$this->assertTrue( strlen( $key ) > 16 );
|
||||
|
||||
}
|
||||
|
||||
|
@ -137,6 +137,46 @@ class Test_Encryption extends UnitTestCase {
|
|||
$this->assertEqual( $this->data, $decrypt );
|
||||
|
||||
}
|
||||
|
||||
function testKeyEncrypt() {
|
||||
|
||||
// Generate keypair
|
||||
$pair1 = OCA_Encryption\Crypt::createKeypair();
|
||||
|
||||
// Encrypt data
|
||||
$crypted = OCA_Encryption\Crypt::keyEncrypt( $this->data, $pair1['publicKey'] );
|
||||
|
||||
$this->assertNotEqual( $this->data, $crypted );
|
||||
|
||||
// Decrypt data
|
||||
$decrypt = OCA_Encryption\Crypt::keyDecrypt( $crypted, $pair1['privateKey'] );
|
||||
|
||||
$this->assertEqual( $this->data, $decrypt );
|
||||
|
||||
}
|
||||
|
||||
function testKeyEncryptKeyfile() {
|
||||
|
||||
# TODO: Don't repeat encryption from previous tests, use PHPUnit test interdependency instead
|
||||
|
||||
// Generate keypair
|
||||
$pair1 = OCA_Encryption\Crypt::createKeypair();
|
||||
|
||||
// Encrypt plain data, generate keyfile & encrypted file
|
||||
$cryptedData = OCA_Encryption\Crypt::symmetricEncryptFileContentKeyfile( $this->data );
|
||||
|
||||
// Encrypt keyfile
|
||||
$cryptedKey = OCA_Encryption\Crypt::keyEncrypt( $cryptedData['key'], $pair1['publicKey'] );
|
||||
|
||||
// Decrypt keyfile
|
||||
$decryptKey = OCA_Encryption\Crypt::keyDecrypt( $cryptedKey, $pair1['privateKey'] );
|
||||
|
||||
// Decrypt encrypted file
|
||||
$decryptData = OCA_Encryption\Crypt::symmetricDecryptFileContent( $cryptedData['encrypted'], $decryptKey );
|
||||
|
||||
$this->assertEqual( $this->data, $decryptData );
|
||||
|
||||
}
|
||||
|
||||
// function testEncryption(){
|
||||
//
|
Loading…
Reference in New Issue