protected function setUp() { parent::setUp(); // login user self::loginHelper(self::TEST_ENCRYPTION_UTIL_USER1); \OC_User::setUserId(self::TEST_ENCRYPTION_UTIL_USER1); $this->userId = self::TEST_ENCRYPTION_UTIL_USER1; $this->pass = self::TEST_ENCRYPTION_UTIL_USER1; // set content for encrypting / decrypting in tests $this->dataUrl = __DIR__ . '/../lib/crypt.php'; $this->dataShort = 'hats'; $this->dataLong = file_get_contents(__DIR__ . '/../lib/crypt.php'); $this->legacyData = __DIR__ . '/legacy-text.txt'; $this->legacyEncryptedData = __DIR__ . '/legacy-encrypted-text.txt'; $this->legacyEncryptedDataKey = __DIR__ . '/encryption.key'; $this->legacyKey = "30943623843030686906"; $keypair = \OCA\Files_Encryption\Crypt::createKeypair(); $this->genPublicKey = $keypair['publicKey']; $this->genPrivateKey = $keypair['privateKey']; $this->publicKeyDir = \OCA\Files_Encryption\Keymanager::getPublicKeyPath(); $this->encryptionDir = '/' . $this->userId . '/' . 'files_encryption'; $this->keysPath = $this->encryptionDir . '/' . 'keys'; $this->publicKeyPath = $this->publicKeyDir . '/' . $this->userId . '.publicKey'; // e.g. data/public-keys/admin.publicKey $this->privateKeyPath = $this->encryptionDir . '/' . $this->userId . '.privateKey'; // e.g. data/admin/admin.privateKey $this->view = new \OC\Files\View('/'); $this->util = new \OCA\Files_Encryption\Util($this->view, $this->userId); // remember files_trashbin state $this->stateFilesTrashbin = \OC_App::isEnabled('files_trashbin'); // we don't want to tests with app files_trashbin enabled \OC_App::disable('files_trashbin'); }
/** * decrypt private key and add it to the current session * @param array $params with 'uid' and 'password' * @return mixed session or false */ public function initEncryption($params) { $session = new Session($this->view); // we tried to initialize the encryption app for this session $session->setInitialized(Session::INIT_EXECUTED); $encryptedKey = Keymanager::getPrivateKey($this->view, $params['uid']); $privateKey = false; if ($encryptedKey) { $privateKey = Crypt::decryptPrivateKey($encryptedKey, $params['password']); } if ($privateKey === false) { \OCP\Util::writeLog('Encryption library', 'Private key for user "' . $params['uid'] . '" is not valid! Maybe the user password was changed from outside if so please change it back to gain access', \OCP\Util::ERROR); return false; } $session->setPrivateKey($privateKey); $session->setInitialized(Session::INIT_SUCCESSFUL); return $session; }
/** * @brief replacing encryption keys during password change should be allowed * until the user logged in for the first time */ public function testSetPassphrase() { $view = new \OC\Files\View(); // set user password for the first time \OC_User::createUser(self::TEST_ENCRYPTION_HOOKS_USER3, 'newUserPassword'); \OCA\Files_Encryption\Hooks::postCreateUser(array('uid' => self::TEST_ENCRYPTION_HOOKS_USER3, 'password' => 'newUserPassword')); $this->assertTrue($view->file_exists(\OCA\Files_Encryption\Keymanager::getPublicKeyPath() . '/' . self::TEST_ENCRYPTION_HOOKS_USER3 . '.publicKey')); $this->assertTrue($view->file_exists(self::TEST_ENCRYPTION_HOOKS_USER3 . '/files_encryption/' . self::TEST_ENCRYPTION_HOOKS_USER3 . '.privateKey')); // check if we are able to decrypt the private key $encryptedKey = \OCA\Files_Encryption\Keymanager::getPrivateKey($view, self::TEST_ENCRYPTION_HOOKS_USER3); $privateKey = \OCA\Files_Encryption\Crypt::decryptPrivateKey($encryptedKey, 'newUserPassword'); $this->assertTrue(is_string($privateKey)); // change the password before the user logged-in for the first time, // we can replace the encryption keys \OCA\Files_Encryption\Hooks::setPassphrase(array('uid' => self::TEST_ENCRYPTION_HOOKS_USER3, 'password' => 'passwordChanged')); $encryptedKey = \OCA\Files_Encryption\Keymanager::getPrivateKey($view, self::TEST_ENCRYPTION_HOOKS_USER3); $privateKey = \OCA\Files_Encryption\Crypt::decryptPrivateKey($encryptedKey, 'passwordChanged'); $this->assertTrue(is_string($privateKey)); // now create a files folder to simulate a already used account $view->mkdir('/' . self::TEST_ENCRYPTION_HOOKS_USER3 . '/files'); // change the password after the user logged in, now the password should not change \OCA\Files_Encryption\Hooks::setPassphrase(array('uid' => self::TEST_ENCRYPTION_HOOKS_USER3, 'password' => 'passwordChanged2')); $encryptedKey = \OCA\Files_Encryption\Keymanager::getPrivateKey($view, self::TEST_ENCRYPTION_HOOKS_USER3); $privateKey = \OCA\Files_Encryption\Crypt::decryptPrivateKey($encryptedKey, 'passwordChanged2'); $this->assertFalse($privateKey); $privateKey = \OCA\Files_Encryption\Crypt::decryptPrivateKey($encryptedKey, 'passwordChanged'); $this->assertTrue(is_string($privateKey)); }
$errorMessage = $l->t('Please repeat the new recovery password'); \OCP\JSON::error(array('data' => array('message' => $errorMessage))); exit; } if ($_POST['newPassword'] !== $_POST['confirmPassword']) { $errorMessage = $l->t('Repeated recovery key password does not match the provided recovery key password'); \OCP\JSON::error(array('data' => array('message' => $errorMessage))); exit; } $view = new \OC\Files\View('/'); $util = new \OCA\Files_Encryption\Util(new \OC\Files\View('/'), \OCP\User::getUser()); $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; $keyId = $util->getRecoveryKeyId(); $encryptedRecoveryKey = \OCA\Files_Encryption\Keymanager::getPrivateSystemKey($keyId); $decryptedRecoveryKey = $encryptedRecoveryKey ? \OCA\Files_Encryption\Crypt::decryptPrivateKey($encryptedRecoveryKey, $oldPassword) : false; if ($decryptedRecoveryKey) { $cipher = \OCA\Files_Encryption\Helper::getCipher(); $encryptedKey = \OCA\Files_Encryption\Crypt::symmetricEncryptFileContent($decryptedRecoveryKey, $newPassword, $cipher); if ($encryptedKey) { \OCA\Files_Encryption\Keymanager::setPrivateSystemKey($encryptedKey, $keyId); $return = true; } } \OC_FileProxy::$enabled = $proxyStatus; // success or failure if ($return) { \OCP\JSON::success(array('data' => array('message' => $l->t('Password successfully changed.')))); } else { \OCP\JSON::error(array('data' => array('message' => $l->t('Could not change the password. Maybe the old password was not correct.')))); }
/** * @medium */ function testFailShareFile() { // login as admin self::loginHelper(self::TEST_ENCRYPTION_SHARE_USER1); // save file with content $cryptedFile = file_put_contents('crypt:///' . self::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->filename, $this->dataShort); // test that data was successfully written $this->assertInternalType('int', $cryptedFile); // disable encryption proxy to prevent recursive calls $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; // get the file info from previous created file $fileInfo = $this->view->getFileInfo('/' . self::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->filename); // check if we have a valid file info $this->assertInstanceOf('\\OC\\Files\\FileInfo', $fileInfo); // check if the unencrypted file size is stored $this->assertGreaterThan(0, $fileInfo['unencrypted_size']); // break users public key $this->view->rename(\OCA\Files_Encryption\Keymanager::getPublicKeyPath() . '/' . self::TEST_ENCRYPTION_SHARE_USER3 . '.publicKey', \OCA\Files_Encryption\Keymanager::getPublicKeyPath() . '/' . self::TEST_ENCRYPTION_SHARE_USER3 . '.publicKey_backup'); // re-enable the file proxy \OC_FileProxy::$enabled = $proxyStatus; // share the file try { \OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_GROUP, self::TEST_ENCRYPTION_SHARE_GROUP1, \OCP\Constants::PERMISSION_ALL); } catch (\Exception $e) { $this->assertEquals(0, strpos($e->getMessage(), "Following users are not set up for encryption")); } // login as admin self::loginHelper(self::TEST_ENCRYPTION_SHARE_USER1); // check if share key for user1 not exists $this->assertFalse($this->view->file_exists('/' . self::TEST_ENCRYPTION_SHARE_USER1 . '/files_encryption/keys/' . $this->filename . '/' . self::TEST_ENCRYPTION_SHARE_USER3 . '.shareKey')); // disable encryption proxy to prevent recursive calls $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; // break user1 public key $this->view->rename(\OCA\Files_Encryption\Keymanager::getPublicKeyPath() . '/' . self::TEST_ENCRYPTION_SHARE_USER3 . '.publicKey_backup', \OCA\Files_Encryption\Keymanager::getPublicKeyPath() . '/' . self::TEST_ENCRYPTION_SHARE_USER3 . '.publicKey'); // remove share file $this->view->unlink('/' . self::TEST_ENCRYPTION_SHARE_USER1 . '/files_encryption/keys/' . $this->filename . '/' . self::TEST_ENCRYPTION_SHARE_USER3 . '.shareKey'); // re-enable the file proxy \OC_FileProxy::$enabled = $proxyStatus; // unshare the file with user1 \OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_GROUP, self::TEST_ENCRYPTION_SHARE_GROUP1); // check if share key not exists $this->assertFalse($this->view->file_exists('/' . self::TEST_ENCRYPTION_SHARE_USER1 . '/files_encryption/keys/' . $this->filename . '/' . self::TEST_ENCRYPTION_SHARE_USER3 . '.shareKey')); // cleanup $this->view->chroot('/' . self::TEST_ENCRYPTION_SHARE_USER1 . '/files/'); $this->view->unlink($this->filename); $this->view->chroot('/'); }
/** * @return bool */ public function stream_close() { $this->flush(); // if there is no valid private key return false if ($this->privateKey === false) { // cleanup if ($this->meta['mode'] !== 'r' && $this->meta['mode'] !== 'rb' && !$this->isLocalTmpFile) { // Disable encryption proxy to prevent recursive calls $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; if ($this->rootView->file_exists($this->rawPath) && $this->size === 0) { fclose($this->handle); $this->rootView->unlink($this->rawPath); } // Re-enable proxy - our work is done \OC_FileProxy::$enabled = $proxyStatus; } // if private key is not valid redirect user to a error page Helper::redirectToErrorPage($this->session); } if ($this->meta['mode'] !== 'r' && $this->meta['mode'] !== 'rb' && $this->isLocalTmpFile === false && $this->size > 0 && $this->unencryptedSize > 0) { // only write keyfiles if it was a new file if ($this->newFile === true) { // Disable encryption proxy to prevent recursive calls $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; // Fetch user's public key $this->publicKey = Keymanager::getPublicKey($this->rootView, $this->keyId); // Check if OC sharing api is enabled $sharingEnabled = \OCP\Share::isEnabled(); // Get all users sharing the file includes current user $uniqueUserIds = $this->util->getSharingUsersArray($sharingEnabled, $this->relPath); $checkedUserIds = $this->util->filterShareReadyUsers($uniqueUserIds); // Fetch public keys for all sharing users $publicKeys = Keymanager::getPublicKeys($this->rootView, $checkedUserIds['ready']); // Encrypt enc key for all sharing users $this->encKeyfiles = Crypt::multiKeyEncrypt($this->plainKey, $publicKeys); // Save the new encrypted file key Keymanager::setFileKey($this->rootView, $this->util, $this->relPath, $this->encKeyfiles['data']); // Save the sharekeys Keymanager::setShareKeys($this->rootView, $this->util, $this->relPath, $this->encKeyfiles['keys']); // Re-enable proxy - our work is done \OC_FileProxy::$enabled = $proxyStatus; } // we need to update the file info for the real file, not for the // part file. $path = Helper::stripPartialFileExtension($this->rawPath); $fileInfo = array('mimetype' => $this->rootView->getMimeType($this->rawPath), 'encrypted' => true, 'unencrypted_size' => $this->unencryptedSize); // if we write a part file we also store the unencrypted size for // the part file so that it can be re-used later $this->rootView->putFileInfo($this->rawPath, $fileInfo); if ($path !== $this->rawPath) { $this->rootView->putFileInfo($path, $fileInfo); } } $result = fclose($this->handle); if ($result === false) { \OCP\Util::writeLog('Encryption library', 'Could not close stream, file could be corrupted', \OCP\Util::FATAL); } return $result; }
$view = new \OC\Files\View('/'); $session = new \OCA\Files_Encryption\Session($view); $user = \OCP\User::getUser(); $loginName = \OC::$server->getUserSession()->getLoginName(); // check new password $passwordCorrect = \OCP\User::checkPassword($loginName, $newPassword); if ($passwordCorrect !== false) { $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; $encryptedKey = \OCA\Files_Encryption\Keymanager::getPrivateKey($view, $user); $decryptedKey = $encryptedKey ? \OCA\Files_Encryption\Crypt::decryptPrivateKey($encryptedKey, $oldPassword) : false; if ($decryptedKey) { $cipher = \OCA\Files_Encryption\Helper::getCipher(); $encryptedKey = \OCA\Files_Encryption\Crypt::symmetricEncryptFileContent($decryptedKey, $newPassword, $cipher); if ($encryptedKey) { \OCA\Files_Encryption\Keymanager::setPrivateKey($encryptedKey, $user); $session->setPrivateKey($decryptedKey); $return = true; } } else { $result = false; $errorMessage = $l->t('The old password was not correct, please try again.'); } \OC_FileProxy::$enabled = $proxyStatus; } else { $result = false; $errorMessage = $l->t('The current log-in password was not correct, please try again.'); } // success or failure if ($return) { $session->setInitialized(\OCA\Files_Encryption\Session::INIT_SUCCESSFUL);
/** * @medium */ function testRecursiveDelShareKeysFile() { $this->view->mkdir('/' . self::TEST_USER . '/files/folder1'); $this->view->file_put_contents('/' . self::TEST_USER . '/files/folder1/existingFile.txt', 'data'); // create folder structure for some dummy share key files $this->view->mkdir('/' . self::TEST_USER . '/files_encryption/keys/folder1'); $this->view->mkdir('/' . self::TEST_USER . '/files_encryption/keys/folder1/existingFile.txt'); // create some dummy share keys $this->view->file_put_contents('/' . self::TEST_USER . '/files_encryption/keys/folder1/existingFile.txt/user1.shareKey', 'data'); $this->view->file_put_contents('/' . self::TEST_USER . '/files_encryption/keys/folder1/existingFile.txt/user2.shareKey', 'data'); $this->view->file_put_contents('/' . self::TEST_USER . '/files_encryption/keys/folder1/existingFile.txt/user3.shareKey', 'data'); $this->view->file_put_contents('/' . self::TEST_USER . '/files_encryption/keys/folder1/existingFile.txt/' . self::TEST_USER . '.shareKey', 'data'); // recursive delete share keys from user1 and user2 \OCA\Files_Encryption\Keymanager::delShareKey($this->view, array('user1', 'user2', self::TEST_USER), \OCA\Files_Encryption\Keymanager::getKeyPath($this->view, new \OCA\Files_Encryption\Util($this->view, self::TEST_USER), '/folder1/existingFile.txt'), self::TEST_USER, '/folder1/existingFile.txt'); // check if share keys from user1 and user2 are deleted $this->assertFalse($this->view->file_exists('/' . self::TEST_USER . '/files_encryption/keys/folder1/existingFile/user1.shareKey')); $this->assertFalse($this->view->file_exists('/' . self::TEST_USER . '/files_encryption/keys/folder1/existingFile/user2.shareKey')); // check if share keys for user3 and owner $this->assertTrue($this->view->file_exists('/' . self::TEST_USER . '/files_encryption/keys/folder1/existingFile.txt/' . self::TEST_USER . '.shareKey')); $this->assertTrue($this->view->file_exists('/' . self::TEST_USER . '/files_encryption/keys/folder1/existingFile.txt/user3.shareKey')); // cleanup $this->view->deleteAll('/' . self::TEST_USER . '/files/folder1'); }