summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRobin Appelman <icewind1991@gmail.com>2011-11-24 01:44:54 +0100
committerRobin Appelman <icewind@owncloud.com>2012-02-21 20:48:48 +0100
commitf1cbb9effc7e0672dd9dd6fa810aba36c5749898 (patch)
treed4c0625ffc75ab2c25ed9b7e03502110af05667a
parente53e7990c404e3ff2a1b7abad1e4c8ad4f89ee2a (diff)
downloadnextcloud-server-f1cbb9effc7e0672dd9dd6fa810aba36c5749898.tar.gz
nextcloud-server-f1cbb9effc7e0672dd9dd6fa810aba36c5749898.zip
initial integration of encryption
-rw-r--r--apps/files_encryption/appinfo/info.xml11
-rw-r--r--apps/files_encryption/lib/crypt.php (renamed from lib/crypt.php)89
-rw-r--r--apps/files_encryption/lib/cryptstream.php49
-rw-r--r--apps/files_encryption/lib/proxy.php91
-rw-r--r--lib/user.php3
5 files changed, 178 insertions, 65 deletions
diff --git a/apps/files_encryption/appinfo/info.xml b/apps/files_encryption/appinfo/info.xml
new file mode 100644
index 00000000000..a8db06aa3db
--- /dev/null
+++ b/apps/files_encryption/appinfo/info.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<info>
+ <id>files_encryption</id>
+ <name>Encryption</name>
+ <description>Server side encryption of files</description>
+ <version>0.1</version>
+ <licence>AGPL</licence>
+ <author>Robin Appelman</author>
+ <require>3</require>
+ <default_enable/>
+</info>
diff --git a/lib/crypt.php b/apps/files_encryption/lib/crypt.php
index 3e6fa05b85d..4e7739b1d06 100644
--- a/lib/crypt.php
+++ b/apps/files_encryption/lib/crypt.php
@@ -37,20 +37,42 @@ require_once('Crypt_Blowfish/Blowfish.php');
* This class is for crypting and decrypting
*/
class OC_Crypt {
+ static private $bf = null;
- static $encription_extension='.encrypted';
+ public static function loginListener($params){
+ self::init($params['uid'],$params['password']);
+ }
public static function init($login,$password) {
- $_SESSION['user_password'] = $password; // save the password as passcode for the encryption
if(OC_User::isLoggedIn()){
- // does key exist?
- if(!file_exists(OC_Config::getValue( "datadirectory").'/'.$login.'/encryption.key')){
- OC_Crypt::createkey($_SESSION['user_password']);
+ $view=new OC_FilesystemView('/'.$login);
+ if(!$view->file_exists('/encryption.key')){// does key exist?
+ OC_Crypt::createkey($password);
}
+ $key=$view->file_get_contents('/encryption.key');
+ $_SESSION['enckey']=OC_Crypt::decrypt($key, $password);
}
}
-
+ /**
+ * get the blowfish encryption handeler for a key
+ * @param string $key (optional)
+ *
+ * if the key is left out, the default handeler will be used
+ */
+ public static function getBlowfish($key=''){
+ if($key){
+ return new Crypt_Blowfish($key);
+ }else{
+ if(!isset($_SESSION['enckey'])){
+ return false;
+ }
+ if(!self::$bf){
+ self::$bf=new Crypt_Blowfish($_SESSION['enckey']);
+ }
+ return self::$bf;
+ }
+ }
public static function createkey($passcode) {
if(OC_User::isLoggedIn()){
@@ -61,57 +83,58 @@ class OC_Crypt {
$enckey=OC_Crypt::encrypt($key,$passcode);
// Write the file
- $username=OC_USER::getUser();
- @file_put_contents(OC_Config::getValue( "datadirectory").'/'.$username.'/encryption.key', $enckey );
+ $username=OC_USER::getUser();
+ OC_FileProxy::$enabled=false;
+ $view=new OC_FilesystemView('/'.$username);
+ $view->file_put_contents('/encryption.key',$enckey);
+ OC_FileProxy::$enabled=true;
}
}
- public static function changekeypasscode( $newpasscode) {
+ public static function changekeypasscode($oldPassword, $newPassword) {
if(OC_User::isLoggedIn()){
- $username=OC_USER::getUser();
+ $username=OC_USER::getUser();
+ $view=new OC_FilesystemView('/'.$username);
// read old key
- $key=file_get_contents(OC_Config::getValue( "datadirectory").'/'.$username.'/encryption.key');
+ $key=$view->file_get_contents('/encryption.key');
// decrypt key with old passcode
- $key=OC_Crypt::decrypt($key, $_SESSION['user_password']);
+ $key=OC_Crypt::decrypt($key, $oldPassword);
// encrypt again with new passcode
- $key=OC_Crypt::encrypt($key,$newpassword);
+ $key=OC_Crypt::encrypt($key, $newPassword);
// store the new key
- file_put_contents(OC_Config::getValue( "datadirectory").'/'.$username.'/encryption.key', $key );
-
- $_SESSION['user_password']=$newpasscode;
+ $view->file_put_contents('/encryption.key', $key );
}
}
/**
* @brief encrypts an content
* @param $content the cleartext message you want to encrypt
- * @param $key the encryption key
+ * @param $key the encryption key (optional)
* @returns encrypted content
*
* This function encrypts an content
*/
- public static function encrypt( $content, $key) {
- $bf = new Crypt_Blowfish($key);
+ public static function encrypt( $content, $key='') {
+ $bf = self::getBlowfish($key);
return($bf->encrypt($content));
}
-
- /**
- * @brief decryption of an content
- * @param $content the cleartext message you want to decrypt
- * @param $key the encryption key
- * @returns cleartext content
- *
- * This function decrypts an content
- */
- public static function decrypt( $content, $key) {
- $bf = new Crypt_Blowfish($key);
+ /**
+ * @brief decryption of an content
+ * @param $content the cleartext message you want to decrypt
+ * @param $key the encryption key (optional)
+ * @returns cleartext content
+ *
+ * This function decrypts an content
+ */
+ public static function decrypt( $content, $key='') {
+ $bf = self::getBlowfish($key);
return($bf->encrypt($contents));
- }
+ }
/**
* @brief encryption of a file
@@ -181,8 +204,4 @@ class OC_Crypt {
}
return $result;
}
-
-
-
-
}
diff --git a/apps/files_encryption/lib/cryptstream.php b/apps/files_encryption/lib/cryptstream.php
index 7fbfeaa7a86..00dda7352b3 100644
--- a/apps/files_encryption/lib/cryptstream.php
+++ b/apps/files_encryption/lib/cryptstream.php
@@ -22,19 +22,35 @@
/**
* transparently encrypted filestream
+ *
+ * you can use it as wrapper around an existing stream by setting OC_CryptStream::$sourceStreams['foo']=array('path'=>$path,'stream'=>$stream)
+ * and then fopen('crypt://streams/foo');
*/
class OC_CryptStream{
+ public static $sourceStreams=array();
private $source;
+ private $path;
+ private $readBuffer;//for streams that dont support seeking
+ private $meta=array();//header/meta for source stream
public function stream_open($path, $mode, $options, &$opened_path){
$path=str_replace('crypt://','',$path);
- OC_Log::write('files_encryption','open encrypted '.$path. ' in '.$mode,OC_Log::DEBUG);
- OC_FileProxy::$enabled=false;//disable fileproxies so we can open the source file
- $this->source=OC_FileSystem::fopen($path,$mode);
- OC_FileProxy::$enabled=true;
- if(!is_resource($this->source)){
- OC_Log::write('files_encryption','failed to open '.$path,OC_Log::ERROR);
+ if(dirname($path)=='streams' and isset(self::$sourceStreams[basename($path)])){
+ $this->source=self::$sourceStreams[basename($path)]['stream'];
+ $this->path=self::$sourceStreams[basename($path)]['path'];
+ }else{
+ $this->path=$path;
+ OC_Log::write('files_encryption','open encrypted '.$path. ' in '.$mode,OC_Log::DEBUG);
+ OC_FileProxy::$enabled=false;//disable fileproxies so we can open the source file
+ $this->source=OC_FileSystem::fopen($path,$mode);
+ OC_FileProxy::$enabled=true;
+ if(!is_resource($this->source)){
+ OC_Log::write('files_encryption','failed to open '.$path,OC_Log::ERROR);
+ }
+ }
+ if(is_resource($this->source)){
+ $this->meta=stream_get_meta_data($this->source);
}
return is_resource($this->source);
}
@@ -51,14 +67,26 @@ class OC_CryptStream{
$pos=0;
$currentPos=ftell($this->source);
$offset=$currentPos%8192;
- fseek($this->source,-$offset,SEEK_CUR);
$result='';
+ if($offset>0){
+ if($this->meta['seekable']){
+ fseek($this->source,-$offset,SEEK_CUR);//if seeking isnt supported the internal read buffer will be used
+ }else{
+ $pos=strlen($this->readBuffer);
+ $result=$this->readBuffer;
+ }
+ }
while($count>$pos){
$data=fread($this->source,8192);
$pos+=8192;
- $result.=OC_Crypt::decrypt($data);
+ if(strlen($data)){
+ $result.=OC_Crypt::decrypt($data);
+ }
}
- return substr($result,$offset,$count);
+ if(!$this->meta['seekable']){
+ $this->readBuffer=substr($result,$count);
+ }
+ return substr($result,0,$count);
}
public function stream_write($data){
@@ -119,6 +147,9 @@ class OC_CryptStream{
}
public function stream_close(){
+ if(OC_FileCache::inCache($this->path)){
+ OC_FileCache::put($this->path,array('encrypted'=>true));
+ }
return fclose($this->source);
}
} \ No newline at end of file
diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php
index 053ac786c33..173aea785ec 100644
--- a/apps/files_encryption/lib/proxy.php
+++ b/apps/files_encryption/lib/proxy.php
@@ -26,38 +26,98 @@
*/
class OC_FileProxy_Encryption extends OC_FileProxy{
+ private static $blackList=null; //mimetypes blacklisted from encryption
+ private static $metaData=array(); //metadata cache
+
+ /**
+ * check if a file should be encrypted during write
+ * @param string $path
+ * @return bool
+ */
+ private static function shouldEncrypt($path){
+ if(is_null(self::$blackList)){
+ self::$blackList=explode(',',OC_Appconfig::getValue('files_encryption','type_blacklist','jpg,png,jpeg,avi,mpg,mpeg,mkv,mp3,oga,ogv,ogg'));
+ }
+ if(isset(self::$metaData[$path])){
+ $metadata=self::$metaData[$path];
+ }else{
+ $metadata=OC_FileCache::get($path);
+ self::$metaData[$path]=$metadata;
+ }
+ if($metadata['encrypted']){
+ return true;
+ }
+ $extention=substr($path,strrpos($path,'.')+1);
+ if(array_search($extention,self::$blackList)===false){
+ return true;
+ }
+ }
+
+ /**
+ * check if a file is encrypted
+ * @param string $path
+ * @return bool
+ */
+ private static function isEncrypted($path){
+ if(isset(self::$metaData[$path])){
+ $metadata=self::$metaData[$path];
+ }else{
+ $metadata=OC_FileCache::get($path);
+ self::$metaData[$path]=$metadata;
+ }
+ return (bool)$metadata['encrypted'];
+ }
+
public function preFile_put_contents($path,&$data){
- if(substr($path,-4)=='.enc'){
+ if(self::shouldEncrypt($path)){
+ $exists=OC_Filesystem::file_exists($path);
+ $target=fopen('crypt://'.$path,'w');
if (is_resource($data)) {
- $newData='';
while(!feof($data)){
- $block=fread($data,8192);
- $newData.=OC_Crypt::encrypt($block);
+ fwrite($target,fread($data,8192));
}
- $data=$newData;
}else{
- $data=OC_Crypt::blockEncrypt($data);
+ fwrite($target,$data);
}
+ //fake the normal hooks
+ OC_Hook::emit( 'OC_Filesystem', 'post_create', array( 'path' => $path));
+ OC_Hook::emit( 'OC_Filesystem', 'post_write', array( 'path' => $path));
+ return false;
}
}
public function postFile_get_contents($path,$data){
- if(substr($path,-4)=='.enc'){
- return OC_Crypt::blockDecrypt($data);
+ if(self::isEncrypted($path)){
+ $data=OC_Crypt::blockDecrypt($data);
}
+ return $data;
}
public function postFopen($path,&$result){
- if(substr($path,-4)=='.enc'){
- $meta=stream_get_meta_data($result);
+ if(!$result){
+ return $result;
+ }
+ $meta=stream_get_meta_data($result);
+ if(self::isEncrypted($path)){
fclose($result);
- OC_log::write('file_encryption','mode: '.$meta['mode']);
+ $result=fopen('crypt://'.$path,$meta['mode']);
+ }elseif(self::shouldEncrypt($path) and $meta['mode']!='r'){
+ if(OC_Filesystem::file_exists($path)){
+ //first encrypt the target file so we don't end up with a half encrypted file
+ OC_Log::write('files_encryption','Decrypting '.$path.' before writing',OC_Log::DEBUG);
+ if($result){
+ fclose($result);
+ }
+ $tmpFile=OC_Filesystem::toTmpFile($path);
+ OC_Filesystem::fromTmpFile($tmpFile,$path);
+ }
$result=fopen('crypt://'.$path,$meta['mode']);
}
+ return $result;
}
public function preReadFile($path){
- if(substr($path,-4)=='.enc'){
+ if(self::isEncrypted($path)){
$stream=fopen('crypt://'.$path,'r');
while(!feof($stream)){
print(fread($stream,8192));
@@ -65,11 +125,4 @@ class OC_FileProxy_Encryption extends OC_FileProxy{
return false;//cancel the original request
}
}
-
- public function postGetMimeType($path,$result){
- if(substr($path,-4)=='.enc'){
- return 'text/plain';
- }
- return $result;
- }
}
diff --git a/lib/user.php b/lib/user.php
index 34f44f572e0..aa828de52f5 100644
--- a/lib/user.php
+++ b/lib/user.php
@@ -195,8 +195,8 @@ class OC_User {
if( $run ){
$uid=self::checkPassword( $uid, $password );
if($uid){
- OC_Crypt::init($uid,$password);
return self::setUserId($uid);
+ OC_Hook::emit( "OC_User", "post_login", array( "uid" => $uid, 'password'=>$password ));
}
}
return false;
@@ -209,7 +209,6 @@ class OC_User {
*/
public static function setUserId($uid) {
$_SESSION['user_id'] = $uid;
- OC_Hook::emit( "OC_User", "post_login", array( "uid" => $uid ));
return true;
}