diff options
-rw-r--r-- | apps/encryption/lib/crypto/crypt.php | 9 | ||||
-rw-r--r-- | apps/encryption/lib/crypto/encryption.php | 14 | ||||
-rw-r--r-- | apps/encryption/tests/lib/crypto/encryptionTest.php | 27 | ||||
-rw-r--r-- | apps/encryption_dummy/lib/dummymodule.php | 3 | ||||
-rw-r--r-- | lib/private/files/storage/wrapper/encryption.php | 26 | ||||
-rw-r--r-- | lib/private/files/stream/encryption.php | 24 | ||||
-rw-r--r-- | lib/public/encryption/iencryptionmodule.php | 3 | ||||
-rw-r--r-- | tests/lib/files/stream/encryption.php | 2 |
8 files changed, 88 insertions, 20 deletions
diff --git a/apps/encryption/lib/crypto/crypt.php b/apps/encryption/lib/crypto/crypt.php index 9ada9200551..782dbbe5a35 100644 --- a/apps/encryption/lib/crypto/crypt.php +++ b/apps/encryption/lib/crypto/crypt.php @@ -210,6 +210,15 @@ class Crypt { } /** + * get legacy cipher + * + * @return string + */ + public function getLegacyCipher() { + return self::LEGACY_CIPHER; + } + + /** * @param string $encryptedContent * @param string $iv * @return string diff --git a/apps/encryption/lib/crypto/encryption.php b/apps/encryption/lib/crypto/encryption.php index 8498b4223e1..3f298481680 100644 --- a/apps/encryption/lib/crypto/encryption.php +++ b/apps/encryption/lib/crypto/encryption.php @@ -101,6 +101,7 @@ class Encryption implements IEncryptionModule { * * @param string $path to the file * @param string $user who read/write the file + * @param string $mode php stream open mode * @param array $header contains the header data read from the file * @param array $accessList who has access to the file contains the key 'users' and 'public' * @@ -108,12 +109,19 @@ class Encryption implements IEncryptionModule { * written to the header, in case of a write operation * or if no additional data is needed return a empty array */ - public function begin($path, $user, array $header, array $accessList) { + public function begin($path, $user, $mode, array $header, array $accessList) { if (isset($header['cipher'])) { $this->cipher = $header['cipher']; - } else { + } else if ( + $mode === 'w' + || $mode === 'w+' + || $mode === 'wb' + || $mode === 'wb+' + ) { $this->cipher = $this->crypt->getCipher(); + } else { + $this->cipher = $this->crypt->getLegacyCipher(); } $this->path = $this->getPathToRealFile($path); @@ -234,7 +242,7 @@ class Encryption implements IEncryptionModule { public function decrypt($data) { $result = ''; if (!empty($data)) { - $result = $this->crypt->symmetricDecryptFileContent($data, $this->fileKey); + $result = $this->crypt->symmetricDecryptFileContent($data, $this->fileKey, $this->cipher); } return $result; } diff --git a/apps/encryption/tests/lib/crypto/encryptionTest.php b/apps/encryption/tests/lib/crypto/encryptionTest.php index 9e14a70ebb0..500433c77d4 100644 --- a/apps/encryption/tests/lib/crypto/encryptionTest.php +++ b/apps/encryption/tests/lib/crypto/encryptionTest.php @@ -72,5 +72,32 @@ class EncryptionTest extends TestCase { ); } + /** + * @dataProvider dataTestBegin + */ + public function testBegin($mode, $header, $legacyCipher, $defaultCipher, $expected) { + + $this->cryptMock->expects($this->any()) + ->method('getCipher') + ->willReturn($defaultCipher); + $this->cryptMock->expects($this->any()) + ->method('getLegacyCipher') + ->willReturn($legacyCipher); + + $result = $this->instance->begin('/user/files/foo.txt', 'user', $mode, $header, []); + + $this->assertArrayHasKey('cipher', $result); + $this->assertSame($expected, $result['cipher']); + } + + public function dataTestBegin() { + return array( + array('w', ['cipher' => 'myCipher'], 'legacyCipher', 'defaultCipher', 'myCipher'), + array('r', ['cipher' => 'myCipher'], 'legacyCipher', 'defaultCipher', 'myCipher'), + array('w', [], 'legacyCipher', 'defaultCipher', 'defaultCipher'), + array('r', [], 'legacyCipher', 'defaultCipher', 'legacyCipher'), + ); + } + }
\ No newline at end of file diff --git a/apps/encryption_dummy/lib/dummymodule.php b/apps/encryption_dummy/lib/dummymodule.php index e974ee468e2..141edfb58f9 100644 --- a/apps/encryption_dummy/lib/dummymodule.php +++ b/apps/encryption_dummy/lib/dummymodule.php @@ -53,6 +53,7 @@ class DummyModule implements IEncryptionModule { * * @param string $path to the file * @param string $user who read/write the file (null for public access) + * @param string $mode php stream open mode * @param array $header contains the header data read from the file * @param array $accessList who has access to the file contains the key 'users' and 'public' * @@ -60,7 +61,7 @@ class DummyModule implements IEncryptionModule { * written to the header, in case of a write operation * or if no additional data is needed return a empty array */ - public function begin($path, $user, array $header, array $accessList) { + public function begin($path, $user, $mode, array $header, array $accessList) { return array(); } diff --git a/lib/private/files/storage/wrapper/encryption.php b/lib/private/files/storage/wrapper/encryption.php index af48d3475c3..e3458cb6bba 100644 --- a/lib/private/files/storage/wrapper/encryption.php +++ b/lib/private/files/storage/wrapper/encryption.php @@ -162,8 +162,9 @@ class Encryption extends Wrapper { public function file_get_contents($path) { $encryptionModule = $this->getEncryptionModule($path); + $info = $this->getCache()->get($path); - if ($encryptionModule) { + if ($encryptionModule || $info['encrypted'] === true) { $handle = $this->fopen($path, "r"); if (!$handle) { return false; @@ -283,7 +284,8 @@ class Encryption extends Wrapper { $encryptionEnabled = $this->encryptionManager->isEnabled(); $shouldEncrypt = false; $encryptionModule = null; - $header = $this->getHeader($path); + $rawHeader = $this->getHeader($path); + $header = $this->util->readHeader($rawHeader); $fullPath = $this->getFullPath($path); $encryptionModuleId = $this->util->getEncryptionModuleId($header); @@ -317,10 +319,18 @@ class Encryption extends Wrapper { $shouldEncrypt = $encryptionModule->shouldEncrypt($fullPath); } } else { + $info = $this->getCache()->get($path); // only get encryption module if we found one in the header + // or if file should be encrypted according to the file cache if (!empty($encryptionModuleId)) { $encryptionModule = $this->encryptionManager->getEncryptionModule($encryptionModuleId); $shouldEncrypt = true; + } else if(empty($encryptionModuleId) && $info['encrypted'] === true) { + // we come from a old installation. No header and/or no module defined + // but the file is encrypted. In this case we need to use the + // OC_DEFAULT_MODULE to read the file + $encryptionModule = $this->encryptionManager->getEncryptionModule('OC_DEFAULT_MODULE'); + $shouldEncrypt = true; } } } catch (ModuleDoesNotExistsException $e) { @@ -339,7 +349,7 @@ class Encryption extends Wrapper { $source = $this->storage->fopen($path, $mode); $handle = \OC\Files\Stream\Encryption::wrap($source, $path, $fullPath, $header, $this->uid, $encryptionModule, $this->storage, $this, $this->util, $this->fileHelper, $mode, - $size, $unencryptedSize); + $size, $unencryptedSize, strlen($rawHeader)); return $handle; } else { return $this->storage->fopen($path, $mode); @@ -417,10 +427,13 @@ class Encryption extends Wrapper { $header = ''; if ($this->storage->file_exists($path)) { $handle = $this->storage->fopen($path, 'r'); - $header = fread($handle, $this->util->getHeaderSize()); + $firstBlock = fread($handle, $this->util->getHeaderSize()); fclose($handle); + if (substr($firstBlock, 0, strlen(Util::HEADER_START)) === Util::HEADER_START) { + $header = $firstBlock; + } } - return $this->util->readHeader($header); + return $header; } /** @@ -433,7 +446,8 @@ class Encryption extends Wrapper { */ protected function getEncryptionModule($path) { $encryptionModule = null; - $header = $this->getHeader($path); + $rawHeader = $this->getHeader($path); + $header = $this->util->readHeader($rawHeader); $encryptionModuleId = $this->util->getEncryptionModuleId($header); if (!empty($encryptionModuleId)) { try { diff --git a/lib/private/files/stream/encryption.php b/lib/private/files/stream/encryption.php index 5f39207db87..0262405f367 100644 --- a/lib/private/files/stream/encryption.php +++ b/lib/private/files/stream/encryption.php @@ -59,6 +59,9 @@ class Encryption extends Wrapper { protected $unencryptedSize; /** @var integer */ + protected $headerSize; + + /** @var integer */ protected $unencryptedBlockSize; /** @var array */ @@ -104,7 +107,8 @@ class Encryption extends Wrapper { 'util', 'size', 'unencryptedSize', - 'encryptionStorage' + 'encryptionStorage', + 'headerSize' ); } @@ -125,6 +129,7 @@ class Encryption extends Wrapper { * @param string $mode * @param int $size * @param int $unencryptedSize + * @param int $headerSize * @return resource * * @throws \BadMethodCallException @@ -138,7 +143,8 @@ class Encryption extends Wrapper { \OC\Encryption\File $file, $mode, $size, - $unencryptedSize) { + $unencryptedSize, + $headerSize) { $context = stream_context_create(array( 'ocencryption' => array( @@ -153,7 +159,8 @@ class Encryption extends Wrapper { 'file' => $file, 'size' => $size, 'unencryptedSize' => $unencryptedSize, - 'encryptionStorage' => $encStorage + 'encryptionStorage' => $encStorage, + 'headerSize' => $headerSize ) )); @@ -235,7 +242,7 @@ class Encryption extends Wrapper { } $accessList = $this->file->getAccessList($sharePath); - $this->newHeader = $this->encryptionModule->begin($this->fullPath, $this->uid, $this->header, $accessList); + $this->newHeader = $this->encryptionModule->begin($this->fullPath, $this->uid, $mode, $this->header, $accessList); if ( $mode === 'w' @@ -246,7 +253,8 @@ class Encryption extends Wrapper { // We're writing a new file so start write counter with 0 bytes $this->unencryptedSize = 0; $this->writeHeader(); - $this->size = $this->util->getHeaderSize(); + $this->headerSize = $this->util->getHeaderSize(); + $this->size = $this->headerSize; } else { $this->skipHeader(); } @@ -300,7 +308,7 @@ class Encryption extends Wrapper { // 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 $positionInFile = (int)floor($this->position / $this->unencryptedBlockSize) * - $this->util->getBlockSize() + $this->util->getHeaderSize(); + $this->util->getBlockSize() + $this->headerSize; $resultFseek = parent::stream_seek($positionInFile); // only allow writes on seekable streams, or at the end of the encrypted stream @@ -367,7 +375,7 @@ class Encryption extends Wrapper { } $newFilePosition = floor($newPosition / $this->unencryptedBlockSize) - * $this->util->getBlockSize() + $this->util->getHeaderSize(); + * $this->util->getBlockSize() + $this->headerSize; $oldFilePosition = parent::stream_tell(); if (parent::stream_seek($newFilePosition)) { @@ -440,7 +448,7 @@ class Encryption extends Wrapper { * read first block to skip the header */ protected function skipHeader() { - parent::stream_read($this->util->getHeaderSize()); + parent::stream_read($this->headerSize); } } diff --git a/lib/public/encryption/iencryptionmodule.php b/lib/public/encryption/iencryptionmodule.php index dc55f8939ef..0dda042d759 100644 --- a/lib/public/encryption/iencryptionmodule.php +++ b/lib/public/encryption/iencryptionmodule.php @@ -50,6 +50,7 @@ interface IEncryptionModule { * * @param string $path to the file * @param string $user who read/write the file (null for public access) + * @param string $mode php stream open mode * @param array $header contains the header data read from the file * @param array $accessList who has access to the file contains the key 'users' and 'public' * @@ -58,7 +59,7 @@ interface IEncryptionModule { * or if no additional data is needed return a empty array * @since 8.1.0 */ - public function begin($path, $user, array $header, array $accessList); + public function begin($path, $user, $mode, array $header, array $accessList); /** * last chunk received. This is the place where you can perform some final diff --git a/tests/lib/files/stream/encryption.php b/tests/lib/files/stream/encryption.php index 0b34de8ae12..892491cbc32 100644 --- a/tests/lib/files/stream/encryption.php +++ b/tests/lib/files/stream/encryption.php @@ -44,7 +44,7 @@ class Encryption extends \Test\TestCase { return \OC\Files\Stream\Encryption::wrap($source, $internalPath, $fullPath, $header, $uid, $encryptionModule, $storage, $encStorage, - $util, $file, $mode, $size, $unencryptedSize); + $util, $file, $mode, $size, $unencryptedSize, 8192); } /** |