From 70cb053e6b03e2848cb54aea72c3f8e550ece69d Mon Sep 17 00:00:00 2001
From: Robin Appelman <icewind@owncloud.com>
Date: Sat, 5 May 2012 16:48:28 +0200
Subject: [PATCH] improve cryptstream fro writing non-chunksized data

---
 apps/files_encryption/lib/cryptstream.php  | 28 +++++++++++++++++++---
 apps/files_encryption/tests/encryption.php | 11 +++++++++
 2 files changed, 36 insertions(+), 3 deletions(-)

diff --git a/apps/files_encryption/lib/cryptstream.php b/apps/files_encryption/lib/cryptstream.php
index 1a7c595cb83..d6643f32689 100755
--- a/apps/files_encryption/lib/cryptstream.php
+++ b/apps/files_encryption/lib/cryptstream.php
@@ -34,6 +34,7 @@ class OC_CryptStream{
 	private $readBuffer;//for streams that dont support seeking
 	private $meta=array();//header/meta for source stream
 	private $count;
+	private $writeCache;
 
 	public function stream_open($path, $mode, $options, &$opened_path){
 		$path=str_replace('crypt://','',$path);
@@ -57,6 +58,7 @@ class OC_CryptStream{
 	}
 	
 	public function stream_seek($offset, $whence=SEEK_SET){
+		$this->flush();
 		fseek($this->source,$offset,$whence);
 	}
 	
@@ -67,6 +69,7 @@ class OC_CryptStream{
 	public function stream_read($count){
 		//$count will always be 8192 https://bugs.php.net/bug.php?id=21641
 		//This makes this function a lot simpler but will breake everything the moment it's fixed
+		$this->writeCache='';
 		if($count!=8192){
 			OCP\Util::writeLog('files_encryption','php bug 21641 no longer holds, decryption will not work',OCP\Util::FATAL);
 			die();
@@ -84,6 +87,10 @@ class OC_CryptStream{
 		$length=strlen($data);
 		$written=0;
 		$currentPos=ftell($this->source);
+		if($this->writeCache){
+			$data=$this->writeCache.$data;
+			$this->writeCache='';
+		}
 		if($currentPos%8192!=0){
 			//make sure we always start on a block start
 			fseek($this->source,-($currentPos%8192),SEEK_CUR);
@@ -91,11 +98,17 @@ class OC_CryptStream{
 			fseek($this->source,-($currentPos%8192),SEEK_CUR);
 			$block=OC_Crypt::decrypt($encryptedBlock);
 			$data=substr($block,0,$currentPos%8192).$data;
+			fseek($this->source,-($currentPos%8192),SEEK_CUR);
 		}
 		while(strlen($data)>0){
-			$encrypted=OC_Crypt::encrypt(substr($data,0,8192));
-			fwrite($this->source,$encrypted);
-			$data=substr($data,8192);
+			if(strlen($data)<8192){
+				$this->writeCache=$data;
+				$data='';
+			}else{
+				$encrypted=OC_Crypt::encrypt(substr($data,0,8192));
+				fwrite($this->source,$encrypted);
+				$data=substr($data,8192);
+			}
 		}
 		return $length;
 	}
@@ -129,7 +142,16 @@ class OC_CryptStream{
 		return feof($this->source);
 	}
 
+	private function flush(){
+		if($this->writeCache){
+			$encrypted=OC_Crypt::encrypt($this->writeCache);
+			fwrite($this->source,$encrypted);
+			$this->writeCache='';
+		}
+	}
+
 	public function stream_close(){
+		$this->flush();
 		if($this->meta['mode']!='r' and $this->meta['mode']!='rb'){
 			OC_FileCache::put($this->path,array('encrypted'=>true));
 		}
diff --git a/apps/files_encryption/tests/encryption.php b/apps/files_encryption/tests/encryption.php
index 00466cc671c..cf24a225d28 100755
--- a/apps/files_encryption/tests/encryption.php
+++ b/apps/files_encryption/tests/encryption.php
@@ -38,5 +38,16 @@ class Test_Encryption extends UnitTestCase {
 		OC_Crypt::decryptfile($tmpFileEncrypted,$tmpFileDecrypted,$key);
 		$decrypted=file_get_contents($tmpFileDecrypted);
 		$this->assertEqual($decrypted,$source);
+
+		$file=OC::$SERVERROOT.'/core/img/weather-clear.png';
+		$source=file_get_contents($file); //binary file
+		$encrypted=OC_Crypt::encrypt($source,$key);
+		$decrypted=OC_Crypt::decrypt($encrypted,$key);
+		$this->assertEqual($decrypted,$source);
+
+		$encrypted=OC_Crypt::blockEncrypt($source,$key);
+		$decrypted=OC_Crypt::blockDecrypt($encrypted,$key);
+		$this->assertEqual($decrypted,$source);
+
 	}
 }
-- 
GitLab