summaryrefslogtreecommitdiffstats
path: root/lib/private/files/stream/encryption.php
diff options
context:
space:
mode:
Diffstat (limited to 'lib/private/files/stream/encryption.php')
-rw-r--r--lib/private/files/stream/encryption.php126
1 files changed, 87 insertions, 39 deletions
diff --git a/lib/private/files/stream/encryption.php b/lib/private/files/stream/encryption.php
index ddef9067bad..b4e06c99943 100644
--- a/lib/private/files/stream/encryption.php
+++ b/lib/private/files/stream/encryption.php
@@ -31,6 +31,9 @@ class Encryption extends Wrapper {
/** @var \OC\Encryption\Util */
protected $util;
+ /** @var \OC\Encryption\File */
+ protected $file;
+
/** @var \OCP\Encryption\IEncryptionModule */
protected $encryptionModule;
@@ -43,6 +46,9 @@ class Encryption extends Wrapper {
/** @var string */
protected $internalPath;
+ /** @var string */
+ protected $cache;
+
/** @var integer */
protected $size;
@@ -72,13 +78,16 @@ class Encryption extends Wrapper {
/**
* user who perform the read/write operation null for public access
*
- * @var string
+ * @var string
*/
protected $uid;
/** @var bool */
protected $readOnly;
+ /** @var bool */
+ protected $writeFlag;
+
/** @var array */
protected $expectedContextProperties;
@@ -91,6 +100,7 @@ class Encryption extends Wrapper {
'encryptionModule',
'header',
'uid',
+ 'file',
'util',
'size',
'unencryptedSize',
@@ -106,11 +116,12 @@ class Encryption extends Wrapper {
* @param string $internalPath relative to mount point
* @param string $fullPath relative to data/
* @param array $header
- * @param sting $uid
+ * @param string $uid
* @param \OCP\Encryption\IEncryptionModule $encryptionModule
* @param \OC\Files\Storage\Storage $storage
- * @param OC\Files\Storage\Wrapper\Encryption $encStorage
+ * @param \OC\Files\Storage\Wrapper\Encryption $encStorage
* @param \OC\Encryption\Util $util
+ * @param \OC\Encryption\File $file
* @param string $mode
* @param int $size
* @param int $unencryptedSize
@@ -119,9 +130,15 @@ class Encryption extends Wrapper {
* @throws \BadMethodCallException
*/
public static function wrap($source, $internalPath, $fullPath, array $header,
- $uid, \OCP\Encryption\IEncryptionModule $encryptionModule,
- \OC\Files\Storage\Storage $storage, \OC\Files\Storage\Wrapper\Encryption $encStorage,
- \OC\Encryption\Util $util, $mode, $size, $unencryptedSize) {
+ $uid,
+ \OCP\Encryption\IEncryptionModule $encryptionModule,
+ \OC\Files\Storage\Storage $storage,
+ \OC\Files\Storage\Wrapper\Encryption $encStorage,
+ \OC\Encryption\Util $util,
+ \OC\Encryption\File $file,
+ $mode,
+ $size,
+ $unencryptedSize) {
$context = stream_context_create(array(
'ocencryption' => array(
@@ -133,6 +150,7 @@ class Encryption extends Wrapper {
'header' => $header,
'uid' => $uid,
'util' => $util,
+ 'file' => $file,
'size' => $size,
'unencryptedSize' => $unencryptedSize,
'encryptionStorage' => $encStorage
@@ -180,7 +198,7 @@ class Encryption extends Wrapper {
$context = parent::loadContext($name);
foreach ($this->expectedContextProperties as $property) {
- if (isset($context[$property])) {
+ if (array_key_exists($property, $context)) {
$this->{$property} = $context[$property];
} else {
throw new \BadMethodCallException('Invalid context, "' . $property . '" options not set');
@@ -194,6 +212,8 @@ class Encryption extends Wrapper {
$this->loadContext('ocencryption');
$this->position = 0;
+ $this->cache = '';
+ $this->writeFlag = false;
$this->unencryptedBlockSize = $this->encryptionModule->getUnencryptedBlockSize();
if (
@@ -216,7 +236,7 @@ class Encryption extends Wrapper {
$sharePath = dirname($path);
}
- $accessList = $this->util->getSharingUsersArray($sharePath);
+ $accessList = $this->file->getAccessList($sharePath);
$this->newHeader = $this->encryptionModule->begin($this->fullPath, $this->uid, $this->header, $accessList);
return true;
@@ -228,25 +248,26 @@ class Encryption extends Wrapper {
$result = '';
// skip the header if we read the file from the beginning
- if ($this->position === 0 && !empty($this->header)) {
- parent::stream_read($this->util->getBlockSize());
+ if ($this->position === 0) {
+ parent::stream_read($this->util->getHeaderSize());
}
+// $count = min($count, $this->unencryptedSize - $this->position);
while ($count > 0) {
$remainingLength = $count;
// update the cache of the current block
- $data = parent::stream_read($this->util->getBlockSize());
- $decrypted = $this->encryptionModule->decrypt($data);
+ $this->readCache();
// determine the relative position in the current block
$blockPosition = ($this->position % $this->unencryptedBlockSize);
// if entire read inside current block then only position needs to be updated
if ($remainingLength < ($this->unencryptedBlockSize - $blockPosition)) {
- $result .= substr($decrypted, $blockPosition, $remainingLength);
+ $result .= substr($this->cache, $blockPosition, $remainingLength);
$this->position += $remainingLength;
$count = 0;
- // otherwise remainder of current block is fetched, the block is flushed and the position updated
+ // otherwise remainder of current block is fetched, the block is flushed and the position updated
} else {
- $result .= substr($decrypted, $blockPosition);
+ $result .= substr($this->cache, $blockPosition);
+ $this->flush();
$this->position += ($this->unencryptedBlockSize - $blockPosition);
$count -= ($this->unencryptedBlockSize - $blockPosition);
}
@@ -259,6 +280,7 @@ class Encryption extends Wrapper {
if ($this->position === 0) {
$this->writeHeader();
+ $this->size+=$this->util->getHeaderSize();
}
$length = 0;
@@ -266,9 +288,8 @@ class Encryption extends Wrapper {
while (strlen($data) > 0) {
$remainingLength = strlen($data);
- // read current block
- $currentBlock = parent::stream_read($this->util->getBlockSize());
- $decrypted = $this->encryptionModule->decrypt($currentBlock, $this->uid);
+ // set the cache to the current 6126 block
+ $this->readCache();
// for seekable streams the pointer is moved back to the beginning of the encrypted block
// flush will start writing there when the position moves to another block
@@ -277,7 +298,10 @@ class Encryption extends Wrapper {
$resultFseek = parent::stream_seek($positionInFile);
// only allow writes on seekable streams, or at the end of the encrypted stream
- if ($resultFseek || $positionInFile === $this->size) {
+ if (!($this->readOnly) && ($resultFseek || $positionInFile === $this->size)) {
+
+ // switch the writeFlag so flush() will write the block
+ $this->writeFlag = true;
// determine the relative position in the current block
$blockPosition = ($this->position % $this->unencryptedBlockSize);
@@ -285,28 +309,22 @@ class Encryption extends Wrapper {
// if so, overwrite existing data (if any)
// update position and liberate $data
if ($remainingLength < ($this->unencryptedBlockSize - $blockPosition)) {
- $decrypted = substr($decrypted, 0, $blockPosition)
- . $data . substr($decrypted, $blockPosition + $remainingLength);
- $encrypted = $this->encryptionModule->encrypt($decrypted);
- parent::stream_write($encrypted);
+ $this->cache = substr($this->cache, 0, $blockPosition)
+ . $data . substr($this->cache, $blockPosition + $remainingLength);
$this->position += $remainingLength;
$length += $remainingLength;
$data = '';
- // if $data doens't fit the current block, the fill the current block and reiterate
- // after the block is filled, it is flushed and $data is updatedxxx
+ // if $data doesn't fit the current block, the fill the current block and reiterate
+ // after the block is filled, it is flushed and $data is updatedxxx
} else {
- $decrypted = substr($decrypted, 0, $blockPosition) .
+ $this->cache = substr($this->cache, 0, $blockPosition) .
substr($data, 0, $this->unencryptedBlockSize - $blockPosition);
- $encrypted = $this->encryptionModule->encrypt($decrypted);
- parent::stream_write($encrypted);
+ $this->flush();
$this->position += ($this->unencryptedBlockSize - $blockPosition);
- $this->size = max($this->size, $this->stream_tell());
$length += ($this->unencryptedBlockSize - $blockPosition);
$data = substr($data, $this->unencryptedBlockSize - $blockPosition);
}
} else {
- $encrypted = $this->encryptionModule->encrypt($data);
- parent::stream_write($encrypted);
$data = '';
}
}
@@ -345,7 +363,11 @@ class Encryption extends Wrapper {
$newFilePosition = floor($newPosition / $this->unencryptedBlockSize)
* $this->util->getBlockSize() + $this->util->getHeaderSize();
+ $oldFilePosition = parent::stream_tell();
if (parent::stream_seek($newFilePosition)) {
+ parent::stream_seek($oldFilePosition);
+ $this->flush();
+ parent::stream_seek($newFilePosition);
$this->position = $newPosition;
$return = true;
}
@@ -355,13 +377,6 @@ class Encryption extends Wrapper {
public function stream_close() {
$this->flush();
- return parent::stream_close();
- }
-
- /**
- * tell encryption module that we are done and write remaining data to the file
- */
- protected function flush() {
$remainingData = $this->encryptionModule->end($this->fullPath);
if ($this->readOnly === false) {
if(!empty($remainingData)) {
@@ -369,17 +384,50 @@ class Encryption extends Wrapper {
}
$this->encryptionStorage->updateUnencryptedSize($this->fullPath, $this->unencryptedSize);
}
+ return parent::stream_close();
}
+ /**
+ * write block to file
+ */
+ protected function flush() {
+ // write to disk only when writeFlag was set to 1
+ if ($this->writeFlag) {
+ // Disable the file proxies so that encryption is not
+ // automatically attempted when the file is written to disk -
+ // we are handling that separately here and we don't want to
+ // get into an infinite loop
+ $encrypted = $this->encryptionModule->encrypt($this->cache);
+ parent::stream_write($encrypted);
+ $this->writeFlag = false;
+ $this->size = max($this->size, parent::stream_tell());
+ }
+ // always empty the cache (otherwise readCache() will not fill it with the new block)
+ $this->cache = '';
+ }
+
+ /**
+ * read block to file
+ */
+ protected function readCache() {
+ // cache should always be empty string when this function is called
+ // don't try to fill the cache when trying to write at the end of the unencrypted file when it coincides with new block
+ if ($this->cache === '' && !($this->position === $this->unencryptedSize && ($this->position % $this->unencryptedBlockSize) === 0)) {
+ // Get the data from the file handle
+ $data = parent::stream_read($this->util->getBlockSize());
+ $this->cache = $this->encryptionModule->decrypt($data);
+ }
+ }
/**
* write header at beginning of encrypted file
*
+ * @return integer
* @throws EncryptionHeaderKeyExistsException if header key is already in use
*/
private function writeHeader() {
$header = $this->util->createHeader($this->newHeader, $this->encryptionModule);
- parent::stream_write($header);
+ return parent::stream_write($header);
}
}