/** * @medium * @brief Test that data that is written by the crypto stream wrapper * @note Encrypted data is manually prepared and decrypted here to avoid dependency on success of stream_read * @note If this test fails with truncate content, check that enough array slices are being rejoined to form $e, as the crypt.php file may have gotten longer and broken the manual * reassembly of its data */ function testSymmetricStreamEncryptLongFileContent() { // Generate a a random filename $filename = 'tmp-' . uniqid() . '.test'; $util = new Encryption\Util(new \OC_FilesystemView(), $this->userId); // Save long data as encrypted file using stream wrapper $cryptedFile = file_put_contents('crypt:///' . $this->userId . '/files/' . $filename, $this->dataLong . $this->dataLong); // Test that data was successfully written $this->assertTrue(is_int($cryptedFile)); // Disable encryption proxy to prevent recursive calls $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; // Get file contents without using any wrapper to get it's actual contents on disk $retreivedCryptedFile = $this->view->file_get_contents($this->userId . '/files/' . $filename); // Re-enable proxy - our work is done \OC_FileProxy::$enabled = $proxyStatus; // Check that the file was encrypted before being written to disk $this->assertNotEquals($this->dataLong . $this->dataLong, $retreivedCryptedFile); // Manuallly split saved file into separate IVs and encrypted chunks $r = preg_split('/(00iv00.{16,18})/', $retreivedCryptedFile, NULL, PREG_SPLIT_DELIM_CAPTURE); //print_r($r); // Join IVs and their respective data chunks $e = array(); $i = 0; while ($i < count($r) - 1) { $e[] = $r[$i] . $r[$i + 1]; $i = $i + 2; } //print_r($e); // Get the encrypted keyfile $encKeyfile = Encryption\Keymanager::getFileKey($this->view, $util, $filename); // Attempt to fetch the user's shareKey $shareKey = Encryption\Keymanager::getShareKey($this->view, $this->userId, $util, $filename); // get session $session = new \OCA\Encryption\Session($this->view); // get private key $privateKey = $session->getPrivateKey($this->userId); // Decrypt keyfile with shareKey $plainKeyfile = Encryption\Crypt::multiKeyDecrypt($encKeyfile, $shareKey, $privateKey); // Set var for reassembling decrypted content $decrypt = ''; // Manually decrypt chunk foreach ($e as $chunk) { $chunkDecrypt = Encryption\Crypt::symmetricDecryptFileContent($chunk, $plainKeyfile); // Assemble decrypted chunks $decrypt .= $chunkDecrypt; } $this->assertEquals($this->dataLong . $this->dataLong, $decrypt); // Teardown $this->view->unlink($this->userId . '/files/' . $filename); Encryption\Keymanager::deleteFileKey($this->view, $filename); }
/** * @medium * Test that data that is written by the crypto stream wrapper with AES 128 * @note Encrypted data is manually prepared and decrypted here to avoid dependency on success of stream_read * @note If this test fails with truncate content, check that enough array slices are being rejoined to form $e, as the crypt.php file may have gotten longer and broken the manual * reassembly of its data */ public function testStreamDecryptLongFileContentWithoutHeader() { // Generate a a random filename $filename = 'tmp-' . $this->getUniqueID() . '.test'; \OCP\Config::setSystemValue('cipher', 'AES-128-CFB'); // Save long data as encrypted file using stream wrapper $cryptedFile = file_put_contents('crypt:///' . $this->userId . '/files/' . $filename, $this->dataLong . $this->dataLong); \OCP\Config::deleteSystemValue('cipher'); // Test that data was successfully written $this->assertTrue(is_int($cryptedFile)); // Disable encryption proxy to prevent recursive calls $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; // Get file contents without using any wrapper to get it's actual contents on disk $retreivedCryptedFile = $this->view->file_get_contents($this->userId . '/files/' . $filename); // Check that the file was encrypted before being written to disk $this->assertNotEquals($this->dataLong . $this->dataLong, $retreivedCryptedFile); // remove the header to check if we can also decrypt old files without a header, // this files should fall back to AES-128 $cryptedWithoutHeader = substr($retreivedCryptedFile, Encryption\Crypt::BLOCKSIZE); $this->view->file_put_contents($this->userId . '/files/' . $filename, $cryptedWithoutHeader); // Re-enable proxy - our work is done \OC_FileProxy::$enabled = $proxyStatus; $decrypted = file_get_contents('crypt:///' . $this->userId . '/files/' . $filename); $this->assertEquals($this->dataLong . $this->dataLong, $decrypted); // Teardown $this->view->unlink($this->userId . '/files/' . $filename); Encryption\Keymanager::deleteFileKey($this->view, $filename); }
/** * @brief if the file was really deleted we remove the encryption keys * @param array $params * @return boolean */ public static function postDelete($params) { if (!isset(self::$deleteFiles[$params[\OC\Files\Filesystem::signal_param_path]])) { return true; } $deletedFile = self::$deleteFiles[$params[\OC\Files\Filesystem::signal_param_path]]; $path = $deletedFile['path']; $user = $deletedFile['uid']; // we don't need to remember the file any longer unset(self::$deleteFiles[$params[\OC\Files\Filesystem::signal_param_path]]); $view = new \OC\Files\View('/'); // return if the file still exists and wasn't deleted correctly if ($view->file_exists('/' . $user . '/files/' . $path)) { return true; } // Disable encryption proxy to prevent recursive calls $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; // Delete keyfile & shareKey so it isn't orphaned if (!Keymanager::deleteFileKey($view, $path, $user)) { \OCP\Util::writeLog('Encryption library', 'Keyfile or shareKey could not be deleted for file "' . $user . '/files/' . $path . '"', \OCP\Util::ERROR); } Keymanager::delAllShareKeys($view, $user, $path); \OC_FileProxy::$enabled = $proxyStatus; }
/** * @medium */ function testDeleteFileKeyFolder() { $this->view->mkdir('/' . Test_Encryption_Keymanager::TEST_USER . '/files/folder1'); $this->view->file_put_contents('/' . Test_Encryption_Keymanager::TEST_USER . '/files/folder1/existingFile.txt', 'data'); // create folder structure for some dummy file key files $this->view->mkdir('/' . Test_Encryption_Keymanager::TEST_USER . '/files_encryption/keyfiles/folder1'); // create dummy keyfile $this->view->file_put_contents('/' . Test_Encryption_Keymanager::TEST_USER . '/files_encryption/keyfiles/folder1/dummyFile.txt.key', 'data'); // recursive delete share keys from user1 and user2 $result = Encryption\Keymanager::deleteFileKey($this->view, '/folder1'); $this->assertFalse($result); // all file keys should still exists if we try to delete a folder with keys for which some files still exists $this->assertTrue($this->view->file_exists('/' . Test_Encryption_Keymanager::TEST_USER . '/files_encryption/keyfiles/folder1/dummyFile.txt.key')); $this->assertTrue($this->view->file_exists('/' . Test_Encryption_Keymanager::TEST_USER . '/files_encryption/keyfiles/folder1/existingFile.txt.key')); // delete folder $this->view->unlink('/' . Test_Encryption_Keymanager::TEST_USER . '/files/folder1'); // create dummy keyfile $this->view->file_put_contents('/' . Test_Encryption_Keymanager::TEST_USER . '/files_encryption/keyfiles/folder1/dummyFile.txt.key', 'data'); // now file keys should be deleted since the folder no longer exists $result = Encryption\Keymanager::deleteFileKey($this->view, '/folder1'); $this->assertTrue($result); $this->assertFalse($this->view->file_exists('/' . Test_Encryption_Keymanager::TEST_USER . '/files_encryption/keyfiles/folder1')); // cleanup $this->view->deleteAll('/' . Test_Encryption_Keymanager::TEST_USER . '/files/folder1'); }