|
|
|
@ -44,6 +44,9 @@ namespace OCA\Encryption; |
|
|
|
|
* buffer size used internally by PHP. The encryption process makes the input |
|
|
|
|
* data longer, and input is chunked into smaller pieces in order to result in |
|
|
|
|
* a 8192 encrypted block size. |
|
|
|
|
* @note When files are deleted via webdav, or when they are updated and the |
|
|
|
|
* previous version deleted, this is handled by OC\Files\View, and thus the |
|
|
|
|
* encryption proxies are used and keyfiles deleted. |
|
|
|
|
*/ |
|
|
|
|
class Stream { |
|
|
|
|
|
|
|
|
@ -171,17 +174,21 @@ class Stream { |
|
|
|
|
// |
|
|
|
|
// Get the data from the file handle |
|
|
|
|
$data = fread( $this->handle, 8192 ); |
|
|
|
|
|
|
|
|
|
$result = ''; |
|
|
|
|
|
|
|
|
|
if ( strlen( $data ) ) { |
|
|
|
|
|
|
|
|
|
$this->getKey(); |
|
|
|
|
if ( ! $this->getKey() ) { |
|
|
|
|
|
|
|
|
|
// Error! We don't have a key to decrypt the file with |
|
|
|
|
throw new \Exception( 'Encryption key not found for "' . $this->rawPath . '" during attempted read via stream' ); |
|
|
|
|
|
|
|
|
|
$result = Crypt::symmetricDecryptFileContent( $data, $this->keyfile ); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Decrypt data |
|
|
|
|
$result = Crypt::symmetricDecryptFileContent( $data, $this->plainKey ); |
|
|
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
|
|
$result = ''; |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// $length = $this->size - $pos; |
|
|
|
@ -224,18 +231,20 @@ class Stream { |
|
|
|
|
*/ |
|
|
|
|
public function getKey() { |
|
|
|
|
|
|
|
|
|
// fix performance issues |
|
|
|
|
if(isset($this->keyfile) && isset($this->encKeyfile)) { |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// If a keyfile already exists for a file named identically to |
|
|
|
|
// file to be written |
|
|
|
|
if ( $this->rootView->file_exists( $this->userId . '/'. 'files_encryption' . '/' . 'keyfiles' . '/' . $this->relPath . '.key' ) ) { |
|
|
|
|
// Check if key is already set |
|
|
|
|
if ( isset( $this->plainKey ) && isset( $this->encKeyfile ) ) { |
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// TODO: add error handling for when file exists but no |
|
|
|
|
// keyfile |
|
|
|
|
// Avoid problems with .part file extensions |
|
|
|
|
$this->relPath = Keymanager::fixPartialFilePath( $this->relPath ); |
|
|
|
|
|
|
|
|
|
// If a keyfile already exists |
|
|
|
|
if ( $this->rootView->file_exists( $this->userId . '/'. 'files_encryption' . '/' . 'keyfiles' . '/' . $this->relPath . '.key' ) ) { |
|
|
|
|
|
|
|
|
|
// Fetch and decrypt keyfile |
|
|
|
|
// Fetch existing keyfile |
|
|
|
|
$this->encKeyfile = Keymanager::getFileKey( $this->rootView, $this->userId, $this->relPath ); |
|
|
|
|
|
|
|
|
@ -247,12 +256,17 @@ class Stream { |
|
|
|
|
|
|
|
|
|
$shareKey = Keymanager::getShareKey( $this->rootView, $this->userId, $this->relPath ); |
|
|
|
|
|
|
|
|
|
$this->keyfile = Crypt::multiKeyDecrypt( $this->encKeyfile, $shareKey, $privateKey ); |
|
|
|
|
$this->plainKey = Crypt::multiKeyDecrypt( $this->encKeyfile, $shareKey, $privateKey ); |
|
|
|
|
|
|
|
|
|
trigger_error( '$this->relPath = '.$this->relPath ); |
|
|
|
|
trigger_error( '$this->userId = '.$this->userId); |
|
|
|
|
trigger_error( '$this->encKeyfile = '.$this->encKeyfile ); |
|
|
|
|
trigger_error( '$this->plainKey1 = '.var_export($this->plainKey, 1)); |
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
|
|
} |
|
|
|
@ -303,7 +317,7 @@ class Stream { |
|
|
|
|
$pointer = ftell( $this->handle ); |
|
|
|
|
|
|
|
|
|
// Make sure the userId is set |
|
|
|
|
$this->getuser(); |
|
|
|
|
$this->setUserProperty(); |
|
|
|
|
|
|
|
|
|
// TODO: Check if file is shared, if so, use multiKeyEncrypt and |
|
|
|
|
// save shareKeys in necessary user directories |
|
|
|
@ -313,21 +327,34 @@ class Stream { |
|
|
|
|
// one), save the newly generated keyfile |
|
|
|
|
if ( ! $this->getKey() ) { |
|
|
|
|
|
|
|
|
|
// TODO: Reuse the keyfile, it it exists, instead of making a new one |
|
|
|
|
$this->keyfile = Crypt::generateKey(); |
|
|
|
|
$util = new Util( $this->rootView, $this->userId ); |
|
|
|
|
|
|
|
|
|
$this->plainKey = Crypt::generateKey(); |
|
|
|
|
|
|
|
|
|
$this->publicKey = Keymanager::getPublicKey( $this->rootView, $this->userId ); |
|
|
|
|
|
|
|
|
|
$this->encKeyfile = Crypt::keyEncrypt( $this->keyfile, $this->publicKey ); |
|
|
|
|
$sharingEnabled = \OCP\Share::isEnabled(); |
|
|
|
|
|
|
|
|
|
$uniqueUserIds = $util->getSharingUsersArray( $sharingEnabled, $this->relPath ); |
|
|
|
|
|
|
|
|
|
// Fetch public keys for all users who will share the file |
|
|
|
|
$publicKeys = Keymanager::getPublicKeys( $this->rootView, $uniqueUserIds ); |
|
|
|
|
|
|
|
|
|
$this->encKeyfiles = Crypt::multiKeyEncrypt( $this->plainKey, $publicKeys ); |
|
|
|
|
|
|
|
|
|
$view = new \OC_FilesystemView( '/' ); |
|
|
|
|
$userId = \OCP\User::getUser(); |
|
|
|
|
|
|
|
|
|
// Save the new encrypted file key |
|
|
|
|
Keymanager::setFileKey( $view, $this->relPath, $userId, $this->encKeyfile ); |
|
|
|
|
Keymanager::setShareKeys( $view, $this->relPath, $this->encKeyfiles['keys'] ); |
|
|
|
|
|
|
|
|
|
// trigger_error( '$this->relPath = '.$this->relPath ); |
|
|
|
|
// trigger_error( '$this->userId = '.$this->userId); |
|
|
|
|
// trigger_error( '$this->encKeyfile = '.var_export($this->encKeyfiles, 1) ); |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// trigger_error( '$this->plainKey2 = '.var_export($this->plainKey, 1)); |
|
|
|
|
|
|
|
|
|
// If extra data is left over from the last round, make sure it |
|
|
|
|
// is integrated into the next 6126 / 8192 block |
|
|
|
|
if ( $this->writeCache ) { |
|
|
|
@ -355,7 +382,7 @@ class Stream { |
|
|
|
|
// |
|
|
|
|
// fseek( $this->handle, - ( $currentPos % 8192 ), SEEK_CUR ); |
|
|
|
|
// |
|
|
|
|
// $block = Crypt::symmetricDecryptFileContent( $unencryptedNewBlock, $this->keyfile ); |
|
|
|
|
// $block = Crypt::symmetricDecryptFileContent( $unencryptedNewBlock, $this->plainKey ); |
|
|
|
|
// |
|
|
|
|
// $x = substr( $block, 0, $currentPos % 8192 ); |
|
|
|
|
// |
|
|
|
@ -396,7 +423,7 @@ class Stream { |
|
|
|
|
// Read the chunk from the start of $data |
|
|
|
|
$chunk = substr( $data, 0, 6126 ); |
|
|
|
|
|
|
|
|
|
$encrypted = $this->preWriteEncrypt( $chunk, $this->keyfile ); |
|
|
|
|
$encrypted = $this->preWriteEncrypt( $chunk, $this->plainKey ); |
|
|
|
|
|
|
|
|
|
// Write the data chunk to disk. This will be |
|
|
|
|
// attended to the last data chunk if the file |
|
|
|
@ -461,7 +488,7 @@ class Stream { |
|
|
|
|
// Set keyfile property for file in question |
|
|
|
|
$this->getKey(); |
|
|
|
|
|
|
|
|
|
$encrypted = $this->preWriteEncrypt( $this->writeCache, $this->keyfile ); |
|
|
|
|
$encrypted = $this->preWriteEncrypt( $this->writeCache, $this->plainKey ); |
|
|
|
|
|
|
|
|
|
fwrite( $this->handle, $encrypted ); |
|
|
|
|
|
|
|
|
|