initial integration of encryption

This commit is contained in:
Robin Appelman 2011-11-24 01:44:54 +01:00 committed by Robin Appelman
parent e53e7990c4
commit f1cbb9effc
5 changed files with 178 additions and 65 deletions

View File

@ -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>

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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;
}