Development snapshot
Crypt{} & Util{} unit tests now passing locally Added keymanager unit tests
This commit is contained in:
parent
665261dc9a
commit
7fe9245636
|
@ -54,7 +54,7 @@ class Hooks {
|
||||||
|
|
||||||
\OC_FileProxy::$enabled = false;
|
\OC_FileProxy::$enabled = false;
|
||||||
|
|
||||||
$encryptedKey = Keymanager::getPrivateKey( $params['uid'], $view );
|
$encryptedKey = Keymanager::getPrivateKey( $view, $params['uid'] );
|
||||||
|
|
||||||
\OC_FileProxy::$enabled = true;
|
\OC_FileProxy::$enabled = true;
|
||||||
|
|
||||||
|
|
|
@ -628,7 +628,7 @@ class Crypt {
|
||||||
public static function changekeypasscode($oldPassword, $newPassword) {
|
public static function changekeypasscode($oldPassword, $newPassword) {
|
||||||
|
|
||||||
if(\OCP\User::isLoggedIn()){
|
if(\OCP\User::isLoggedIn()){
|
||||||
$key = Keymanager::getPrivateKey();
|
$key = Keymanager::getPrivateKey( $user, $view );
|
||||||
if ( ($key = Crypt::symmetricDecryptFileContent($key,$oldpasswd)) ) {
|
if ( ($key = Crypt::symmetricDecryptFileContent($key,$oldpasswd)) ) {
|
||||||
if ( ($key = Crypt::symmetricEncryptFileContent($key, $newpasswd)) ) {
|
if ( ($key = Crypt::symmetricEncryptFileContent($key, $newpasswd)) ) {
|
||||||
Keymanager::setPrivateKey($key);
|
Keymanager::setPrivateKey($key);
|
||||||
|
|
|
@ -23,7 +23,8 @@
|
||||||
namespace OCA\Encryption;
|
namespace OCA\Encryption;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class provides basic operations to read/write encryption keys from/to the filesystem
|
* @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 {
|
||||||
|
|
||||||
|
@ -35,60 +36,46 @@ class Keymanager {
|
||||||
* @return string private key or false
|
* @return string private key or false
|
||||||
* @note the key returned by this method must be decrypted before use
|
* @note the key returned by this method must be decrypted before use
|
||||||
*/
|
*/
|
||||||
public static function getPrivateKey( $user, $view ) {
|
public static function getPrivateKey( $view, $user ) {
|
||||||
|
|
||||||
$view->chroot( '/' . $user . '/' . 'files_encryption' );
|
|
||||||
return $view->file_get_contents( '/' . $user.'.private.key' );
|
|
||||||
|
|
||||||
|
return $view->file_get_contents( '/' . $user . '/' . 'files_encryption' . '/' . $user.'.private.key' );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief retrieve public key for a specified user
|
* @brief retrieve public key for a specified user
|
||||||
* @return string public key or false
|
* @return string public key or false
|
||||||
*/
|
*/
|
||||||
public static function getPublicKey( $userId = NULL ) {
|
public static function getPublicKey( $view, $userId ) {
|
||||||
|
|
||||||
// If the username wasn't specified, fetch it
|
return $view->file_get_contents( '/public-keys/' . '/' . $userId . '.public.key' );
|
||||||
if ( ! $userId ) {
|
|
||||||
|
|
||||||
$userId = \OCP\User::getUser();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create new view with the right
|
|
||||||
$view = new \OC_FilesystemView( '/public-keys/' );
|
|
||||||
|
|
||||||
return $view->file_get_contents( '/' . $userId . '.public.key' );
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief retrieve both keys from a user (private and public)
|
* @brief retrieve both keys from a user (private and public)
|
||||||
*
|
* @return array keys: privateKey, publicKey
|
||||||
* @return string private key or false
|
|
||||||
*/
|
*/
|
||||||
public static function getUserKeys() {
|
public static function getUserKeys( $view, $userId ) {
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
'privatekey' => self::getPrivateKey(),
|
'publicKey' => self::getPublicKey( $view, $userId )
|
||||||
'publickey' => self::getPublicKey(),
|
, 'privateKey' => self::getPrivateKey( $view, $userId )
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief retrieve a list of the public key from all users with access to the file
|
* @brief Retrieve public keys of all users with access to a file
|
||||||
*
|
* @param string $path Path to file
|
||||||
* @param string path to file
|
|
||||||
* @return array of public keys for the given file
|
* @return array of public keys for the given file
|
||||||
|
* @note Checks that the sharing app is enabled should be performed
|
||||||
|
* by client code, that isn't checked here
|
||||||
*/
|
*/
|
||||||
public static function getPublicKeys( $path ) {
|
public static function getPublicKeys( $view, $userId, $filePath ) {
|
||||||
|
|
||||||
$userId = \OCP\User::getUser();
|
|
||||||
|
|
||||||
$path = ltrim( $path, '/' );
|
$path = ltrim( $path, '/' );
|
||||||
|
|
||||||
$filepath = '/'.$userId.'/files/'.$path;
|
$filepath = '/' . $userId . '/files/' . $filePath;
|
||||||
|
|
||||||
// Check if sharing is enabled
|
// Check if sharing is enabled
|
||||||
if ( OC_App::isEnabled( 'files_sharing' ) ) {
|
if ( OC_App::isEnabled( 'files_sharing' ) ) {
|
||||||
|
@ -157,34 +144,30 @@ class Keymanager {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief retrieve keyfile for an encrypted file
|
* @brief retrieve keyfile for an encrypted file
|
||||||
*
|
|
||||||
* @param string file name
|
* @param string file name
|
||||||
* @return string file key or false
|
* @return string file key or false
|
||||||
* @note The keyfile returned is asymmetrically encrypted. Decryption
|
* @note The keyfile returned is asymmetrically encrypted. Decryption
|
||||||
* of the keyfile must be performed by client code
|
* of the keyfile must be performed by client code
|
||||||
*/
|
*/
|
||||||
public static function getFileKey( $path, $staticUserClass = 'OCP\User' ) {
|
public static function getFileKey( $view, $userId, $filePath ) {
|
||||||
|
|
||||||
$keypath = ltrim( $path, '/' );
|
$filePath_f = ltrim( $filePath, '/' );
|
||||||
$user = $staticUserClass::getUser();
|
|
||||||
|
|
||||||
// // update $keypath and $user if path point to a file shared by someone else
|
// // update $keypath and $userId 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 = ?" );
|
// $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));
|
// $result = $query->execute( array ('/'.$userId.'/files/'.$keypath, $userId));
|
||||||
//
|
//
|
||||||
// if ($row = $result->fetchRow()) {
|
// if ($row = $result->fetchRow()) {
|
||||||
//
|
//
|
||||||
// $keypath = $row['source'];
|
// $keypath = $row['source'];
|
||||||
// $keypath_parts = explode( '/', $keypath );
|
// $keypath_parts = explode( '/', $keypath );
|
||||||
// $user = $keypath_parts[1];
|
// $userId = $keypath_parts[1];
|
||||||
// $keypath = str_replace( '/' . $user . '/files/', '', $keypath );
|
// $keypath = str_replace( '/' . $userId . '/files/', '', $keypath );
|
||||||
//
|
//
|
||||||
// }
|
// }
|
||||||
|
|
||||||
$view = new \OC_FilesystemView('/'.$user.'/files_encryption/keyfiles/');
|
return $this->view->file_get_contents( '/' . $userId . '/files_encryption/keyfiles/' . $filePath_f );
|
||||||
|
|
||||||
return $view->file_get_contents( $keypath . '.key' );
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -91,6 +91,10 @@ class Proxy extends \OC_FileProxy {
|
||||||
|
|
||||||
if ( !is_resource( $data ) ) { //stream put contents should have been converted to fopen
|
if ( !is_resource( $data ) ) { //stream put contents should have been converted to fopen
|
||||||
|
|
||||||
|
$userId = \OCP\USER::getUser();
|
||||||
|
|
||||||
|
$rootView = new \OC_FilesystemView( '/' );
|
||||||
|
|
||||||
// Set the filesize for userland, before encrypting
|
// Set the filesize for userland, before encrypting
|
||||||
$size = strlen( $data );
|
$size = strlen( $data );
|
||||||
|
|
||||||
|
@ -98,7 +102,7 @@ class Proxy extends \OC_FileProxy {
|
||||||
\OC_FileProxy::$enabled = false;
|
\OC_FileProxy::$enabled = false;
|
||||||
|
|
||||||
// Encrypt plain data and fetch key
|
// Encrypt plain data and fetch key
|
||||||
$encrypted = Crypt::keyEncryptKeyfile( $data, Keymanager::getPublicKey() );
|
$encrypted = Crypt::keyEncryptKeyfile( $data, Keymanager::getPublicKey( $rootView, $userId ) );
|
||||||
|
|
||||||
// Replace plain content with encrypted content by reference
|
// Replace plain content with encrypted content by reference
|
||||||
$data = $encrypted['data'];
|
$data = $encrypted['data'];
|
||||||
|
@ -110,7 +114,7 @@ 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( '/' . \OCP\USER::getUser() . '/files_encryption/keyfiles' );
|
$view = new \OC_FilesystemView( '/' . $userId . '/files_encryption/keyfiles' );
|
||||||
|
|
||||||
// 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( $filePath, $encrypted['key'], $view, '\OC_DB' );
|
||||||
|
|
|
@ -63,7 +63,8 @@ class Stream {
|
||||||
private $publicKey;
|
private $publicKey;
|
||||||
private $keyfile;
|
private $keyfile;
|
||||||
private $encKeyfile;
|
private $encKeyfile;
|
||||||
private static $view;
|
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 ) {
|
public function stream_open( $path, $mode, $options, &$opened_path ) {
|
||||||
|
|
||||||
|
@ -76,6 +77,13 @@ class Stream {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set rootview object if necessary
|
||||||
|
if ( ! $this->rootView ) {
|
||||||
|
|
||||||
|
$this->rootView = new \OC_FilesystemView( $this->userId . '/' );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
$this->userId = \OCP\User::getUser();
|
$this->userId = \OCP\User::getUser();
|
||||||
|
|
||||||
// Get the bare file path
|
// Get the bare file path
|
||||||
|
@ -332,7 +340,7 @@ class Stream {
|
||||||
|
|
||||||
$this->keyfile = Crypt::generateKey();
|
$this->keyfile = Crypt::generateKey();
|
||||||
|
|
||||||
$this->publicKey = Keymanager::getPublicKey( $this->userId );
|
$this->publicKey = Keymanager::getPublicKey( $this->rootView, $this->userId );
|
||||||
|
|
||||||
$this->encKeyfile = Crypt::keyEncrypt( $this->keyfile, $this->publicKey );
|
$this->encKeyfile = Crypt::keyEncrypt( $this->keyfile, $this->publicKey );
|
||||||
|
|
||||||
|
|
|
@ -7,21 +7,6 @@
|
||||||
* See the COPYING-README file.
|
* See the COPYING-README file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Load mockery files
|
|
||||||
require_once 'Mockery/Loader.php';
|
|
||||||
require_once 'Hamcrest/Hamcrest.php';
|
|
||||||
$loader = new \Mockery\Loader;
|
|
||||||
$loader->register();
|
|
||||||
|
|
||||||
use \Mockery as m;
|
|
||||||
|
|
||||||
// Overload Session{} with a mock object before it is included
|
|
||||||
$adminEncPriKey = realpath( dirname(__FILE__).'/../../../data/admin/files_encryption/admin.private.key' );
|
|
||||||
$adminDePriKey = OCA\Encryption\Crypt::symmetricDecryptFileContent( $adminEncPriKey, 'admin' );
|
|
||||||
|
|
||||||
$mockSession = m::mock('overload:OCA\Encryption\Session');
|
|
||||||
$mockSession->shouldReceive( 'getPrivateKey' )->andReturn( file_get_contents( $adminDePriKey ) );
|
|
||||||
|
|
||||||
//require_once "PHPUnit/Framework/TestCase.php";
|
//require_once "PHPUnit/Framework/TestCase.php";
|
||||||
require_once realpath( dirname(__FILE__).'/../../../3rdparty/Crypt_Blowfish/Blowfish.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/base.php' );
|
||||||
|
@ -38,7 +23,13 @@ use OCA\Encryption;
|
||||||
// encryption key needs to be saved in the session
|
// encryption key needs to be saved in the session
|
||||||
\OC_User::login( 'admin', 'admin' );
|
\OC_User::login( 'admin', 'admin' );
|
||||||
|
|
||||||
//trigger_error("session = ".var_export($_SESSION, 1));
|
/**
|
||||||
|
* @note It would be better to use Mockery here for mocking out the session
|
||||||
|
* handling process, and isolate calls to session class and data from the unit
|
||||||
|
* tests relating to them (stream etc.). However getting mockery to work and
|
||||||
|
* overload classes whilst also using the OC autoloader is difficult due to
|
||||||
|
* load order Pear errors.
|
||||||
|
*/
|
||||||
|
|
||||||
class Test_Crypt extends \PHPUnit_Framework_TestCase {
|
class Test_Crypt extends \PHPUnit_Framework_TestCase {
|
||||||
|
|
||||||
|
@ -66,8 +57,6 @@ class Test_Crypt extends \PHPUnit_Framework_TestCase {
|
||||||
|
|
||||||
function tearDown() {
|
function tearDown() {
|
||||||
|
|
||||||
m::close();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function testGenerateKey() {
|
function testGenerateKey() {
|
||||||
|
@ -247,7 +236,7 @@ class Test_Crypt extends \PHPUnit_Framework_TestCase {
|
||||||
$this->assertNotEquals( $this->dataShort, $retreivedCryptedFile );
|
$this->assertNotEquals( $this->dataShort, $retreivedCryptedFile );
|
||||||
|
|
||||||
// Get private key
|
// Get private key
|
||||||
$encryptedPrivateKey = Encryption\Keymanager::getPrivateKey( $this->userId, $this->view );
|
$encryptedPrivateKey = Encryption\Keymanager::getPrivateKey( $this->view, $this->userId );
|
||||||
|
|
||||||
$decryptedPrivateKey = Encryption\Crypt::symmetricDecryptFileContent( $encryptedPrivateKey, $this->pass );
|
$decryptedPrivateKey = Encryption\Crypt::symmetricDecryptFileContent( $encryptedPrivateKey, $this->pass );
|
||||||
|
|
||||||
|
@ -303,7 +292,7 @@ class Test_Crypt extends \PHPUnit_Framework_TestCase {
|
||||||
|
|
||||||
|
|
||||||
// Get private key
|
// Get private key
|
||||||
$encryptedPrivateKey = Encryption\Keymanager::getPrivateKey( $this->userId, $this->view );
|
$encryptedPrivateKey = Encryption\Keymanager::getPrivateKey( $this->view, $this->userId );
|
||||||
|
|
||||||
$decryptedPrivateKey = Encryption\Crypt::symmetricDecryptFileContent( $encryptedPrivateKey, $this->pass );
|
$decryptedPrivateKey = Encryption\Crypt::symmetricDecryptFileContent( $encryptedPrivateKey, $this->pass );
|
||||||
|
|
||||||
|
|
|
@ -25,11 +25,15 @@ class Test_Keymanager extends \PHPUnit_Framework_TestCase {
|
||||||
$this->data = realpath( dirname(__FILE__).'/../lib/crypt.php' );
|
$this->data = realpath( dirname(__FILE__).'/../lib/crypt.php' );
|
||||||
$this->user = 'admin';
|
$this->user = 'admin';
|
||||||
$this->passphrase = 'admin';
|
$this->passphrase = 'admin';
|
||||||
|
$this->filePath = '/testing';
|
||||||
$this->view = new \OC_FilesystemView( '' );
|
$this->view = new \OC_FilesystemView( '' );
|
||||||
|
|
||||||
// Disable encryption proxy to prevent recursive calls
|
// Disable encryption proxy to prevent recursive calls
|
||||||
\OC_FileProxy::$enabled = false;
|
\OC_FileProxy::$enabled = false;
|
||||||
|
|
||||||
|
// Notify system which iser is logged in etc.
|
||||||
|
\OC_User::setUserId( 'admin' );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function tearDown(){
|
function tearDown(){
|
||||||
|
@ -38,17 +42,29 @@ class Test_Keymanager extends \PHPUnit_Framework_TestCase {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function testGetEncryptedPrivateKey() {
|
function testGetPrivateKey() {
|
||||||
|
|
||||||
$key = Encryption\Keymanager::getPrivateKey( $this->user, $this->view );
|
$key = Encryption\Keymanager::getPrivateKey( $this->view, $this->user );
|
||||||
|
|
||||||
$this->assertEquals( 2302, strlen( $key ) );
|
|
||||||
|
|
||||||
|
// Will this length vary? Perhaps we should use a range instead
|
||||||
|
$this->assertEquals( 2296, strlen( $key ) );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function testGetPublicKey() {
|
||||||
|
|
||||||
|
$key = Encryption\Keymanager::getPublicKey( $this->view, $this->user );
|
||||||
|
|
||||||
|
$this->assertEquals( 451, strlen( $key ) );
|
||||||
|
|
||||||
|
$this->assertEquals( '-----BEGIN PUBLIC KEY-----', substr( $key, 0, 26 ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
function testSetFileKey() {
|
function testSetFileKey() {
|
||||||
|
|
||||||
# NOTE: This cannot be tested until we are able to break out of the FileSystemView data directory root
|
# NOTE: This cannot be tested until we are able to break out
|
||||||
|
# of the FileSystemView data directory root
|
||||||
|
|
||||||
// $key = Crypt::symmetricEncryptFileContentKeyfile( $this->data, 'hat' );
|
// $key = Crypt::symmetricEncryptFileContentKeyfile( $this->data, 'hat' );
|
||||||
//
|
//
|
||||||
|
@ -62,21 +78,39 @@ class Test_Keymanager extends \PHPUnit_Framework_TestCase {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function testGetDecryptedPrivateKey() {
|
function testGetPrivateKey_decrypt() {
|
||||||
|
|
||||||
$key = Encryption\Keymanager::getPrivateKey( $this->user, $this->view );
|
$key = Encryption\Keymanager::getPrivateKey( $this->view, $this->user );
|
||||||
|
|
||||||
# TODO: replace call to Crypt with a mock object?
|
# TODO: replace call to Crypt with a mock object?
|
||||||
$decrypted = Encryption\Crypt::symmetricDecryptFileContent( $key, $this->passphrase );
|
$decrypted = Encryption\Crypt::symmetricDecryptFileContent( $key, $this->passphrase );
|
||||||
|
|
||||||
var_dump($decrypted);
|
$this->assertEquals( 1704, strlen( $decrypted ) );
|
||||||
|
|
||||||
$this->assertEquals( 1708, strlen( $decrypted ) );
|
|
||||||
|
|
||||||
$this->assertEquals( '-----BEGIN PRIVATE KEY-----', substr( $decrypted, 0, 27 ) );
|
$this->assertEquals( '-----BEGIN PRIVATE KEY-----', substr( $decrypted, 0, 27 ) );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function testGetUserKeys() {
|
||||||
|
|
||||||
|
$keys = Encryption\Keymanager::getUserKeys( $this->view, $this->user );
|
||||||
|
|
||||||
|
$this->assertEquals( 451, strlen( $keys['publicKey'] ) );
|
||||||
|
$this->assertEquals( '-----BEGIN PUBLIC KEY-----', substr( $keys['publicKey'], 0, 26 ) );
|
||||||
|
$this->assertEquals( 2296, strlen( $keys['privateKey'] ) );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function testGetPublicKeys() {
|
||||||
|
|
||||||
|
# TODO: write me
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function testGetFileKey() {
|
||||||
|
|
||||||
|
// Encryption\Keymanager::getFileKey( $this->view, $this->user, $this->filePath );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue