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.
This commit is contained in:
parent
d5c1596887
commit
b5824f024a
|
@ -169,10 +169,11 @@ class Crypt {
|
||||||
/**
|
/**
|
||||||
* @param string $plainContent
|
* @param string $plainContent
|
||||||
* @param string $passPhrase
|
* @param string $passPhrase
|
||||||
|
* @param int $version
|
||||||
* @return false|string
|
* @return false|string
|
||||||
* @throws EncryptionFailedException
|
* @throws EncryptionFailedException
|
||||||
*/
|
*/
|
||||||
public function symmetricEncryptFileContent($plainContent, $passPhrase) {
|
public function symmetricEncryptFileContent($plainContent, $passPhrase, $version) {
|
||||||
|
|
||||||
if (!$plainContent) {
|
if (!$plainContent) {
|
||||||
$this->logger->error('Encryption Library, symmetrical encryption failed no content given',
|
$this->logger->error('Encryption Library, symmetrical encryption failed no content given',
|
||||||
|
@ -187,7 +188,8 @@ class Crypt {
|
||||||
$passPhrase,
|
$passPhrase,
|
||||||
$this->getCipher());
|
$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
|
// combine content to encrypt the IV identifier and actual IV
|
||||||
$catFile = $this->concatIV($encryptedContent, $iv);
|
$catFile = $this->concatIV($encryptedContent, $iv);
|
||||||
|
@ -365,7 +367,8 @@ class Crypt {
|
||||||
$hash = $this->generatePasswordHash($password, $cipher, $uid);
|
$hash = $this->generatePasswordHash($password, $cipher, $uid);
|
||||||
$encryptedKey = $this->symmetricEncryptFileContent(
|
$encryptedKey = $this->symmetricEncryptFileContent(
|
||||||
$privateKey,
|
$privateKey,
|
||||||
$hash
|
$hash,
|
||||||
|
0
|
||||||
);
|
);
|
||||||
|
|
||||||
return $encryptedKey;
|
return $encryptedKey;
|
||||||
|
@ -404,9 +407,12 @@ class Crypt {
|
||||||
self::HEADER_END) + strlen(self::HEADER_END));
|
self::HEADER_END) + strlen(self::HEADER_END));
|
||||||
}
|
}
|
||||||
|
|
||||||
$plainKey = $this->symmetricDecryptFileContent($privateKey,
|
$plainKey = $this->symmetricDecryptFileContent(
|
||||||
|
$privateKey,
|
||||||
$password,
|
$password,
|
||||||
$cipher);
|
$cipher,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
if ($this->isValidPrivateKey($plainKey) === false) {
|
if ($this->isValidPrivateKey($plainKey) === false) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -437,15 +443,15 @@ class Crypt {
|
||||||
* @param string $keyFileContents
|
* @param string $keyFileContents
|
||||||
* @param string $passPhrase
|
* @param string $passPhrase
|
||||||
* @param string $cipher
|
* @param string $cipher
|
||||||
|
* @param int $version
|
||||||
* @return string
|
* @return string
|
||||||
* @throws DecryptionFailedException
|
* @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);
|
$catFile = $this->splitMetaData($keyFileContents, $cipher);
|
||||||
|
|
||||||
if ($catFile['signature'] !== false) {
|
if ($catFile['signature'] !== false) {
|
||||||
$this->checkSignature($catFile['encrypted'], $passPhrase, $catFile['signature']);
|
$this->checkSignature($catFile['encrypted'], $passPhrase.$version, $catFile['signature']);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->decrypt($catFile['encrypted'],
|
return $this->decrypt($catFile['encrypted'],
|
||||||
|
|
|
@ -100,6 +100,9 @@ class Encryption implements IEncryptionModule {
|
||||||
/** @var int unencrypted block size */
|
/** @var int unencrypted block size */
|
||||||
private $unencryptedBlockSize = 6126;
|
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
|
* or if no additional data is needed return a empty array
|
||||||
*/
|
*/
|
||||||
public function begin($path, $user, $mode, array $header, array $accessList) {
|
public function begin($path, $user, $mode, array $header, array $accessList) {
|
||||||
|
|
||||||
$this->path = $this->getPathToRealFile($path);
|
$this->path = $this->getPathToRealFile($path);
|
||||||
$this->accessList = $accessList;
|
$this->accessList = $accessList;
|
||||||
$this->user = $user;
|
$this->user = $user;
|
||||||
|
@ -180,6 +182,8 @@ class Encryption implements IEncryptionModule {
|
||||||
$this->fileKey = $this->keyManager->getFileKey($this->path, $this->user);
|
$this->fileKey = $this->keyManager->getFileKey($this->path, $this->user);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->version = (int)$this->keyManager->getVersion($this->path);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
$mode === 'w'
|
$mode === 'w'
|
||||||
|| $mode === 'w+'
|
|| $mode === 'w+'
|
||||||
|
@ -220,8 +224,13 @@ class Encryption implements IEncryptionModule {
|
||||||
public function end($path) {
|
public function end($path) {
|
||||||
$result = '';
|
$result = '';
|
||||||
if ($this->isWriteOperation) {
|
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)) {
|
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 = '';
|
$this->writeCache = '';
|
||||||
}
|
}
|
||||||
$publicKeys = array();
|
$publicKeys = array();
|
||||||
|
@ -258,7 +267,6 @@ class Encryption implements IEncryptionModule {
|
||||||
* @return string encrypted data
|
* @return string encrypted data
|
||||||
*/
|
*/
|
||||||
public function encrypt($data) {
|
public function encrypt($data) {
|
||||||
|
|
||||||
// If extra data is left over from the last round, make sure it
|
// If extra data is left over from the last round, make sure it
|
||||||
// is integrated into the next block
|
// is integrated into the next block
|
||||||
if ($this->writeCache) {
|
if ($this->writeCache) {
|
||||||
|
@ -302,7 +310,11 @@ class Encryption implements IEncryptionModule {
|
||||||
// Read the chunk from the start of $data
|
// Read the chunk from the start of $data
|
||||||
$chunk = substr($data, 0, $this->unencryptedBlockSizeSigned);
|
$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
|
// Remove the chunk we just processed from
|
||||||
// $data, leaving only unprocessed data in $data
|
// $data, leaving only unprocessed data in $data
|
||||||
|
@ -334,7 +346,7 @@ class Encryption implements IEncryptionModule {
|
||||||
|
|
||||||
$result = '';
|
$result = '';
|
||||||
if (!empty($data)) {
|
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;
|
return $result;
|
||||||
}
|
}
|
||||||
|
@ -349,6 +361,7 @@ class Encryption implements IEncryptionModule {
|
||||||
*/
|
*/
|
||||||
public function update($path, $uid, array $accessList) {
|
public function update($path, $uid, array $accessList) {
|
||||||
$fileKey = $this->keyManager->getFileKey($path, $uid);
|
$fileKey = $this->keyManager->getFileKey($path, $uid);
|
||||||
|
$version = $this->keyManager->getVersion($path);
|
||||||
|
|
||||||
if (!empty($fileKey)) {
|
if (!empty($fileKey)) {
|
||||||
|
|
||||||
|
@ -369,6 +382,8 @@ class Encryption implements IEncryptionModule {
|
||||||
|
|
||||||
$this->keyManager->setAllFileKeys($path, $encryptedFileKey);
|
$this->keyManager->setAllFileKeys($path, $encryptedFileKey);
|
||||||
|
|
||||||
|
$this->keyManager->setVersion($path, $version);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
$this->logger->debug('no file key found, we assume that the file "{file}" is not encrypted',
|
$this->logger->debug('no file key found, we assume that the file "{file}" is not encrypted',
|
||||||
array('file' => $path, 'app' => 'encryption'));
|
array('file' => $path, 'app' => 'encryption'));
|
||||||
|
|
|
@ -412,6 +412,24 @@ class KeyManager {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
* get the encrypted file key
|
||||||
*
|
*
|
||||||
|
@ -546,6 +564,7 @@ class KeyManager {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $path
|
* @param string $path
|
||||||
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function deleteAllFileKeys($path) {
|
public function deleteAllFileKeys($path) {
|
||||||
return $this->keyStorage->deleteAllFileKeys($path);
|
return $this->keyStorage->deleteAllFileKeys($path);
|
||||||
|
|
Loading…
Reference in New Issue