|
|
|
|
@ -31,6 +31,7 @@ use OC\Encryption\Util; |
|
|
|
|
use OC\Files\Filesystem; |
|
|
|
|
use OC\Files\Mount\Manager; |
|
|
|
|
use OC\Files\Storage\LocalTempFileTrait; |
|
|
|
|
use OCP\Encryption\Exceptions\GenericEncryptionException; |
|
|
|
|
use OCP\Encryption\IFile; |
|
|
|
|
use OCP\Encryption\IManager; |
|
|
|
|
use OCP\Encryption\Keys\IStorage; |
|
|
|
|
@ -174,9 +175,8 @@ class Encryption extends Wrapper { |
|
|
|
|
public function file_get_contents($path) { |
|
|
|
|
|
|
|
|
|
$encryptionModule = $this->getEncryptionModule($path); |
|
|
|
|
$info = $this->getCache()->get($path); |
|
|
|
|
|
|
|
|
|
if ($encryptionModule || $info['encrypted'] === true) { |
|
|
|
|
if ($encryptionModule) { |
|
|
|
|
$handle = $this->fopen($path, "r"); |
|
|
|
|
if (!$handle) { |
|
|
|
|
return false; |
|
|
|
|
@ -338,14 +338,15 @@ class Encryption extends Wrapper { |
|
|
|
|
* @param string $path |
|
|
|
|
* @param string $mode |
|
|
|
|
* @return resource |
|
|
|
|
* @throws GenericEncryptionException |
|
|
|
|
* @throws ModuleDoesNotExistsException |
|
|
|
|
*/ |
|
|
|
|
public function fopen($path, $mode) { |
|
|
|
|
|
|
|
|
|
$encryptionEnabled = $this->encryptionManager->isEnabled(); |
|
|
|
|
$shouldEncrypt = false; |
|
|
|
|
$encryptionModule = null; |
|
|
|
|
$rawHeader = $this->getHeader($path); |
|
|
|
|
$header = $this->util->readHeader($rawHeader); |
|
|
|
|
$header = $this->getHeader($path); |
|
|
|
|
$fullPath = $this->getFullPath($path); |
|
|
|
|
$encryptionModuleId = $this->util->getEncryptionModuleId($header); |
|
|
|
|
|
|
|
|
|
@ -380,6 +381,10 @@ class Encryption extends Wrapper { |
|
|
|
|
|| $mode === 'wb' |
|
|
|
|
|| $mode === 'wb+' |
|
|
|
|
) { |
|
|
|
|
// don't overwrite encrypted files if encyption is not enabled |
|
|
|
|
if ($targetIsEncrypted && $encryptionEnabled === false) { |
|
|
|
|
throw new GenericEncryptionException('Tried to access encrypted file but encryption is not enabled'); |
|
|
|
|
} |
|
|
|
|
if ($encryptionEnabled) { |
|
|
|
|
// if $encryptionModuleId is empty, the default module will be used |
|
|
|
|
$encryptionModule = $this->encryptionManager->getEncryptionModule($encryptionModuleId); |
|
|
|
|
@ -416,7 +421,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, strlen($rawHeader)); |
|
|
|
|
$size, $unencryptedSize, $this->getHeaderSize($path)); |
|
|
|
|
return $handle; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -605,6 +610,72 @@ class Encryption extends Wrapper { |
|
|
|
|
return Filesystem::normalizePath($this->mountPoint . '/' . $path); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* read first block of encrypted file, typically this will contain the |
|
|
|
|
* encryption header |
|
|
|
|
* |
|
|
|
|
* @param string $path |
|
|
|
|
* @return string |
|
|
|
|
*/ |
|
|
|
|
protected function readFirstBlock($path) { |
|
|
|
|
$firstBlock = ''; |
|
|
|
|
if ($this->storage->file_exists($path)) { |
|
|
|
|
$handle = $this->storage->fopen($path, 'r'); |
|
|
|
|
$firstBlock = fread($handle, $this->util->getHeaderSize()); |
|
|
|
|
fclose($handle); |
|
|
|
|
} |
|
|
|
|
return $firstBlock; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* return header size of given file |
|
|
|
|
* |
|
|
|
|
* @param string $path |
|
|
|
|
* @return int |
|
|
|
|
*/ |
|
|
|
|
protected function getHeaderSize($path) { |
|
|
|
|
$headerSize = 0; |
|
|
|
|
$realFile = $this->util->stripPartialFileExtension($path); |
|
|
|
|
if ($this->storage->file_exists($realFile)) { |
|
|
|
|
$path = $realFile; |
|
|
|
|
} |
|
|
|
|
$firstBlock = $this->readFirstBlock($path); |
|
|
|
|
|
|
|
|
|
if (substr($firstBlock, 0, strlen(Util::HEADER_START)) === Util::HEADER_START) { |
|
|
|
|
$headerSize = strlen($firstBlock); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return $headerSize; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* parse raw header to array |
|
|
|
|
* |
|
|
|
|
* @param string $rawHeader |
|
|
|
|
* @return array |
|
|
|
|
*/ |
|
|
|
|
protected function parseRawHeader($rawHeader) { |
|
|
|
|
$result = array(); |
|
|
|
|
if (substr($rawHeader, 0, strlen(Util::HEADER_START)) === Util::HEADER_START) { |
|
|
|
|
$header = $rawHeader; |
|
|
|
|
$endAt = strpos($header, Util::HEADER_END); |
|
|
|
|
if ($endAt !== false) { |
|
|
|
|
$header = substr($header, 0, $endAt + strlen(Util::HEADER_END)); |
|
|
|
|
|
|
|
|
|
// +1 to not start with an ':' which would result in empty element at the beginning |
|
|
|
|
$exploded = explode(':', substr($header, strlen(Util::HEADER_START)+1)); |
|
|
|
|
|
|
|
|
|
$element = array_shift($exploded); |
|
|
|
|
while ($element !== Util::HEADER_END) { |
|
|
|
|
$result[$element] = array_shift($exploded); |
|
|
|
|
$element = array_shift($exploded); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return $result; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* read header from file |
|
|
|
|
* |
|
|
|
|
@ -612,21 +683,29 @@ class Encryption extends Wrapper { |
|
|
|
|
* @return array |
|
|
|
|
*/ |
|
|
|
|
protected function getHeader($path) { |
|
|
|
|
$header = ''; |
|
|
|
|
$realFile = $this->util->stripPartialFileExtension($path); |
|
|
|
|
if ($this->storage->file_exists($realFile)) { |
|
|
|
|
$path = $realFile; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if ($this->storage->file_exists($path)) { |
|
|
|
|
$handle = $this->storage->fopen($path, 'r'); |
|
|
|
|
$firstBlock = fread($handle, $this->util->getHeaderSize()); |
|
|
|
|
fclose($handle); |
|
|
|
|
if (substr($firstBlock, 0, strlen(Util::HEADER_START)) === Util::HEADER_START) { |
|
|
|
|
$header = $firstBlock; |
|
|
|
|
$firstBlock = $this->readFirstBlock($path); |
|
|
|
|
$result = $this->parseRawHeader($firstBlock); |
|
|
|
|
|
|
|
|
|
// if the header doesn't contain a encryption module we check if it is a |
|
|
|
|
// legacy file. If true, we add the default encryption module |
|
|
|
|
if (!isset($result[Util::HEADER_ENCRYPTION_MODULE_KEY])) { |
|
|
|
|
if (!empty($result)) { |
|
|
|
|
$result[Util::HEADER_ENCRYPTION_MODULE_KEY] = 'OC_DEFAULT_MODULE'; |
|
|
|
|
} else { |
|
|
|
|
// if the header was empty we have to check first if it is a encrypted file at all |
|
|
|
|
$info = $this->getCache()->get($path); |
|
|
|
|
if (isset($info['encrypted']) && $info['encrypted'] === true) { |
|
|
|
|
$result[Util::HEADER_ENCRYPTION_MODULE_KEY] = 'OC_DEFAULT_MODULE'; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return $header; |
|
|
|
|
|
|
|
|
|
return $result; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
@ -639,8 +718,7 @@ class Encryption extends Wrapper { |
|
|
|
|
*/ |
|
|
|
|
protected function getEncryptionModule($path) { |
|
|
|
|
$encryptionModule = null; |
|
|
|
|
$rawHeader = $this->getHeader($path); |
|
|
|
|
$header = $this->util->readHeader($rawHeader); |
|
|
|
|
$header = $this->getHeader($path); |
|
|
|
|
$encryptionModuleId = $this->util->getEncryptionModuleId($header); |
|
|
|
|
if (!empty($encryptionModuleId)) { |
|
|
|
|
try { |
|
|
|
|
@ -675,4 +753,5 @@ class Encryption extends Wrapper { |
|
|
|
|
|
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|