summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLukas Reschke <lukas@owncloud.com>2016-02-02 20:00:36 +0100
committerLukas Reschke <lukas@owncloud.com>2016-02-09 23:43:26 +0100
commitb5824f024a1008b0195b6e8f4803774cfe644b7b (patch)
tree51855889ff57470aad0711c4d7236087123663fd
parentd5c15968878f896caf7b2c197ecc8e87f0b584c8 (diff)
downloadnextcloud-server-b5824f024a1008b0195b6e8f4803774cfe644b7b.tar.gz
nextcloud-server-b5824f024a1008b0195b6e8f4803774cfe644b7b.zip
Keep track of file version
This way it is not possible anymore for an external storage admin to put up old versions of the file.
-rw-r--r--apps/encryption/lib/crypto/crypt.php22
-rw-r--r--apps/encryption/lib/crypto/encryption.php25
-rw-r--r--apps/encryption/lib/keymanager.php19
3 files changed, 53 insertions, 13 deletions
diff --git a/apps/encryption/lib/crypto/crypt.php b/apps/encryption/lib/crypto/crypt.php
index 69d8757eb86..6c3aee47a56 100644
--- a/apps/encryption/lib/crypto/crypt.php
+++ b/apps/encryption/lib/crypto/crypt.php
@@ -169,10 +169,11 @@ class Crypt {
/**
* @param string $plainContent
* @param string $passPhrase
+ * @param int $version
* @return false|string
* @throws EncryptionFailedException
*/
- public function symmetricEncryptFileContent($plainContent, $passPhrase) {
+ public function symmetricEncryptFileContent($plainContent, $passPhrase, $version) {
if (!$plainContent) {
$this->logger->error('Encryption Library, symmetrical encryption failed no content given',
@@ -187,7 +188,8 @@ class Crypt {
$passPhrase,
$this->getCipher());
- $sig = $this->createSignature($encryptedContent, $passPhrase);
+ // Create a signature based on the key as well as the current version
+ $sig = $this->createSignature($encryptedContent, $passPhrase.$version);
// combine content to encrypt the IV identifier and actual IV
$catFile = $this->concatIV($encryptedContent, $iv);
@@ -365,7 +367,8 @@ class Crypt {
$hash = $this->generatePasswordHash($password, $cipher, $uid);
$encryptedKey = $this->symmetricEncryptFileContent(
$privateKey,
- $hash
+ $hash,
+ 0
);
return $encryptedKey;
@@ -404,9 +407,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;
@@ -437,15 +443,15 @@ class Crypt {
* @param string $keyFileContents
* @param string $passPhrase
* @param string $cipher
+ * @param int $version
* @return string
* @throws DecryptionFailedException
*/
- public function symmetricDecryptFileContent($keyFileContents, $passPhrase, $cipher = self::DEFAULT_CIPHER) {
-
+ public function symmetricDecryptFileContent($keyFileContents, $passPhrase, $cipher = self::DEFAULT_CIPHER, $version = 0) {
$catFile = $this->splitMetaData($keyFileContents, $cipher);
if ($catFile['signature'] !== false) {
- $this->checkSignature($catFile['encrypted'], $passPhrase, $catFile['signature']);
+ $this->checkSignature($catFile['encrypted'], $passPhrase.$version, $catFile['signature']);
}
return $this->decrypt($catFile['encrypted'],
diff --git a/apps/encryption/lib/crypto/encryption.php b/apps/encryption/lib/crypto/encryption.php
index dc60c094784..90c60b8e0d5 100644
--- a/apps/encryption/lib/crypto/encryption.php
+++ b/apps/encryption/lib/crypto/encryption.php
@@ -100,6 +100,9 @@ class Encryption implements IEncryptionModule {
/** @var int unencrypted block size */
private $unencryptedBlockSize = 6126;
+ /** @var int Current version of the file */
+ private $version = 0;
+
/**
*
@@ -163,7 +166,6 @@ 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->accessList = $accessList;
$this->user = $user;
@@ -180,6 +182,8 @@ class Encryption implements IEncryptionModule {
$this->fileKey = $this->keyManager->getFileKey($this->path, $this->user);
}
+ $this->version = (int)$this->keyManager->getVersion($this->path);
+
if (
$mode === 'w'
|| $mode === 'w+'
@@ -220,8 +224,13 @@ class Encryption implements IEncryptionModule {
public function end($path) {
$result = '';
if ($this->isWriteOperation) {
+ // Partial files do not increase the version
+ if(\OC\Files\Cache\Scanner::isPartialFile($path)) {
+ $this->version = $this->version-1;
+ }
+ $this->keyManager->setVersion($this->path, $this->version+1);
if (!empty($this->writeCache)) {
- $result = $this->crypt->symmetricEncryptFileContent($this->writeCache, $this->fileKey);
+ $result = $this->crypt->symmetricEncryptFileContent($this->writeCache, $this->fileKey, $this->version+1);
$this->writeCache = '';
}
$publicKeys = array();
@@ -258,7 +267,6 @@ class Encryption implements IEncryptionModule {
* @return string encrypted data
*/
public function encrypt($data) {
-
// If extra data is left over from the last round, make sure it
// is integrated into the next block
if ($this->writeCache) {
@@ -302,7 +310,11 @@ class Encryption implements IEncryptionModule {
// Read the chunk from the start of $data
$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)) {
+ $this->version = $this->version - 1;
+ }
+ $encrypted .= $this->crypt->symmetricEncryptFileContent($chunk, $this->fileKey, $this->version+1);
// Remove the chunk we just processed from
// $data, leaving only unprocessed data in $data
@@ -334,7 +346,7 @@ class Encryption implements IEncryptionModule {
$result = '';
if (!empty($data)) {
- $result = $this->crypt->symmetricDecryptFileContent($data, $this->fileKey, $this->cipher);
+ $result = $this->crypt->symmetricDecryptFileContent($data, $this->fileKey, $this->cipher, $this->version);
}
return $result;
}
@@ -349,6 +361,7 @@ class Encryption implements IEncryptionModule {
*/
public function update($path, $uid, array $accessList) {
$fileKey = $this->keyManager->getFileKey($path, $uid);
+ $version = $this->keyManager->getVersion($path);
if (!empty($fileKey)) {
@@ -369,6 +382,8 @@ class Encryption implements IEncryptionModule {
$this->keyManager->setAllFileKeys($path, $encryptedFileKey);
+ $this->keyManager->setVersion($path, $version);
+
} else {
$this->logger->debug('no file key found, we assume that the file "{file}" is not encrypted',
array('file' => $path, 'app' => 'encryption'));
diff --git a/apps/encryption/lib/keymanager.php b/apps/encryption/lib/keymanager.php
index b6365cf2cce..4cbb377a43c 100644
--- a/apps/encryption/lib/keymanager.php
+++ b/apps/encryption/lib/keymanager.php
@@ -413,6 +413,24 @@ class KeyManager {
}
/**
+ * Get the current version of a file
+ *
+ * @param string $path
+ * @return mixed
+ */
+ public function getVersion($path) {
+ return $this->keyStorage->getFileKey($path, 'version', Encryption::ID);
+ }
+
+ /**
+ * @param string $path
+ * @param string $version
+ */
+ public function setVersion($path, $version) {
+ $this->keyStorage->setFileKey($path, 'version', $version, Encryption::ID);
+ }
+
+ /**
* get the encrypted file key
*
* @param string $path
@@ -546,6 +564,7 @@ class KeyManager {
/**
* @param string $path
+ * @return bool
*/
public function deleteAllFileKeys($path) {
return $this->keyStorage->deleteAllFileKeys($path);