Exemplo n.º 1
0
 /**
  * @NoAdminRequired
  * @UseSession
  *
  * @param string $oldPassword
  * @param string $newPassword
  * @return DataResponse
  */
 public function updatePrivateKeyPassword($oldPassword, $newPassword)
 {
     $result = false;
     $uid = $this->userSession->getUser()->getUID();
     $errorMessage = $this->l->t('Could not update the private key password.');
     //check if password is correct
     $passwordCorrect = $this->userManager->checkPassword($uid, $newPassword);
     if ($passwordCorrect !== false) {
         $encryptedKey = $this->keyManager->getPrivateKey($uid);
         $decryptedKey = $this->crypt->decryptPrivateKey($encryptedKey, $oldPassword);
         if ($decryptedKey) {
             $encryptedKey = $this->crypt->symmetricEncryptFileContent($decryptedKey, $newPassword);
             $header = $this->crypt->generateHeader();
             if ($encryptedKey) {
                 $this->keyManager->setPrivateKey($uid, $header . $encryptedKey);
                 $this->session->setPrivateKey($decryptedKey);
                 $result = true;
             }
         } else {
             $errorMessage = $this->l->t('The old password was not correct, please try again.');
         }
     } else {
         $errorMessage = $this->l->t('The current log-in password was not correct, please try again.');
     }
     if ($result === true) {
         $this->session->setStatus(Session::INIT_SUCCESSFUL);
         return new DataResponse(['message' => (string) $this->l->t('Private key password successfully updated.')]);
     } else {
         return new DataResponse(['message' => (string) $errorMessage], Http::STATUS_BAD_REQUEST);
     }
 }
Exemplo n.º 2
0
 /**
  * @dataProvider dataTestGetFileKey
  *
  * @param $uid
  * @param $isMasterKeyEnabled
  * @param $privateKey
  * @param $expected
  */
 public function testGetFileKey($uid, $isMasterKeyEnabled, $privateKey, $expected)
 {
     $path = '/foo.txt';
     if ($isMasterKeyEnabled) {
         $expectedUid = 'masterKeyId';
     } else {
         $expectedUid = $uid;
     }
     $this->invokePrivate($this->instance, 'masterKeyId', ['masterKeyId']);
     $this->keyStorageMock->expects($this->at(0))->method('getFileKey')->with($path, 'fileKey', 'OC_DEFAULT_MODULE')->willReturn(true);
     $this->keyStorageMock->expects($this->at(1))->method('getFileKey')->with($path, $expectedUid . '.shareKey', 'OC_DEFAULT_MODULE')->willReturn(true);
     if (is_null($uid)) {
         $this->keyStorageMock->expects($this->once())->method('getSystemUserKey')->willReturn(true);
         $this->cryptMock->expects($this->once())->method('decryptPrivateKey')->willReturn($privateKey);
     } else {
         $this->keyStorageMock->expects($this->never())->method('getSystemUserKey');
         $this->utilMock->expects($this->once())->method('isMasterKeyEnabled')->willReturn($isMasterKeyEnabled);
         $this->sessionMock->expects($this->once())->method('getPrivateKey')->willReturn($privateKey);
     }
     if ($privateKey) {
         $this->cryptMock->expects($this->once())->method('multiKeyDecrypt')->willReturn(true);
     } else {
         $this->cryptMock->expects($this->never())->method('multiKeyDecrypt');
     }
     $this->assertSame($expected, $this->instance->getFileKey($path, $uid));
 }
Exemplo n.º 3
0
 /**
  * start receiving chunks from a file. This is the place where you can
  * perform some initial step before starting encrypting/decrypting the
  * chunks
  *
  * @param string $path to the file
  * @param string $user who read/write the file
  * @param string $mode php stream open mode
  * @param array $header contains the header data read from the file
  * @param array $accessList who has access to the file contains the key 'users' and 'public'
  *
  * @return array $header contain data as key-value pairs which should be
  *                       written to the header, in case of a write operation
  *                       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;
     $this->isWriteOperation = false;
     $this->writeCache = '';
     if ($this->session->decryptAllModeActivated()) {
         $encryptedFileKey = $this->keyManager->getEncryptedFileKey($this->path);
         $shareKey = $this->keyManager->getShareKey($this->path, $this->session->getDecryptAllUid());
         $this->fileKey = $this->crypt->multiKeyDecrypt($encryptedFileKey, $shareKey, $this->session->getDecryptAllKey());
     } else {
         $this->fileKey = $this->keyManager->getFileKey($this->path, $this->user);
     }
     if ($mode === 'w' || $mode === 'w+' || $mode === 'wb' || $mode === 'wb+') {
         $this->isWriteOperation = true;
         if (empty($this->fileKey)) {
             $this->fileKey = $this->crypt->generateFileKey();
         }
     }
     if (isset($header['cipher'])) {
         $this->cipher = $header['cipher'];
     } elseif ($this->isWriteOperation) {
         $this->cipher = $this->crypt->getCipher();
     } else {
         // if we read a file without a header we fall-back to the legacy cipher
         // which was used in <=oC6
         $this->cipher = $this->crypt->getLegacyCipher();
     }
     return array('cipher' => $this->cipher);
 }
Exemplo n.º 4
0
 /**
  *
  */
 public function testClearWillRemoveValues()
 {
     $this->instance->setPrivateKey('privateKey');
     $this->instance->setStatus('initStatus');
     $this->instance->prepareDecryptAll('user', 'key');
     $this->assertNotEmpty(self::$tempStorage);
     $this->instance->clear();
     $this->assertEmpty(self::$tempStorage);
 }
Exemplo n.º 5
0
 /**
  * @NoAdminRequired
  * @return DataResponse
  */
 public function getStatus()
 {
     $status = 'error';
     $message = 'no valid init status';
     switch ($this->session->getStatus()) {
         case Session::RUN_MIGRATION:
             $status = 'interactionNeeded';
             $message = (string) $this->l->t('You need to migrate your encryption keys from the old encryption (ownCloud <= 8.0) to the new one. Please run \'occ encryption:migrate\' or contact your administrator');
             break;
         case Session::INIT_EXECUTED:
             $status = 'interactionNeeded';
             $message = (string) $this->l->t('Invalid private key for Encryption App. Please update your private key password in your personal settings to recover access to your encrypted files.');
             break;
         case Session::NOT_INITIALIZED:
             $status = 'interactionNeeded';
             $message = (string) $this->l->t('Encryption App is enabled but your keys are not initialized, please log-out and log-in again');
             break;
         case Session::INIT_SUCCESSFUL:
             $status = 'success';
             $message = (string) $this->l->t('Encryption App is enabled and ready');
     }
     return new DataResponse(['status' => $status, 'data' => ['message' => $message]]);
 }
Exemplo n.º 6
0
 /**
  * @param $path raw path relative to data/
  * @param $mode
  * @param $options
  * @param $opened_path
  * @return bool
  */
 public function stream_open($path, $mode, $options, &$opened_path)
 {
     // assume that the file already exist before we decide it finally in getKey()
     $this->newFile = false;
     if (!isset($this->rootView)) {
         $this->rootView = new \OC_FilesystemView('/');
     }
     $this->session = new \OCA\Encryption\Session($this->rootView);
     $this->privateKey = $this->session->getPrivateKey();
     // rawPath is relative to the data directory
     $this->rawPath = \OC\Files\Filesystem::normalizePath(str_replace('crypt://', '', $path));
     $this->userId = Helper::getUser($this->rawPath);
     $util = new Util($this->rootView, $this->userId);
     // get the key ID which we want to use, can be the users key or the
     // public share key
     $this->keyId = $util->getKeyId();
     // Strip identifier text from path, this gives us the path relative to data/<user>/files
     $this->relPath = Helper::stripUserFilesPath($this->rawPath);
     // if raw path doesn't point to a real file, check if it is a version or a file in the trash bin
     if ($this->relPath === false) {
         $this->relPath = Helper::getPathToRealFile($this->rawPath);
     }
     if ($this->relPath === false) {
         \OCP\Util::writeLog('Encryption library', 'failed to open file "' . $this->rawPath . '" expecting a path to "files", "files_versions" or "cache"', \OCP\Util::ERROR);
         return false;
     }
     // Disable fileproxies so we can get the file size and open the source file without recursive encryption
     $proxyStatus = \OC_FileProxy::$enabled;
     \OC_FileProxy::$enabled = false;
     if ($mode === 'w' or $mode === 'w+' or $mode === 'wb' or $mode === 'wb+') {
         // We're writing a new file so start write counter with 0 bytes
         $this->size = 0;
         $this->unencryptedSize = 0;
     } else {
         if ($this->privateKey === false) {
             // if private key is not valid redirect user to a error page
             \OCA\Encryption\Helper::redirectToErrorPage($this->session);
         }
         $this->size = $this->rootView->filesize($this->rawPath, $mode);
     }
     $this->handle = $this->rootView->fopen($this->rawPath, $mode);
     \OC_FileProxy::$enabled = $proxyStatus;
     if (!is_resource($this->handle)) {
         \OCP\Util::writeLog('Encryption library', 'failed to open file "' . $this->rawPath . '"', \OCP\Util::ERROR);
     } else {
         $this->meta = stream_get_meta_data($this->handle);
     }
     return is_resource($this->handle);
 }
Exemplo n.º 7
0
 /**
  * Change a user's encryption passphrase
  *
  * @param array $params keys: uid, password
  * @return boolean|null
  */
 public function setPassphrase($params)
 {
     // Get existing decrypted private key
     $privateKey = $this->session->getPrivateKey();
     $user = $this->user->getUser();
     // current logged in user changes his own password
     if ($user && $params['uid'] === $user->getUID() && $privateKey) {
         // Encrypt private key with new user pwd as passphrase
         $encryptedPrivateKey = $this->crypt->encryptPrivateKey($privateKey, $params['password'], $params['uid']);
         // Save private key
         if ($encryptedPrivateKey) {
             $this->keyManager->setPrivateKey($this->user->getUser()->getUID(), $this->crypt->generateHeader() . $encryptedPrivateKey);
         } else {
             $this->logger->error('Encryption could not update users encryption password');
         }
         // NOTE: Session does not need to be updated as the
         // private key has not changed, only the passphrase
         // used to decrypt it has changed
     } else {
         // admin changed the password for a different user, create new keys and re-encrypt file keys
         $user = $params['uid'];
         $this->initMountPoints($user);
         $recoveryPassword = isset($params['recoveryPassword']) ? $params['recoveryPassword'] : null;
         // we generate new keys if...
         // ...we have a recovery password and the user enabled the recovery key
         // ...encryption was activated for the first time (no keys exists)
         // ...the user doesn't have any files
         if ($this->recovery->isRecoveryEnabledForUser($user) && $recoveryPassword || !$this->keyManager->userHasKeys($user) || !$this->util->userHasFiles($user)) {
             // backup old keys
             //$this->backupAllKeys('recovery');
             $newUserPassword = $params['password'];
             $keyPair = $this->crypt->createKeyPair();
             // Save public key
             $this->keyManager->setPublicKey($user, $keyPair['publicKey']);
             // Encrypt private key with new password
             $encryptedKey = $this->crypt->encryptPrivateKey($keyPair['privateKey'], $newUserPassword, $user);
             if ($encryptedKey) {
                 $this->keyManager->setPrivateKey($user, $this->crypt->generateHeader() . $encryptedKey);
                 if ($recoveryPassword) {
                     // if recovery key is set we can re-encrypt the key files
                     $this->recovery->recoverUsersFiles($recoveryPassword, $user);
                 }
             } else {
                 $this->logger->error('Encryption Could not update users encryption password');
             }
         }
     }
 }
Exemplo n.º 8
0
 /**
  * test begin() if decryptAll mode was activated
  */
 public function testBeginDecryptAll()
 {
     $path = '/user/files/foo.txt';
     $recoveryKeyId = 'recoveryKeyId';
     $recoveryShareKey = 'recoveryShareKey';
     $decryptAllKey = 'decryptAllKey';
     $fileKey = 'fileKey';
     $this->sessionMock->expects($this->once())->method('decryptAllModeActivated')->willReturn(true);
     $this->sessionMock->expects($this->once())->method('getDecryptAllUid')->willReturn($recoveryKeyId);
     $this->sessionMock->expects($this->once())->method('getDecryptAllKey')->willReturn($decryptAllKey);
     $this->keyManagerMock->expects($this->once())->method('getEncryptedFileKey')->willReturn('encryptedFileKey');
     $this->keyManagerMock->expects($this->once())->method('getShareKey')->with($path, $recoveryKeyId)->willReturn($recoveryShareKey);
     $this->cryptMock->expects($this->once())->method('multiKeyDecrypt')->with('encryptedFileKey', $recoveryShareKey, $decryptAllKey)->willReturn($fileKey);
     $this->keyManagerMock->expects($this->never())->method('getFileKey');
     $this->instance->begin($path, 'user', 'r', [], []);
     $this->assertSame($fileKey, $this->invokePrivate($this->instance, 'fileKey'));
 }
Exemplo n.º 9
0
 /**
  * @param $path
  * @param $uid
  * @return string
  */
 public function getFileKey($path, $uid)
 {
     $encryptedFileKey = $this->keyStorage->getFileKey($path, $this->fileKeyId, Encryption::ID);
     if (is_null($uid)) {
         $uid = $this->getPublicShareKeyId();
         $shareKey = $this->getShareKey($path, $uid);
         $privateKey = $this->keyStorage->getSystemUserKey($this->publicShareKeyId . '.privateKey', Encryption::ID);
         $privateKey = $this->crypt->decryptPrivateKey($privateKey);
     } else {
         $shareKey = $this->getShareKey($path, $uid);
         $privateKey = $this->session->getPrivateKey();
     }
     if ($encryptedFileKey && $shareKey && $privateKey) {
         return $this->crypt->multiKeyDecrypt($encryptedFileKey, $shareKey, $privateKey);
     }
     return '';
 }
 /**
  * test updatePrivateKeyPassword() with the correct old and new password
  */
 public function testUpdatePrivateKeyPassword()
 {
     $oldPassword = '******';
     $newPassword = '******';
     $this->ocSessionMock->expects($this->once())->method('get')->with('loginname')->willReturn('testUser');
     $this->userManagerMock->expects($this->at(0))->method('checkPassword')->with('testUserUid', 'new')->willReturn(false);
     $this->userManagerMock->expects($this->at(1))->method('checkPassword')->with('testUser', 'new')->willReturn(true);
     $this->cryptMock->expects($this->once())->method('decryptPrivateKey')->willReturn('decryptedKey');
     $this->cryptMock->expects($this->once())->method('encryptPrivateKey')->willReturn('encryptedKey');
     $this->cryptMock->expects($this->once())->method('generateHeader')->willReturn('header.');
     // methods which must be called after successful changing the key password
     $this->keyManagerMock->expects($this->once())->method('setPrivateKey')->with($this->equalTo('testUserUid'), $this->equalTo('header.encryptedKey'));
     $this->sessionMock->expects($this->once())->method('setPrivateKey')->with($this->equalTo('decryptedKey'));
     $this->sessionMock->expects($this->once())->method('setStatus')->with($this->equalTo(Session::INIT_SUCCESSFUL));
     $result = $this->controller->updatePrivateKeyPassword($oldPassword, $newPassword);
     $data = $result->getData();
     $this->assertSame(Http::STATUS_OK, $result->getStatus());
     $this->assertSame('Private key password successfully updated.', $data['message']);
 }
Exemplo n.º 11
0
 /**
  * start receiving chunks from a file. This is the place where you can
  * perform some initial step before starting encrypting/decrypting the
  * chunks
  *
  * @param string $path to the file
  * @param string $user who read/write the file
  * @param string $mode php stream open mode
  * @param array $header contains the header data read from the file
  * @param array $accessList who has access to the file contains the key 'users' and 'public'
  *
  * @return array $header contain data as key-value pairs which should be
  *                       written to the header, in case of a write operation
  *                       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;
     $this->isWriteOperation = false;
     $this->writeCache = '';
     if ($this->session->decryptAllModeActivated()) {
         $encryptedFileKey = $this->keyManager->getEncryptedFileKey($this->path);
         $shareKey = $this->keyManager->getShareKey($this->path, $this->session->getDecryptAllUid());
         $this->fileKey = $this->crypt->multiKeyDecrypt($encryptedFileKey, $shareKey, $this->session->getDecryptAllKey());
     } else {
         $this->fileKey = $this->keyManager->getFileKey($this->path, $this->user);
     }
     // always use the version from the original file, also part files
     // need to have a correct version number if they get moved over to the
     // final location
     $this->version = (int) $this->keyManager->getVersion($this->stripPartFileExtension($path), new View());
     if ($mode === 'w' || $mode === 'w+' || $mode === 'wb' || $mode === 'wb+') {
         $this->isWriteOperation = true;
         if (empty($this->fileKey)) {
             $this->fileKey = $this->crypt->generateFileKey();
         }
     } else {
         // if we read a part file we need to increase the version by 1
         // because the version number was also increased by writing
         // the part file
         if (Scanner::isPartialFile($path)) {
             $this->version = $this->version + 1;
         }
     }
     if ($this->isWriteOperation) {
         $this->cipher = $this->crypt->getCipher();
     } elseif (isset($header['cipher'])) {
         $this->cipher = $header['cipher'];
     } else {
         // if we read a file without a header we fall-back to the legacy cipher
         // which was used in <=oC6
         $this->cipher = $this->crypt->getLegacyCipher();
     }
     return array('cipher' => $this->cipher, 'signed' => 'true');
 }
Exemplo n.º 12
0
 /**
  * @NoAdminRequired
  * @UseSession
  *
  * @param string $oldPassword
  * @param string $newPassword
  * @return DataResponse
  */
 public function updatePrivateKeyPassword($oldPassword, $newPassword)
 {
     $result = false;
     $uid = $this->userSession->getUser()->getUID();
     $errorMessage = $this->l->t('Could not update the private key password.');
     //check if password is correct
     $passwordCorrect = $this->userManager->checkPassword($uid, $newPassword);
     if ($passwordCorrect === false) {
         // if check with uid fails we need to check the password with the login name
         // e.g. in the ldap case. For local user we need to check the password with
         // the uid because in this case the login name is case insensitive
         $loginName = $this->ocSession->get('loginname');
         $passwordCorrect = $this->userManager->checkPassword($loginName, $newPassword);
     }
     if ($passwordCorrect !== false) {
         $encryptedKey = $this->keyManager->getPrivateKey($uid);
         $decryptedKey = $this->crypt->decryptPrivateKey($encryptedKey, $oldPassword, $uid);
         if ($decryptedKey) {
             $encryptedKey = $this->crypt->encryptPrivateKey($decryptedKey, $newPassword, $uid);
             $header = $this->crypt->generateHeader();
             if ($encryptedKey) {
                 $this->keyManager->setPrivateKey($uid, $header . $encryptedKey);
                 $this->session->setPrivateKey($decryptedKey);
                 $result = true;
             }
         } else {
             $errorMessage = $this->l->t('The old password was not correct, please try again.');
         }
     } else {
         $errorMessage = $this->l->t('The current log-in password was not correct, please try again.');
     }
     if ($result === true) {
         $this->session->setStatus(Session::INIT_SUCCESSFUL);
         return new DataResponse(['message' => (string) $this->l->t('Private key password successfully updated.')]);
     } else {
         return new DataResponse(['message' => (string) $errorMessage], Http::STATUS_BAD_REQUEST);
     }
 }
Exemplo n.º 13
0
 /**
  * @param $path
  * @param $mode
  * @param $options
  * @param $opened_path
  * @return bool
  */
 public function stream_open($path, $mode, $options, &$opened_path)
 {
     if (!isset($this->rootView)) {
         $this->rootView = new \OC_FilesystemView('/');
     }
     $this->session = new \OCA\Encryption\Session($this->rootView);
     $this->privateKey = $this->session->getPrivateKey($this->userId);
     $util = new Util($this->rootView, \OCP\USER::getUser());
     $this->userId = $util->getUserId();
     // Strip identifier text from path, this gives us the path relative to data/<user>/files
     $this->relPath = \OC\Files\Filesystem::normalizePath(str_replace('crypt://', '', $path));
     // rawPath is relative to the data directory
     $this->rawPath = $util->getUserFilesDir() . $this->relPath;
     // Disable fileproxies so we can get the file size and open the source file without recursive encryption
     $proxyStatus = \OC_FileProxy::$enabled;
     \OC_FileProxy::$enabled = false;
     if ($mode === 'w' or $mode === 'w+' or $mode === 'wb' or $mode === 'wb+') {
         // We're writing a new file so start write counter with 0 bytes
         $this->size = 0;
         $this->unencryptedSize = 0;
     } else {
         if ($this->privateKey === false) {
             // if private key is not valid redirect user to a error page
             \OCA\Encryption\Helper::redirectToErrorPage();
         }
         $this->size = $this->rootView->filesize($this->rawPath, $mode);
     }
     $this->handle = $this->rootView->fopen($this->rawPath, $mode);
     \OC_FileProxy::$enabled = $proxyStatus;
     if (!is_resource($this->handle)) {
         \OCP\Util::writeLog('Encryption library', 'failed to open file "' . $this->rawPath . '"', \OCP\Util::ERROR);
     } else {
         $this->meta = stream_get_meta_data($this->handle);
     }
     return is_resource($this->handle);
 }
Exemplo n.º 14
0
 protected function updateSession($user, $privateKey)
 {
     $this->session->prepareDecryptAll($user, $privateKey);
 }
Exemplo n.º 15
0
 /**
  *
  */
 public function testClearWillRemoveValues()
 {
     $this->instance->clear();
     $this->assertEmpty(self::$tempStorage);
 }
Exemplo n.º 16
0
 /**
  * Encrypt keyfile to multiple users
  * @param Session $session
  * @param array $users list of users which should be able to access the file
  * @param string $filePath path of the file to be shared
  * @return bool
  */
 public function setSharedFileKeyfiles(Session $session, array $users, $filePath)
 {
     // Make sure users are capable of sharing
     $filteredUids = $this->filterShareReadyUsers($users);
     // If we're attempting to share to unready users
     if (!empty($filteredUids['unready'])) {
         \OCP\Util::writeLog('Encryption library', 'Sharing to these user(s) failed as they are unready for encryption:"' . print_r($filteredUids['unready'], 1), \OCP\Util::WARN);
         return false;
     }
     // Get public keys for each user, ready for generating sharekeys
     $userPubKeys = Keymanager::getPublicKeys($this->view, $filteredUids['ready']);
     // Note proxy status then disable it
     $proxyStatus = \OC_FileProxy::$enabled;
     \OC_FileProxy::$enabled = false;
     // Get the current users's private key for decrypting existing keyfile
     $privateKey = $session->getPrivateKey();
     try {
         // Decrypt keyfile
         $plainKeyfile = $this->decryptKeyfile($filePath, $privateKey);
         // Re-enc keyfile to (additional) sharekeys
         $multiEncKey = Crypt::multiKeyEncrypt($plainKeyfile, $userPubKeys);
     } catch (Exceptions\EncryptionException $e) {
         $msg = 'set shareFileKeyFailed (code: ' . $e->getCode() . '): ' . $e->getMessage();
         \OCP\Util::writeLog('files_encryption', $msg, \OCP\Util::FATAL);
         return false;
     } catch (\Exception $e) {
         $msg = 'set shareFileKeyFailed (unknown error): ' . $e->getMessage();
         \OCP\Util::writeLog('files_encryption', $msg, \OCP\Util::FATAL);
         return false;
     }
     // Save the recrypted key to it's owner's keyfiles directory
     // Save new sharekeys to all necessary user directory
     if (!Keymanager::setFileKey($this->view, $this, $filePath, $multiEncKey['data']) || !Keymanager::setShareKeys($this->view, $this, $filePath, $multiEncKey['keys'])) {
         \OCP\Util::writeLog('Encryption library', 'Keyfiles could not be saved for users sharing ' . $filePath, \OCP\Util::ERROR);
         return false;
     }
     // Return proxy to original status
     \OC_FileProxy::$enabled = $proxyStatus;
     return true;
 }