diff --git a/apps/encryption/lib/crypto/crypt.php b/apps/encryption/lib/crypto/crypt.php index 6c3aee47a5..b4c10f4279 100644 --- a/apps/encryption/lib/crypto/crypt.php +++ b/apps/encryption/lib/crypto/crypt.php @@ -170,10 +170,11 @@ class Crypt { * @param string $plainContent * @param string $passPhrase * @param int $version + * @param int $position * @return false|string * @throws EncryptionFailedException */ - public function symmetricEncryptFileContent($plainContent, $passPhrase, $version) { + public function symmetricEncryptFileContent($plainContent, $passPhrase, $version, $position) { if (!$plainContent) { $this->logger->error('Encryption Library, symmetrical encryption failed no content given', @@ -189,7 +190,7 @@ class Crypt { $this->getCipher()); // Create a signature based on the key as well as the current version - $sig = $this->createSignature($encryptedContent, $passPhrase.$version); + $sig = $this->createSignature($encryptedContent, $passPhrase.$version.$position); // combine content to encrypt the IV identifier and actual IV $catFile = $this->concatIV($encryptedContent, $iv); @@ -368,6 +369,7 @@ class Crypt { $encryptedKey = $this->symmetricEncryptFileContent( $privateKey, $hash, + 0, 0 ); @@ -444,14 +446,15 @@ class Crypt { * @param string $passPhrase * @param string $cipher * @param int $version + * @param int $position * @return string * @throws DecryptionFailedException */ - public function symmetricDecryptFileContent($keyFileContents, $passPhrase, $cipher = self::DEFAULT_CIPHER, $version = 0) { + public function symmetricDecryptFileContent($keyFileContents, $passPhrase, $cipher = self::DEFAULT_CIPHER, $version = 0, $position = 0) { $catFile = $this->splitMetaData($keyFileContents, $cipher); if ($catFile['signature'] !== false) { - $this->checkSignature($catFile['encrypted'], $passPhrase.$version, $catFile['signature']); + $this->checkSignature($catFile['encrypted'], $passPhrase.$version.$position, $catFile['signature']); } return $this->decrypt($catFile['encrypted'], diff --git a/apps/encryption/lib/crypto/encryption.php b/apps/encryption/lib/crypto/encryption.php index 90c60b8e0d..d4e8087c4b 100644 --- a/apps/encryption/lib/crypto/encryption.php +++ b/apps/encryption/lib/crypto/encryption.php @@ -215,13 +215,14 @@ class Encryption implements IEncryptionModule { * buffer. * * @param string $path to the file + * @param int $position * @return string remained data which should be written to the file in case * of a write operation * @throws PublicKeyMissingException * @throws \Exception * @throws \OCA\Encryption\Exceptions\MultiKeyEncryptException */ - public function end($path) { + public function end($path, $position = 0) { $result = ''; if ($this->isWriteOperation) { // Partial files do not increase the version @@ -230,7 +231,7 @@ class Encryption implements IEncryptionModule { } $this->keyManager->setVersion($this->path, $this->version+1); if (!empty($this->writeCache)) { - $result = $this->crypt->symmetricEncryptFileContent($this->writeCache, $this->fileKey, $this->version+1); + $result = $this->crypt->symmetricEncryptFileContent($this->writeCache, $this->fileKey, $this->version+1, $position); $this->writeCache = ''; } $publicKeys = array(); @@ -264,9 +265,10 @@ class Encryption implements IEncryptionModule { * encrypt data * * @param string $data you want to encrypt + * @param int $position * @return string encrypted data */ - public function encrypt($data) { + public function encrypt($data, $position = 0) { // If extra data is left over from the last round, make sure it // is integrated into the next block if ($this->writeCache) { @@ -314,7 +316,7 @@ class Encryption implements IEncryptionModule { if(\OC\Files\Cache\Scanner::isPartialFile($this->path)) { $this->version = $this->version - 1; } - $encrypted .= $this->crypt->symmetricEncryptFileContent($chunk, $this->fileKey, $this->version+1); + $encrypted .= $this->crypt->symmetricEncryptFileContent($chunk, $this->fileKey, $this->version+1, $position); // Remove the chunk we just processed from // $data, leaving only unprocessed data in $data @@ -332,10 +334,11 @@ class Encryption implements IEncryptionModule { * decrypt data * * @param string $data you want to decrypt + * @param int $position * @return string decrypted data * @throws DecryptionFailedException */ - public function decrypt($data) { + public function decrypt($data, $position = 0) { if (empty($this->fileKey)) { $msg = 'Can not decrypt this file, probably this is a shared file. Please ask the file owner to reshare the file with you.'; $hint = $this->l->t('Can not decrypt this file, probably this is a shared file. Please ask the file owner to reshare the file with you.'); @@ -344,11 +347,7 @@ class Encryption implements IEncryptionModule { throw new DecryptionFailedException($msg, $hint); } - $result = ''; - if (!empty($data)) { - $result = $this->crypt->symmetricDecryptFileContent($data, $this->fileKey, $this->cipher, $this->version); - } - return $result; + return $this->crypt->symmetricDecryptFileContent($data, $this->fileKey, $this->cipher, $this->version, $position); } /** diff --git a/lib/private/files/stream/encryption.php b/lib/private/files/stream/encryption.php index bc771a91eb..63949035b5 100644 --- a/lib/private/files/stream/encryption.php +++ b/lib/private/files/stream/encryption.php @@ -399,8 +399,9 @@ class Encryption extends Wrapper { } public function stream_close() { - $this->flush(); - $remainingData = $this->encryptionModule->end($this->fullPath); + $this->flush('end'); + $position = (int)floor($this->position/$this->unencryptedBlockSize); + $remainingData = $this->encryptionModule->end($this->fullPath, $position . 'end'); if ($this->readOnly === false) { if(!empty($remainingData)) { parent::stream_write($remainingData); @@ -412,15 +413,17 @@ class Encryption extends Wrapper { /** * write block to file + * @param string $positionPrefix */ - protected function flush() { + protected function flush($positionPrefix = '') { // 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); + $position = (int)floor($this->position/$this->unencryptedBlockSize); + $encrypted = $this->encryptionModule->encrypt($this->cache, $position . $positionPrefix); $bytesWritten = parent::stream_write($encrypted); $this->writeFlag = false; // Check whether the write concerns the last block @@ -447,7 +450,12 @@ class Encryption extends Wrapper { 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); + $position = (int)floor($this->position/$this->unencryptedBlockSize); + $numberOfChunks = (int)($this->unencryptedSize / $this->unencryptedBlockSize); + if($numberOfChunks === $position) { + $position .= 'end'; + } + $this->cache = $this->encryptionModule->decrypt($data, $position); } }