initial integration of encryption
This commit is contained in:
parent
e53e7990c4
commit
f1cbb9effc
|
@ -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>
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue