diff --git a/apps/encryption/appinfo/application.php b/apps/encryption/appinfo/application.php
index 433e9e86284b1a1f6cb765098234d347eaae9f3d..6d01d3e8353300c0b2ad0abe6e2da69b151ec38d 100644
--- a/apps/encryption/appinfo/application.php
+++ b/apps/encryption/appinfo/application.php
@@ -131,7 +131,8 @@ class Application extends \OCP\AppFramework\App {
 				$server = $c->getServer();
 				return new Crypt($server->getLogger(),
 					$server->getUserSession(),
-					$server->getConfig());
+					$server->getConfig(),
+					$server->getL10N($c->getAppName()));
 			});
 
 		$container->registerService('Session',
diff --git a/apps/encryption/appinfo/register_command.php b/apps/encryption/appinfo/register_command.php
index 2bb49d55c2e031fc1691f781869e62c68b00972f..5f32718cdf0d5c3a57dced166e31a0aeea4c607f 100644
--- a/apps/encryption/appinfo/register_command.php
+++ b/apps/encryption/appinfo/register_command.php
@@ -25,11 +25,12 @@ use Symfony\Component\Console\Helper\QuestionHelper;
 $userManager = OC::$server->getUserManager();
 $view = new \OC\Files\View();
 $config = \OC::$server->getConfig();
+$l = \OC::$server->getL10N('encryption');
 $userSession = \OC::$server->getUserSession();
 $connection = \OC::$server->getDatabaseConnection();
 $logger = \OC::$server->getLogger();
 $questionHelper = new QuestionHelper();
-$crypt = new \OCA\Encryption\Crypto\Crypt($logger, $userSession, $config);
+$crypt = new \OCA\Encryption\Crypto\Crypt($logger, $userSession, $config, $l);
 $util = new \OCA\Encryption\Util($view, $crypt, $logger, $userSession, $config, $userManager);
 
 $application->add(new MigrateKeys($userManager, $view, $connection, $config, $logger));
diff --git a/apps/encryption/lib/crypto/crypt.php b/apps/encryption/lib/crypto/crypt.php
index e387380cd9516d81270212014b0eaabb9d69b0cc..b4c10f42790ac87f5557b9864f4bb3a43e321302 100644
--- a/apps/encryption/lib/crypto/crypt.php
+++ b/apps/encryption/lib/crypto/crypt.php
@@ -29,16 +29,32 @@ namespace OCA\Encryption\Crypto;
 
 use OC\Encryption\Exceptions\DecryptionFailedException;
 use OC\Encryption\Exceptions\EncryptionFailedException;
+use OC\HintException;
 use OCA\Encryption\Exceptions\MultiKeyDecryptException;
 use OCA\Encryption\Exceptions\MultiKeyEncryptException;
 use OCP\Encryption\Exceptions\GenericEncryptionException;
 use OCP\IConfig;
+use OCP\IL10N;
 use OCP\ILogger;
 use OCP\IUserSession;
 
+/**
+ * Class Crypt provides the encryption implementation of the default ownCloud
+ * encryption module. As default AES-256-CTR is used, it does however offer support
+ * for the following modes:
+ *
+ * - AES-256-CTR
+ * - AES-128-CTR
+ * - AES-256-CFB
+ * - AES-128-CFB
+ *
+ * For integrity protection Encrypt-Then-MAC using HMAC-SHA256 is used.
+ *
+ * @package OCA\Encryption\Crypto
+ */
 class Crypt {
 
-	const DEFAULT_CIPHER = 'AES-256-CFB';
+	const DEFAULT_CIPHER = 'AES-256-CTR';
 	// default cipher from old ownCloud versions
 	const LEGACY_CIPHER = 'AES-128-CFB';
 
@@ -48,33 +64,41 @@ class Crypt {
 
 	const HEADER_START = 'HBEGIN';
 	const HEADER_END = 'HEND';
-	/**
-	 * @var ILogger
-	 */
+
+	/** @var ILogger */
 	private $logger;
-	/**
-	 * @var string
-	 */
+
+	/** @var string */
 	private $user;
-	/**
-	 * @var IConfig
-	 */
+
+	/** @var IConfig */
 	private $config;
 
-	/**
-	 * @var array
-	 */
+	/** @var array */
 	private $supportedKeyFormats;
 
+	/** @var IL10N */
+	private $l;
+
+	/** @var array */
+	private $supportedCiphersAndKeySize = [
+		'AES-256-CTR' => 32,
+		'AES-128-CTR' => 16,
+		'AES-256-CFB' => 32,
+		'AES-128-CFB' => 16,
+	];
+
 	/**
 	 * @param ILogger $logger
 	 * @param IUserSession $userSession
 	 * @param IConfig $config
+	 * @param IL10N $l
 	 */
-	public function __construct(ILogger $logger, IUserSession $userSession, IConfig $config) {
+	public function __construct(ILogger $logger, IUserSession $userSession, IConfig $config, IL10N $l) {
 		$this->logger = $logger;
 		$this->user = $userSession && $userSession->isLoggedIn() ? $userSession->getUser()->getUID() : '"no user given"';
 		$this->config = $config;
+		$this->l = $l;
 		$this->supportedKeyFormats = ['hash', 'password'];
 	}
 
@@ -145,10 +169,12 @@ class Crypt {
 	/**
 	 * @param string $plainContent
 	 * @param string $passPhrase
+	 * @param int $version
+	 * @param int $position
 	 * @return false|string
-	 * @throws GenericEncryptionException
+	 * @throws EncryptionFailedException
 	 */
-	public function symmetricEncryptFileContent($plainContent, $passPhrase) {
+	public function symmetricEncryptFileContent($plainContent, $passPhrase, $version, $position) {
 
 		if (!$plainContent) {
 			$this->logger->error('Encryption Library, symmetrical encryption failed no content given',
@@ -162,8 +188,13 @@ class Crypt {
 			$iv,
 			$passPhrase,
 			$this->getCipher());
+
+		// Create a signature based on the key as well as the current version
+		$sig = $this->createSignature($encryptedContent, $passPhrase.$version.$position);
+
 		// combine content to encrypt the IV identifier and actual IV
 		$catFile = $this->concatIV($encryptedContent, $iv);
+		$catFile = $this->concatSig($catFile, $sig);
 		$padded = $this->addPadding($catFile);
 
 		return $padded;
@@ -225,8 +256,13 @@ class Crypt {
 	 */
 	public function getCipher() {
 		$cipher = $this->config->getSystemValue('cipher', self::DEFAULT_CIPHER);
-		if ($cipher !== 'AES-256-CFB' && $cipher !== 'AES-128-CFB') {
-			$this->logger->warning('Wrong cipher defined in config.php only AES-128-CFB and AES-256-CFB are supported. Fall back' . self::DEFAULT_CIPHER,
+		if (!isset($this->supportedCiphersAndKeySize[$cipher])) {
+			$this->logger->warning(
+					sprintf(
+							'Unsupported cipher (%s) defined in config.php supported. Falling back to %s',
+							$cipher,
+							self::DEFAULT_CIPHER
+					),
 				['app' => 'encryption']);
 			$cipher = self::DEFAULT_CIPHER;
 		}
@@ -237,19 +273,20 @@ class Crypt {
 	/**
 	 * get key size depending on the cipher
 	 *
-	 * @param string $cipher supported ('AES-256-CFB' and 'AES-128-CFB')
+	 * @param string $cipher
 	 * @return int
 	 * @throws \InvalidArgumentException
 	 */
 	protected function getKeySize($cipher) {
-		if ($cipher === 'AES-256-CFB') {
-			return 32;
-		} else if ($cipher === 'AES-128-CFB') {
-			return 16;
+		if(isset($this->supportedCiphersAndKeySize[$cipher])) {
+			return $this->supportedCiphersAndKeySize[$cipher];
 		}
 
 		throw new \InvalidArgumentException(
-			'Wrong cipher defined only AES-128-CFB and AES-256-CFB are supported.'
+			sprintf(
+					'Unsupported cipher (%s) defined.',
+					$cipher
+			)
 		);
 	}
 
@@ -272,11 +309,24 @@ class Crypt {
 	}
 
 	/**
+	 * @param string $encryptedContent
+	 * @param string $signature
+	 * @return string
+	 */
+	private function concatSig($encryptedContent, $signature) {
+		return $encryptedContent . '00sig00' . $signature;
+	}
+
+	/**
+	 * Note: This is _NOT_ a padding used for encryption purposes. It is solely
+	 * used to achieve the PHP stream size. It has _NOTHING_ to do with the
+	 * encrypted content and is not used in any crypto primitive.
+	 *
 	 * @param string $data
 	 * @return string
 	 */
 	private function addPadding($data) {
-		return $data . 'xx';
+		return $data . 'xxx';
 	}
 
 	/**
@@ -318,7 +368,9 @@ class Crypt {
 		$hash = $this->generatePasswordHash($password, $cipher, $uid);
 		$encryptedKey = $this->symmetricEncryptFileContent(
 			$privateKey,
-			$hash
+			$hash,
+			0,
+			0
 		);
 
 		return $encryptedKey;
@@ -357,9 +409,12 @@ class Crypt {
 					self::HEADER_END) + strlen(self::HEADER_END));
 		}
 
-		$plainKey = $this->symmetricDecryptFileContent($privateKey,
+		$plainKey = $this->symmetricDecryptFileContent(
+			$privateKey,
 			$password,
-			$cipher);
+			$cipher,
+			0
+		);
 
 		if ($this->isValidPrivateKey($plainKey) === false) {
 			return false;
@@ -390,14 +445,17 @@ class Crypt {
 	 * @param string $keyFileContents
 	 * @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) {
-		// Remove Padding
-		$noPadding = $this->removePadding($keyFileContents);
+	public function symmetricDecryptFileContent($keyFileContents, $passPhrase, $cipher = self::DEFAULT_CIPHER, $version = 0, $position = 0) {
+		$catFile = $this->splitMetaData($keyFileContents, $cipher);
 
-		$catFile = $this->splitIv($noPadding);
+		if ($catFile['signature'] !== false) {
+			$this->checkSignature($catFile['encrypted'], $passPhrase.$version.$position, $catFile['signature']);
+		}
 
 		return $this->decrypt($catFile['encrypted'],
 			$catFile['iv'],
@@ -406,41 +464,102 @@ class Crypt {
 	}
 
 	/**
-	 * remove padding
+	 * check for valid signature
 	 *
-	 * @param $padded
-	 * @return string|false
+	 * @param string $data
+	 * @param string $passPhrase
+	 * @param string $expectedSignature
+	 * @throws HintException
 	 */
-	private function removePadding($padded) {
-		if (substr($padded, -2) === 'xx') {
-			return substr($padded, 0, -2);
+	private function checkSignature($data, $passPhrase, $expectedSignature) {
+		$signature = $this->createSignature($data, $passPhrase);
+		if (!hash_equals($expectedSignature, $signature)) {
+			throw new HintException('Bad Signature', $this->l->t('Bad Signature'));
 		}
-		return false;
 	}
 
 	/**
-	 * split iv from encrypted content
+	 * create signature
 	 *
-	 * @param string|false $catFile
+	 * @param string $data
+	 * @param string $passPhrase
 	 * @return string
 	 */
-	private function splitIv($catFile) {
-		// Fetch encryption metadata from end of file
-		$meta = substr($catFile, -22);
+	private function createSignature($data, $passPhrase) {
+		$passPhrase = hash('sha512', $passPhrase . 'a', true);
+		$signature = hash_hmac('sha256', $data, $passPhrase);
+		return $signature;
+	}
 
-		// Fetch IV from end of file
-		$iv = substr($meta, -16);
 
-		// Remove IV and IV Identifier text to expose encrypted content
+	/**
+	 * remove padding
+	 *
+	 * @param string $padded
+	 * @param bool $hasSignature did the block contain a signature, in this case we use a different padding
+	 * @return string|false
+	 */
+	private function removePadding($padded, $hasSignature = false) {
+		if ($hasSignature === false && substr($padded, -2) === 'xx') {
+			return substr($padded, 0, -2);
+		} elseif ($hasSignature === true && substr($padded, -3) === 'xxx') {
+			return substr($padded, 0, -3);
+		}
+		return false;
+	}
 
-		$encrypted = substr($catFile, 0, -22);
+	/**
+	 * split meta data from encrypted file
+	 * Note: for now, we assume that the meta data always start with the iv
+	 *       followed by the signature, if available
+	 *
+	 * @param string $catFile
+	 * @param string $cipher
+	 * @return array
+	 */
+	private function splitMetaData($catFile, $cipher) {
+		if ($this->hasSignature($catFile, $cipher)) {
+			$catFile = $this->removePadding($catFile, true);
+			$meta = substr($catFile, -93);
+			$iv = substr($meta, strlen('00iv00'), 16);
+			$sig = substr($meta, 22 + strlen('00sig00'));
+			$encrypted = substr($catFile, 0, -93);
+		} else {
+			$catFile = $this->removePadding($catFile);
+			$meta = substr($catFile, -22);
+			$iv = substr($meta, -16);
+			$sig = false;
+			$encrypted = substr($catFile, 0, -22);
+		}
 
 		return [
 			'encrypted' => $encrypted,
-			'iv' => $iv
+			'iv' => $iv,
+			'signature' => $sig
 		];
 	}
 
+	/**
+	 * check if encrypted block is signed
+	 *
+	 * @param string $catFile
+	 * @param string $cipher
+	 * @return bool
+	 * @throws HintException
+	 */
+	private function hasSignature($catFile, $cipher) {
+		$meta = substr($catFile, -93);
+		$signaturePosition = strpos($meta, '00sig00');
+
+		// enforce signature for the new 'CTR' ciphers
+		if ($signaturePosition === false && strpos(strtolower($cipher), 'ctr') !== false) {
+			throw new HintException('Missing Signature', $this->l->t('Missing Signature'));
+		}
+
+		return ($signaturePosition !== false);
+	}
+
+
 	/**
 	 * @param string $encryptedContent
 	 * @param string $iv
@@ -496,40 +615,18 @@ class Crypt {
 	 * @throws GenericEncryptionException
 	 */
 	private function generateIv() {
-		$random = openssl_random_pseudo_bytes(12, $strong);
-		if ($random) {
-			if (!$strong) {
-				// If OpenSSL indicates randomness is insecure log error
-				$this->logger->error('Encryption Library: Insecure symmetric key was generated using openssl_random_psudo_bytes()',
-					['app' => 'encryption']);
-			}
-
-			/*
-			 * We encode the iv purely for string manipulation
-			 * purposes -it gets decoded before use
-			 */
-			return base64_encode($random);
-		}
-		// If we ever get here we've failed anyway no need for an else
-		throw new GenericEncryptionException('Generating IV Failed');
+		return random_bytes(16);
 	}
 
 	/**
-	 * Generate a cryptographically secure pseudo-random base64 encoded 256-bit
-	 * ASCII key, used as file key
+	 * Generate a cryptographically secure pseudo-random 256-bit ASCII key, used
+	 * as file key
 	 *
 	 * @return string
 	 * @throws \Exception
 	 */
 	public function generateFileKey() {
-		// Generate key
-		$key = base64_encode(openssl_random_pseudo_bytes(32, $strong));
-		if (!$key || !$strong) {
-				// If OpenSSL indicates randomness is insecure, log error
-				throw new \Exception('Encryption library, Insecure symmetric key was generated using openssl_random_pseudo_bytes()');
-		}
-
-		return $key;
+		return random_bytes(32);
 	}
 
 	/**
diff --git a/apps/encryption/lib/crypto/encryption.php b/apps/encryption/lib/crypto/encryption.php
index 3b66684a7f4936f789dfd64c7c7a70532f85a62f..a637f52a86992fabe7bfd37e540ea89edc29547d 100644
--- a/apps/encryption/lib/crypto/encryption.php
+++ b/apps/encryption/lib/crypto/encryption.php
@@ -29,6 +29,7 @@ namespace OCA\Encryption\Crypto;
 
 
 use OC\Encryption\Exceptions\DecryptionFailedException;
+use OC\Files\View;
 use OCA\Encryption\Exceptions\PublicKeyMissingException;
 use OCA\Encryption\Session;
 use OCA\Encryption\Util;
@@ -55,6 +56,9 @@ class Encryption implements IEncryptionModule {
 	/** @var string */
 	private $path;
 
+	/** @var string */
+	private $realPath;
+
 	/** @var string */
 	private $user;
 
@@ -94,6 +98,16 @@ class Encryption implements IEncryptionModule {
 	/** @var DecryptAll  */
 	private $decryptAll;
 
+	/** @var int unencrypted block size if block contains signature */
+	private $unencryptedBlockSizeSigned = 6072;
+
+	/** @var int unencrypted block size */
+	private $unencryptedBlockSize = 6126;
+
+	/** @var int Current version of the file */
+	private $version = 0;
+
+
 	/**
 	 *
 	 * @param Crypt $crypt
@@ -156,8 +170,8 @@ class Encryption implements IEncryptionModule {
 	 *                       or if no additional data is needed return a empty array
 	 */
 	public function begin($path, $user, $mode, array $header, array $accessList) {
-
 		$this->path = $this->getPathToRealFile($path);
+		$this->realPath = $path;
 		$this->accessList = $accessList;
 		$this->user = $user;
 		$this->isWriteOperation = false;
@@ -173,6 +187,8 @@ class Encryption implements IEncryptionModule {
 			$this->fileKey = $this->keyManager->getFileKey($this->path, $this->user);
 		}
 
+		$this->version = (int)$this->keyManager->getVersion($this->realPath, new View());
+
 		if (
 			$mode === 'w'
 			|| $mode === 'w+'
@@ -185,17 +201,17 @@ class Encryption implements IEncryptionModule {
 			}
 		}
 
-		if (isset($header['cipher'])) {
-			$this->cipher = $header['cipher'];
-		} elseif ($this->isWriteOperation) {
+		if ($this->isWriteOperation) {
 			$this->cipher = $this->crypt->getCipher();
+		} elseif (isset($header['cipher'])) {
+			$this->cipher = $header['cipher'];
 		} else {
 			// if we read a file without a header we fall-back to the legacy cipher
 			// which was used in <=oC6
 			$this->cipher = $this->crypt->getLegacyCipher();
 		}
 
-		return array('cipher' => $this->cipher);
+		return array('cipher' => $this->cipher, 'signed' => 'true');
 	}
 
 	/**
@@ -204,17 +220,25 @@ 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
+			if(\OC\Files\Cache\Scanner::isPartialFile($path)) {
+				$version = $this->version;
+			} else {
+				$version = $this->version + 1;
+			}
+			$this->keyManager->setVersion($this->path, $this->version+1, new View());
 			if (!empty($this->writeCache)) {
-				$result = $this->crypt->symmetricEncryptFileContent($this->writeCache, $this->fileKey);
+				$result = $this->crypt->symmetricEncryptFileContent($this->writeCache, $this->fileKey, $version, $position);
 				$this->writeCache = '';
 			}
 			$publicKeys = array();
@@ -248,12 +272,12 @@ 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 6126 / 8192 block
+		// is integrated into the next block
 		if ($this->writeCache) {
 
 			// Concat writeCache to start of $data
@@ -275,7 +299,7 @@ class Encryption implements IEncryptionModule {
 
 			// If data remaining to be written is less than the
 			// size of 1 6126 byte block
-			if ($remainingLength < 6126) {
+			if ($remainingLength < $this->unencryptedBlockSizeSigned) {
 
 				// Set writeCache to contents of $data
 				// The writeCache will be carried over to the
@@ -293,14 +317,20 @@ class Encryption implements IEncryptionModule {
 			} else {
 
 				// Read the chunk from the start of $data
-				$chunk = substr($data, 0, 6126);
+				$chunk = substr($data, 0, $this->unencryptedBlockSizeSigned);
 
-				$encrypted .= $this->crypt->symmetricEncryptFileContent($chunk, $this->fileKey);
+				// Partial files do not increase the version
+				if(\OC\Files\Cache\Scanner::isPartialFile($this->path)) {
+					$version = $this->version;
+				} else {
+					$version = $this->version + 1;
+				}
+				$encrypted .= $this->crypt->symmetricEncryptFileContent($chunk, $this->fileKey, $version, $position);
 
 				// Remove the chunk we just processed from
 				// $data, leaving only unprocessed data in $data
 				// var, for handling on the next round
-				$data = substr($data, 6126);
+				$data = substr($data, $this->unencryptedBlockSizeSigned);
 
 			}
 
@@ -313,10 +343,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.');
@@ -325,11 +356,7 @@ class Encryption implements IEncryptionModule {
 			throw new DecryptionFailedException($msg, $hint);
 		}
 
-		$result = '';
-		if (!empty($data)) {
-			$result = $this->crypt->symmetricDecryptFileContent($data, $this->fileKey, $this->cipher);
-		}
-		return $result;
+		return $this->crypt->symmetricDecryptFileContent($data, $this->fileKey, $this->cipher, $this->version, $position);
 	}
 
 	/**
@@ -342,6 +369,10 @@ class Encryption implements IEncryptionModule {
 	 */
 	public function update($path, $uid, array $accessList) {
 		$fileKey = $this->keyManager->getFileKey($path, $uid);
+		if(empty($this->realPath)) {
+			$this->realPath = $path;
+		}
+		$version = $this->keyManager->getVersion($this->realPath, new View());
 
 		if (!empty($fileKey)) {
 
@@ -362,6 +393,8 @@ class Encryption implements IEncryptionModule {
 
 			$this->keyManager->setAllFileKeys($path, $encryptedFileKey);
 
+			$this->keyManager->setVersion($path, $version, new View());
+
 		} else {
 			$this->logger->debug('no file key found, we assume that the file "{file}" is not encrypted',
 				array('file' => $path, 'app' => 'encryption'));
@@ -407,10 +440,15 @@ class Encryption implements IEncryptionModule {
 	 * get size of the unencrypted payload per block.
 	 * ownCloud read/write files with a block size of 8192 byte
 	 *
-	 * @return integer
+	 * @param bool $signed
+	 * @return int
 	 */
-	public function getUnencryptedBlockSize() {
-		return 6126;
+	public function getUnencryptedBlockSize($signed = false) {
+		if ($signed === false) {
+			return $this->unencryptedBlockSize;
+		}
+
+		return $this->unencryptedBlockSizeSigned;
 	}
 
 	/**
diff --git a/apps/encryption/lib/keymanager.php b/apps/encryption/lib/keymanager.php
index b6365cf2ccee2bc6210e11437d43d8daf3df8b24..0c957e1201215bf41ca82ba7d665720494c842d0 100644
--- a/apps/encryption/lib/keymanager.php
+++ b/apps/encryption/lib/keymanager.php
@@ -25,12 +25,14 @@
 namespace OCA\Encryption;
 
 use OC\Encryption\Exceptions\DecryptionFailedException;
+use OC\Files\View;
 use OCA\Encryption\Crypto\Encryption;
 use OCA\Encryption\Exceptions\PrivateKeyMissingException;
 use OCA\Encryption\Exceptions\PublicKeyMissingException;
 use OCA\Encryption\Crypto\Crypt;
 use OCP\Encryption\Keys\IStorage;
 use OCP\IConfig;
+use OCP\IDBConnection;
 use OCP\ILogger;
 use OCP\IUserSession;
 
@@ -412,6 +414,37 @@ class KeyManager {
 		return '';
 	}
 
+	/**
+	 * Get the current version of a file
+	 *
+	 * @param string $path
+	 * @param View $view
+	 * @return int
+	 */
+	public function getVersion($path, View $view) {
+		$fileInfo = $view->getFileInfo($path);
+		if($fileInfo === false) {
+			return 0;
+		}
+		return $fileInfo->getEncryptedVersion();
+	}
+
+	/**
+	 * Set the current version of a file
+	 *
+	 * @param string $path
+	 * @param int $version
+	 * @param View $view
+	 */
+	public function setVersion($path, $version, View $view) {
+		$fileInfo= $view->getFileInfo($path);
+
+		if($fileInfo !== false) {
+			$cache = $fileInfo->getStorage()->getCache();
+			$cache->update($fileInfo->getId(), ['encrypted' => $version, 'encryptedVersion' => $version]);
+		}
+	}
+
 	/**
 	 * get the encrypted file key
 	 *
@@ -546,6 +579,7 @@ class KeyManager {
 
 	/**
 	 * @param string $path
+	 * @return bool
 	 */
 	public function deleteAllFileKeys($path) {
 		return $this->keyStorage->deleteAllFileKeys($path);
diff --git a/apps/encryption/settings/settings-admin.php b/apps/encryption/settings/settings-admin.php
index c3d523f27da9d78635a317875e5e68136fa5d418..6c7c0987fd722bb11ceb76092573cf53133473c0 100644
--- a/apps/encryption/settings/settings-admin.php
+++ b/apps/encryption/settings/settings-admin.php
@@ -29,7 +29,8 @@ $tmpl = new OCP\Template('encryption', 'settings-admin');
 $crypt = new \OCA\Encryption\Crypto\Crypt(
 	\OC::$server->getLogger(),
 	\OC::$server->getUserSession(),
-	\OC::$server->getConfig());
+	\OC::$server->getConfig(),
+	\OC::$server->getL10N('encryption'));
 
 $util = new \OCA\Encryption\Util(
 	new \OC\Files\View(),
diff --git a/apps/encryption/settings/settings-personal.php b/apps/encryption/settings/settings-personal.php
index 2dff59048503a8a1c78188632b732c3237217f1b..0f6e9353707e9074a665cc4695a26e442eacf63d 100644
--- a/apps/encryption/settings/settings-personal.php
+++ b/apps/encryption/settings/settings-personal.php
@@ -28,7 +28,8 @@ $template = new OCP\Template('encryption', 'settings-personal');
 $crypt = new \OCA\Encryption\Crypto\Crypt(
 	\OC::$server->getLogger(),
 	$userSession,
-	\OC::$server->getConfig());
+	\OC::$server->getConfig(),
+	\OC::$server->getL10N('encryption'));
 
 $util = new \OCA\Encryption\Util(
 	new \OC\Files\View(),
diff --git a/apps/encryption/tests/lib/KeyManagerTest.php b/apps/encryption/tests/lib/KeyManagerTest.php
index c69610fb541e7b26601be937936a3f7d460b1e83..ea1830db4d5e562d03d8f822cbe519cb3c87653f 100644
--- a/apps/encryption/tests/lib/KeyManagerTest.php
+++ b/apps/encryption/tests/lib/KeyManagerTest.php
@@ -579,4 +579,71 @@ class KeyManagerTest extends TestCase {
 		];
 	}
 
+	public function testGetVersionWithoutFileInfo() {
+		$view = $this->getMockBuilder('\\OC\\Files\\View')
+			->disableOriginalConstructor()->getMock();
+		$view->expects($this->once())
+			->method('getFileInfo')
+			->with('/admin/files/myfile.txt')
+			->willReturn(false);
+
+		$this->assertSame(0, $this->instance->getVersion('/admin/files/myfile.txt', $view));
+	}
+
+	public function testGetVersionWithFileInfo() {
+		$view = $this->getMockBuilder('\\OC\\Files\\View')
+			->disableOriginalConstructor()->getMock();
+		$fileInfo = $this->getMockBuilder('\\OC\\Files\\FileInfo')
+			->disableOriginalConstructor()->getMock();
+		$fileInfo->expects($this->once())
+			->method('getEncryptedVersion')
+			->willReturn(1337);
+		$view->expects($this->once())
+			->method('getFileInfo')
+			->with('/admin/files/myfile.txt')
+			->willReturn($fileInfo);
+
+		$this->assertSame(1337, $this->instance->getVersion('/admin/files/myfile.txt', $view));
+	}
+
+	public function testSetVersionWithFileInfo() {
+		$view = $this->getMockBuilder('\\OC\\Files\\View')
+			->disableOriginalConstructor()->getMock();
+		$cache = $this->getMockBuilder('\\OCP\\Files\\Cache\\ICache')
+			->disableOriginalConstructor()->getMock();
+		$cache->expects($this->once())
+			->method('update')
+			->with(123, ['encrypted' => 5, 'encryptedVersion' => 5]);
+		$storage = $this->getMockBuilder('\\OCP\\Files\\Storage')
+			->disableOriginalConstructor()->getMock();
+		$storage->expects($this->once())
+			->method('getCache')
+			->willReturn($cache);
+		$fileInfo = $this->getMockBuilder('\\OC\\Files\\FileInfo')
+			->disableOriginalConstructor()->getMock();
+		$fileInfo->expects($this->once())
+			->method('getStorage')
+			->willReturn($storage);
+		$fileInfo->expects($this->once())
+			->method('getId')
+			->willReturn(123);
+		$view->expects($this->once())
+			->method('getFileInfo')
+			->with('/admin/files/myfile.txt')
+			->willReturn($fileInfo);
+
+		$this->instance->setVersion('/admin/files/myfile.txt', 5, $view);
+	}
+
+	public function testSetVersionWithoutFileInfo() {
+		$view = $this->getMockBuilder('\\OC\\Files\\View')
+			->disableOriginalConstructor()->getMock();
+		$view->expects($this->once())
+			->method('getFileInfo')
+			->with('/admin/files/myfile.txt')
+			->willReturn(false);
+
+		$this->instance->setVersion('/admin/files/myfile.txt', 5, $view);
+	}
+
 }
diff --git a/apps/encryption/tests/lib/crypto/cryptTest.php b/apps/encryption/tests/lib/crypto/cryptTest.php
index e599cc28963259e437a7e895b64cfafc5c864f56..d94aea463cf5aa982cc1cd77900604b5bb64a44a 100644
--- a/apps/encryption/tests/lib/crypto/cryptTest.php
+++ b/apps/encryption/tests/lib/crypto/cryptTest.php
@@ -39,6 +39,10 @@ class cryptTest extends TestCase {
 	/** @var \PHPUnit_Framework_MockObject_MockObject */
 	private $config;
 
+
+	/** @var \PHPUnit_Framework_MockObject_MockObject */
+	private $l;
+
 	/** @var  Crypt */
 	private $crypt;
 
@@ -57,8 +61,9 @@ class cryptTest extends TestCase {
 		$this->config = $this->getMockBuilder('OCP\IConfig')
 			->disableOriginalConstructor()
 			->getMock();
+		$this->l = $this->getMock('OCP\IL10N');
 
-		$this->crypt = new Crypt($this->logger, $this->userSession, $this->config);
+		$this->crypt = new Crypt($this->logger, $this->userSession, $this->config, $this->l);
 	}
 
 	/**
@@ -105,7 +110,7 @@ class cryptTest extends TestCase {
 
 		$this->config->expects($this->once())
 			->method('getSystemValue')
-			->with($this->equalTo('cipher'), $this->equalTo('AES-256-CFB'))
+			->with($this->equalTo('cipher'), $this->equalTo('AES-256-CTR'))
 			->willReturn('AES-128-CFB');
 
 		if ($keyFormat) {
@@ -126,6 +131,9 @@ class cryptTest extends TestCase {
 		$this->crypt->generateHeader('unknown');
 	}
 
+	/**
+	 * @return array
+	 */
 	public function dataTestGenerateHeader() {
 		return [
 			[null, 'HBEGIN:cipher:AES-128-CFB:keyFormat:hash:HEND'],
@@ -134,16 +142,28 @@ class cryptTest extends TestCase {
 		];
 	}
 
+	public function testGetCipherWithInvalidCipher() {
+		$this->config->expects($this->once())
+				->method('getSystemValue')
+				->with($this->equalTo('cipher'), $this->equalTo('AES-256-CTR'))
+				->willReturn('Not-Existing-Cipher');
+		$this->logger
+			->expects($this->once())
+			->method('warning')
+			->with('Unsupported cipher (Not-Existing-Cipher) defined in config.php supported. Falling back to AES-256-CTR');
+
+		$this->assertSame('AES-256-CTR',  $this->crypt->getCipher());
+	}
+
 	/**
 	 * @dataProvider dataProviderGetCipher
 	 * @param string $configValue
 	 * @param string $expected
 	 */
 	public function testGetCipher($configValue, $expected) {
-
 		$this->config->expects($this->once())
 			->method('getSystemValue')
-			->with($this->equalTo('cipher'), $this->equalTo('AES-256-CFB'))
+			->with($this->equalTo('cipher'), $this->equalTo('AES-256-CTR'))
 			->willReturn($configValue);
 
 		$this->assertSame($expected,
@@ -161,7 +181,10 @@ class cryptTest extends TestCase {
 		return array(
 			array('AES-128-CFB', 'AES-128-CFB'),
 			array('AES-256-CFB', 'AES-256-CFB'),
-			array('unknown', 'AES-256-CFB')
+			array('AES-128-CTR', 'AES-128-CTR'),
+			array('AES-256-CTR', 'AES-256-CTR'),
+
+			array('unknown', 'AES-256-CTR')
 		);
 	}
 
@@ -181,17 +204,61 @@ class cryptTest extends TestCase {
 	}
 
 	/**
-	 * test splitIV()
+	 * @dataProvider dataTestSplitMetaData
 	 */
-	public function testSplitIV() {
-		$data = 'encryptedContent00iv001234567890123456';
-		$result = self::invokePrivate($this->crypt, 'splitIV', array($data));
+	public function testSplitMetaData($data, $expected) {
+		$result = self::invokePrivate($this->crypt, 'splitMetaData', array($data, 'AES-256-CFB'));
 		$this->assertTrue(is_array($result));
-		$this->assertSame(2, count($result));
+		$this->assertSame(3, count($result));
 		$this->assertArrayHasKey('encrypted', $result);
 		$this->assertArrayHasKey('iv', $result);
-		$this->assertSame('encryptedContent', $result['encrypted']);
-		$this->assertSame('1234567890123456', $result['iv']);
+		$this->assertArrayHasKey('signature', $result);
+		$this->assertSame($expected['encrypted'], $result['encrypted']);
+		$this->assertSame($expected['iv'], $result['iv']);
+		$this->assertSame($expected['signature'], $result['signature']);
+	}
+
+	public function dataTestSplitMetaData() {
+		return [
+			['encryptedContent00iv001234567890123456xx',
+				['encrypted' => 'encryptedContent', 'iv' => '1234567890123456', 'signature' => false]],
+			['encryptedContent00iv00123456789012345600sig00e1992521e437f6915f9173b190a512cfc38a00ac24502db44e0ba10c2bb0cc86xxx',
+				['encrypted' => 'encryptedContent', 'iv' => '1234567890123456', 'signature' => 'e1992521e437f6915f9173b190a512cfc38a00ac24502db44e0ba10c2bb0cc86']],
+		];
+	}
+
+	/**
+	 * @dataProvider dataTestHasSignature
+	 */
+	public function testHasSignature($data, $expected) {
+		$this->assertSame($expected,
+			$this->invokePrivate($this->crypt, 'hasSignature', array($data, 'AES-256-CFB'))
+		);
+	}
+
+	public function dataTestHasSignature() {
+		return [
+			['encryptedContent00iv001234567890123456xx', false],
+			['encryptedContent00iv00123456789012345600sig00e1992521e437f6915f9173b190a512cfc38a00ac24502db44e0ba10c2bb0cc86xxx', true]
+		];
+	}
+
+	/**
+	 * @dataProvider dataTestHasSignatureFail
+	 * @expectedException \OC\HintException
+	 */
+	public function testHasSignatureFail($cipher) {
+		$data = 'encryptedContent00iv001234567890123456xx';
+		$this->invokePrivate($this->crypt, 'hasSignature', array($data, $cipher));
+	}
+
+	public function dataTestHasSignatureFail() {
+		return [
+			['AES-256-CTR'],
+			['aes-256-ctr'],
+			['AES-128-CTR'],
+			['ctr-256-ctr']
+		];
 	}
 
 	/**
@@ -199,7 +266,7 @@ class cryptTest extends TestCase {
 	 */
 	public function testAddPadding() {
 		$result = self::invokePrivate($this->crypt, 'addPadding', array('data'));
-		$this->assertSame('dataxx', $result);
+		$this->assertSame('dataxxx', $result);
 	}
 
 	/**
@@ -303,10 +370,15 @@ class cryptTest extends TestCase {
 		$this->invokePrivate($this->crypt, 'getKeySize', ['foo']);
 	}
 
+	/**
+	 * @return array
+	 */
 	public function dataTestGetKeySize() {
 		return [
 			['AES-256-CFB', 32],
 			['AES-128-CFB', 16],
+			['AES-256-CTR', 32],
+			['AES-128-CTR', 16],
 		];
 	}
 
@@ -320,7 +392,8 @@ class cryptTest extends TestCase {
 				[
 					$this->logger,
 					$this->userSession,
-					$this->config
+					$this->config,
+					$this->l
 				]
 			)
 			->setMethods(
@@ -351,6 +424,9 @@ class cryptTest extends TestCase {
 		$this->assertSame($expected, $result);
 	}
 
+	/**
+	 * @return array
+	 */
 	public function dataTestDecryptPrivateKey() {
 		return [
 			[['cipher' => 'AES-128-CFB', 'keyFormat' => 'password'], 'HBEGIN:HENDprivateKey', 'AES-128-CFB', true, 'key'],
diff --git a/apps/encryption/tests/lib/crypto/encryptionTest.php b/apps/encryption/tests/lib/crypto/encryptionTest.php
index 62e77c742d80b8ab6e6f1ca292d4588734397032..ad943ab6e49159275212e5508da7f4c7cae52ce8 100644
--- a/apps/encryption/tests/lib/crypto/encryptionTest.php
+++ b/apps/encryption/tests/lib/crypto/encryptionTest.php
@@ -229,7 +229,7 @@ class EncryptionTest extends TestCase {
 
 	public function dataTestBegin() {
 		return array(
-			array('w', ['cipher' => 'myCipher'], 'legacyCipher', 'defaultCipher', 'fileKey', 'myCipher'),
+			array('w', ['cipher' => 'myCipher'], 'legacyCipher', 'defaultCipher', 'fileKey', 'defaultCipher'),
 			array('r', ['cipher' => 'myCipher'], 'legacyCipher', 'defaultCipher', 'fileKey', 'myCipher'),
 			array('w', [], 'legacyCipher', 'defaultCipher', '', 'defaultCipher'),
 			array('r', [], 'legacyCipher', 'defaultCipher', 'file_key', 'legacyCipher'),
diff --git a/apps/files_versions/lib/storage.php b/apps/files_versions/lib/storage.php
index 47acec1d7634ae77b043ecc1787e018db8d872f7..0b121c344f9034850026288f0878fc1c4441246f 100644
--- a/apps/files_versions/lib/storage.php
+++ b/apps/files_versions/lib/storage.php
@@ -165,7 +165,15 @@ class Storage {
 			$mtime = $users_view->filemtime('files/' . $filename);
 			$users_view->copy('files/' . $filename, 'files_versions/' . $filename . '.v' . $mtime);
 			// call getFileInfo to enforce a file cache entry for the new version
-			$users_view->getFileInfo('files_versions/' . $filename . '.v' . $mtime);
+			$newFileInfo = $users_view->getFileInfo('files_versions/' . $filename . '.v' . $mtime);
+
+			// Keep the "encrypted" value of the original file
+			$oldVersion = $files_view->getFileInfo($filename)->getEncryptedVersion();
+			$qb = \OC::$server->getDatabaseConnection()->getQueryBuilder();
+			$qb->update('filecache')
+				->set('encrypted', $qb->createNamedParameter($oldVersion))
+				->where($qb->expr()->eq('fileid', $qb->createNamedParameter($newFileInfo->getId())))
+				->execute();
 		}
 	}
 
diff --git a/lib/private/files/cache/cache.php b/lib/private/files/cache/cache.php
index 22b9f49e528a45560229dcdabbecac6c9cf549e9..b30666d48d28290833b8ca83c1c7de941865e21d 100644
--- a/lib/private/files/cache/cache.php
+++ b/lib/private/files/cache/cache.php
@@ -145,6 +145,7 @@ class Cache implements ICache {
 			$data['size'] = 0 + $data['size'];
 			$data['mtime'] = (int)$data['mtime'];
 			$data['storage_mtime'] = (int)$data['storage_mtime'];
+			$data['encryptedVersion'] = (int)$data['encrypted'];
 			$data['encrypted'] = (bool)$data['encrypted'];
 			$data['storage'] = $this->storageId;
 			$data['mimetype'] = $this->mimetypeLoader->getMimetypeById($data['mimetype']);
@@ -345,8 +346,12 @@ class Cache implements ICache {
 						$queryParts[] = '`mtime`';
 					}
 				} elseif ($name === 'encrypted') {
-					// Boolean to integer conversion
-					$value = $value ? 1 : 0;
+					if(isset($data['encryptedVersion'])) {
+						$value = $data['encryptedVersion'];
+					} else {
+						// Boolean to integer conversion
+						$value = $value ? 1 : 0;
+					}
 				}
 				$params[] = $value;
 				$queryParts[] = '`' . $name . '`';
diff --git a/lib/private/files/fileinfo.php b/lib/private/files/fileinfo.php
index f22e1099e26e1d813589cca3e8229205e004d829..1d722a46735ad246a2be72a8cbcc9d58486bbc98 100644
--- a/lib/private/files/fileinfo.php
+++ b/lib/private/files/fileinfo.php
@@ -193,6 +193,15 @@ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess {
 		return $this->data['encrypted'];
 	}
 
+	/**
+	 * Return the currently version used for the HMAC in the encryption app
+	 *
+	 * @return int
+	 */
+	public function getEncryptedVersion() {
+		return isset($this->data['encryptedVersion']) ? (int) $this->data['encryptedVersion'] : 1;
+	}
+
 	/**
 	 * @return int
 	 */
diff --git a/lib/private/files/storage/wrapper/encryption.php b/lib/private/files/storage/wrapper/encryption.php
index f358bd592390ce85b51a946cbc7168544708f0db..14d3b15bbae88e884fb6b3bda353e610f14d7f65 100644
--- a/lib/private/files/storage/wrapper/encryption.php
+++ b/lib/private/files/storage/wrapper/encryption.php
@@ -39,6 +39,7 @@ use OCP\Encryption\Keys\IStorage;
 use OCP\Files\Mount\IMountPoint;
 use OCP\Files\Storage;
 use OCP\ILogger;
+use OCP\Files\Cache\ICacheEntry;
 
 class Encryption extends Wrapper {
 
@@ -129,13 +130,16 @@ class Encryption extends Wrapper {
 		if (isset($this->unencryptedSize[$fullPath])) {
 			$size = $this->unencryptedSize[$fullPath];
 			// update file cache
-			if ($info) {
+			if ($info instanceof ICacheEntry) {
 				$info = $info->getData();
+				$info['encrypted'] = $info['encryptedVersion'];
 			} else {
-				$info = [];
+				if (!is_array($info)) {
+					$info = [];
+				}
+				$info['encrypted'] = true;
 			}
 
-			$info['encrypted'] = true;
 			$info['size'] = $size;
 			$this->getCache()->put($path, $info);
 
@@ -343,6 +347,7 @@ class Encryption extends Wrapper {
 		$shouldEncrypt = false;
 		$encryptionModule = null;
 		$header = $this->getHeader($path);
+		$signed = (isset($header['signed']) && $header['signed'] === 'true') ? true : false;
 		$fullPath = $this->getFullPath($path);
 		$encryptionModuleId = $this->util->getEncryptionModuleId($header);
 
@@ -377,7 +382,7 @@ class Encryption extends Wrapper {
 					|| $mode === 'wb'
 					|| $mode === 'wb+'
 				) {
-					// don't overwrite encrypted files if encyption is not enabled
+					// don't overwrite encrypted files if encryption is not enabled
 					if ($targetIsEncrypted && $encryptionEnabled === false) {
 						throw new GenericEncryptionException('Tried to access encrypted file but encryption is not enabled');
 					}
@@ -385,6 +390,7 @@ class Encryption extends Wrapper {
 						// if $encryptionModuleId is empty, the default module will be used
 						$encryptionModule = $this->encryptionManager->getEncryptionModule($encryptionModuleId);
 						$shouldEncrypt = $encryptionModule->shouldEncrypt($fullPath);
+						$signed = true;
 					}
 				} else {
 					$info = $this->getCache()->get($path);
@@ -422,7 +428,7 @@ class Encryption extends Wrapper {
 				}
 				$handle = \OC\Files\Stream\Encryption::wrap($source, $path, $fullPath, $header,
 					$this->uid, $encryptionModule, $this->storage, $this, $this->util, $this->fileHelper, $mode,
-					$size, $unencryptedSize, $headerSize);
+					$size, $unencryptedSize, $headerSize, $signed);
 				return $handle;
 			}
 
diff --git a/lib/private/files/stream/encryption.php b/lib/private/files/stream/encryption.php
index c884cd8fa0742259a30ea1985a15b582ce2949b8..63949035b5a4787d186eac652748e0396ed3f655 100644
--- a/lib/private/files/stream/encryption.php
+++ b/lib/private/files/stream/encryption.php
@@ -72,6 +72,9 @@ class Encryption extends Wrapper {
 	/** @var string */
 	protected $fullPath;
 
+	/** @var  bool */
+	protected $signed;
+
 	/**
 	 * header data returned by the encryption module, will be written to the file
 	 * in case of a write operation
@@ -110,7 +113,8 @@ class Encryption extends Wrapper {
 			'size',
 			'unencryptedSize',
 			'encryptionStorage',
-			'headerSize'
+			'headerSize',
+			'signed'
 		);
 	}
 
@@ -132,6 +136,7 @@ class Encryption extends Wrapper {
 	 * @param int $size
 	 * @param int $unencryptedSize
 	 * @param int $headerSize
+	 * @param bool $signed
 	 * @param string $wrapper stream wrapper class
 	 * @return resource
 	 *
@@ -148,6 +153,7 @@ class Encryption extends Wrapper {
 								$size,
 								$unencryptedSize,
 								$headerSize,
+								$signed,
 								$wrapper =  'OC\Files\Stream\Encryption') {
 
 		$context = stream_context_create(array(
@@ -164,7 +170,8 @@ class Encryption extends Wrapper {
 				'size' => $size,
 				'unencryptedSize' => $unencryptedSize,
 				'encryptionStorage' => $encStorage,
-				'headerSize' => $headerSize
+				'headerSize' => $headerSize,
+				'signed' => $signed
 			)
 		));
 
@@ -225,7 +232,7 @@ class Encryption extends Wrapper {
 		$this->position = 0;
 		$this->cache = '';
 		$this->writeFlag = false;
-		$this->unencryptedBlockSize = $this->encryptionModule->getUnencryptedBlockSize();
+		$this->unencryptedBlockSize = $this->encryptionModule->getUnencryptedBlockSize($this->signed);
 
 		if (
 			$mode === 'w'
@@ -392,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);
@@ -405,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
@@ -440,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);
 		}
 	}
 
diff --git a/lib/public/encryption/iencryptionmodule.php b/lib/public/encryption/iencryptionmodule.php
index 426e4ddecced701b853e0e3073c56437cb1e8b3c..45e0b79c2a97ffb79913bb2cb576aab53b3c36d6 100644
--- a/lib/public/encryption/iencryptionmodule.php
+++ b/lib/public/encryption/iencryptionmodule.php
@@ -119,10 +119,11 @@ interface IEncryptionModule {
 	 * get size of the unencrypted payload per block.
 	 * ownCloud read/write files with a block size of 8192 byte
 	 *
-	 * @return integer
-	 * @since 8.1.0
+	 * @param bool $signed
+	 * @return int
+	 * @since 8.1.0 optional parameter $signed was added in 9.0.0
 	 */
-	public function getUnencryptedBlockSize();
+	public function getUnencryptedBlockSize($signed = false);
 
 	/**
 	 * check if the encryption module is able to read the file,
diff --git a/settings/changepassword/controller.php b/settings/changepassword/controller.php
index bfa599c1d04ab8d05c5c47473ce3378dafdf5712..8469ec1423a07731e3c7631222ae76008006c62e 100644
--- a/settings/changepassword/controller.php
+++ b/settings/changepassword/controller.php
@@ -89,7 +89,8 @@ class Controller {
 			$crypt = new \OCA\Encryption\Crypto\Crypt(
 				\OC::$server->getLogger(),
 				\OC::$server->getUserSession(),
-				\OC::$server->getConfig());
+				\OC::$server->getConfig(),
+				\OC::$server->getL10N('encryption'));
 			$keyStorage = \OC::$server->getEncryptionKeyStorage();
 			$util = new \OCA\Encryption\Util(
 				new \OC\Files\View(),
diff --git a/tests/lib/files/stream/encryption.php b/tests/lib/files/stream/encryption.php
index f9d8f076b63fb2ef21c961ebe6e88b87e6d6fba5..f67dd09bc4dc312ac06d65e9bde0c7ed5776a227 100644
--- a/tests/lib/files/stream/encryption.php
+++ b/tests/lib/files/stream/encryption.php
@@ -117,6 +117,7 @@ class Encryption extends \Test\TestCase {
 		$header->setAccessible(true);
 		$header->setValue($streamWrapper, array());
 		$header->setAccessible(false);
+		$this->invokePrivate($streamWrapper, 'signed', [true]);
 
 		// call stream_open, that's the method we want to test
 		$dummyVar = 'foo';