/** * @param string $uid user id * @param string $password user password * @return bool */ public function setupUser($uid, $password) { if (!$this->keyManager->userHasKeys($uid)) { return $this->keyManager->storeKeyPair($uid, $password, $this->crypt->createKeyPair()); } return true; }
/** * @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); } }
/** * @param string $uid userid * @param string $password user password * @return bool */ public function setupServerSide($uid, $password) { // Check if user already has keys if (!$this->keyManager->userHasKeys($uid)) { return $this->keyManager->storeKeyPair($uid, $password, $this->crypt->createKeyPair()); } return true; }
/** * @dataProvider dataTestSetupUser * * @param bool $hasKeys * @param bool $expected */ public function testSetupUser($hasKeys, $expected) { $this->keyManagerMock->expects($this->once())->method('userHasKeys')->with('uid')->willReturn($hasKeys); if ($hasKeys) { $this->keyManagerMock->expects($this->never())->method('storeKeyPair'); } else { $this->cryptMock->expects($this->once())->method('createKeyPair')->willReturn('keyPair'); $this->keyManagerMock->expects($this->once())->method('storeKeyPair')->with('uid', 'password', 'keyPair')->willReturn(true); } $this->assertSame($expected, $this->instance->setupUser('uid', 'password')); }
/** * update encrypted file, e.g. give additional users access to the file * * @param string $path path to the file which should be updated * @param string $uid of the user who performs the operation * @param array $accessList who has access to the file contains the key 'users' and 'public' * @return boolean */ public function update($path, $uid, array $accessList) { if (empty($accessList)) { if (isset(self::$rememberVersion[$path])) { $this->keyManager->setVersion($path, self::$rememberVersion[$path], new View()); unset(self::$rememberVersion[$path]); } return; } $fileKey = $this->keyManager->getFileKey($path, $uid); if (!empty($fileKey)) { $publicKeys = array(); if ($this->useMasterPassword === true) { $publicKeys[$this->keyManager->getMasterKeyId()] = $this->keyManager->getPublicMasterKey(); } else { foreach ($accessList['users'] as $user) { try { $publicKeys[$user] = $this->keyManager->getPublicKey($user); } catch (PublicKeyMissingException $e) { $this->logger->warning('Could not encrypt file for ' . $user . ': ' . $e->getMessage()); } } } $publicKeys = $this->keyManager->addSystemKeys($accessList, $publicKeys, $uid); $encryptedFileKey = $this->crypt->multiKeyEncrypt($fileKey, $publicKeys); $this->keyManager->deleteAllFileKeys($path); $this->keyManager->setAllFileKeys($path, $encryptedFileKey); } else { $this->logger->debug('no file key found, we assume that the file "{file}" is not encrypted', array('file' => $path, 'app' => 'encryption')); return false; } return true; }
/** * get the private key which will be used to decrypt all files * * @param string $user * @param string $password * @return bool|string * @throws \OCA\Encryption\Exceptions\PrivateKeyMissingException */ protected function getPrivateKey($user, $password) { $recoveryKeyId = $this->keyManager->getRecoveryKeyId(); if ($user === $recoveryKeyId) { $recoveryKey = $this->keyManager->getSystemPrivateKey($recoveryKeyId); $privateKey = $this->crypt->decryptPrivateKey($recoveryKey, $password); } else { $userKey = $this->keyManager->getPrivateKey($user); $privateKey = $this->crypt->decryptPrivateKey($userKey, $password, $user); } return $privateKey; }
public function testRecoverFile() { $this->keyManagerMock->expects($this->once())->method('getEncryptedFileKey')->willReturn(true); $this->keyManagerMock->expects($this->once())->method('getShareKey')->willReturn(true); $this->cryptMock->expects($this->once())->method('multiKeyDecrypt')->willReturn(true); $this->fileMock->expects($this->once())->method('getAccessList')->willReturn(['users' => ['admin']]); $this->keyManagerMock->expects($this->once())->method('getPublicKey')->willReturn('publicKey'); $this->keyManagerMock->expects($this->once())->method('addSystemKeys')->with($this->anything(), $this->anything(), $this->equalTo('admin'))->willReturn(['admin' => 'publicKey']); $this->cryptMock->expects($this->once())->method('multiKeyEncrypt'); $this->keyManagerMock->expects($this->once())->method('setAllFileKeys'); $this->assertNull(self::invokePrivate($this->instance, 'recoverFile', ['/', 'testkey', 'admin'])); }
/** * update encrypted file, e.g. give additional users access to the file * * @param string $path path to the file which should be updated * @param string $uid of the user who performs the operation * @param array $accessList who has access to the file contains the key 'users' and 'public' * @return boolean */ public function update($path, $uid, array $accessList) { $fileKey = $this->keyManager->getFileKey($path, $uid); $publicKeys = array(); foreach ($accessList['users'] as $user) { $publicKeys[$user] = $this->keyManager->getPublicKey($user); } $publicKeys = $this->keyManager->addSystemKeys($accessList, $publicKeys); $encryptedFileKey = $this->crypt->multiKeyEncrypt($fileKey, $publicKeys); $this->keyManager->deleteAllFileKeys($path); $this->keyManager->setAllFileKeys($path, $encryptedFileKey); return true; }
/** * 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'); } } } }
/** * Test case if the public key is missing. ownCloud should still encrypt * the file for the remaining users */ public function testUpdateMissingPublicKey() { $this->keyManagerMock->expects($this->once())->method('getFileKey')->willReturn('fileKey'); $this->keyManagerMock->expects($this->any())->method('getPublicKey')->willReturnCallback(function ($user) { throw new PublicKeyMissingException($user); }); $this->keyManagerMock->expects($this->any())->method('addSystemKeys')->willReturnCallback(function ($accessList, $publicKeys) { return $publicKeys; }); $this->cryptMock->expects($this->once())->method('multiKeyEncrypt')->willReturnCallback(function ($fileKey, $publicKeys) { $this->assertEmpty($publicKeys); $this->assertSame('fileKey', $fileKey); }); $this->keyManagerMock->expects($this->never())->method('getVersion'); $this->keyManagerMock->expects($this->never())->method('setVersion'); $this->assertTrue($this->instance->update('path', 'user1', ['users' => ['user1']])); }
/** * @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 ''; }
/** * recover file * * @param string $path * @param string $privateKey * @param string $uid */ private function recoverFile($path, $privateKey, $uid) { $encryptedFileKey = $this->keyManager->getEncryptedFileKey($path); $shareKey = $this->keyManager->getShareKey($path, $this->keyManager->getRecoveryKeyId()); if ($encryptedFileKey && $shareKey && $privateKey) { $fileKey = $this->crypt->multiKeyDecrypt($encryptedFileKey, $shareKey, $privateKey); } if (!empty($fileKey)) { $accessList = $this->file->getAccessList($path); $publicKeys = array(); foreach ($accessList['users'] as $user) { $publicKeys[$user] = $this->keyManager->getPublicKey($user); } $publicKeys = $this->keyManager->addSystemKeys($accessList, $publicKeys, $uid); $encryptedKeyfiles = $this->crypt->multiKeyEncrypt($fileKey, $publicKeys); $this->keyManager->setAllFileKeys($path, $encryptedKeyfiles); } }
/** * update encrypted file, e.g. give additional users access to the file * * @param string $path path to the file which should be updated * @param string $uid of the user who performs the operation * @param array $accessList who has access to the file contains the key 'users' and 'public' * @return boolean */ public function update($path, $uid, array $accessList) { $fileKey = $this->keyManager->getFileKey($path, $uid); if (!empty($fileKey)) { $publicKeys = array(); foreach ($accessList['users'] as $user) { $publicKeys[$user] = $this->keyManager->getPublicKey($user); } $publicKeys = $this->keyManager->addSystemKeys($accessList, $publicKeys, $uid); $encryptedFileKey = $this->crypt->multiKeyEncrypt($fileKey, $publicKeys); $this->keyManager->deleteAllFileKeys($path); $this->keyManager->setAllFileKeys($path, $encryptedFileKey); } else { $this->logger->debug('no file key found, we assume that the file "{file}" is not encrypted', array('file' => $path, 'app' => 'encryption')); return false; } return true; }
/** * 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']); }
/** * @dataProvider dataTestValidateMasterKey * * @param $masterKey */ public function testValidateMasterKey($masterKey) { /** @var \OCA\Encryption\KeyManager | \PHPUnit_Framework_MockObject_MockObject $instance */ $instance = $this->getMockBuilder('OCA\\Encryption\\KeyManager')->setConstructorArgs([$this->keyStorageMock, $this->cryptMock, $this->configMock, $this->userMock, $this->sessionMock, $this->logMock, $this->utilMock])->setMethods(['getPublicMasterKey', 'setSystemPrivateKey', 'getMasterKeyPassword'])->getMock(); $instance->expects($this->once())->method('getPublicMasterKey')->willReturn($masterKey); $instance->expects($this->any())->method('getMasterKeyPassword')->willReturn('masterKeyPassword'); $this->cryptMock->expects($this->any())->method('generateHeader')->willReturn('header'); if (empty($masterKey)) { $this->cryptMock->expects($this->once())->method('createKeyPair')->willReturn(['publicKey' => 'public', 'privateKey' => 'private']); $this->keyStorageMock->expects($this->once())->method('setSystemUserKey')->with('systemKeyId.publicKey', 'public', \OCA\Encryption\Crypto\Encryption::ID); $this->cryptMock->expects($this->once())->method('encryptPrivateKey')->with('private', 'masterKeyPassword', 'systemKeyId')->willReturn('EncryptedKey'); $instance->expects($this->once())->method('setSystemPrivateKey')->with('systemKeyId', 'headerEncryptedKey'); } else { $this->cryptMock->expects($this->never())->method('createKeyPair'); $this->keyStorageMock->expects($this->never())->method('setSystemUserKey'); $this->cryptMock->expects($this->never())->method('encryptPrivateKey'); $instance->expects($this->never())->method('setSystemPrivateKey'); } $instance->validateMasterKey(); }
/** * @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); } }
/** * @dataProvider dataProviderGetCipher * @param string $configValue * @param string $expected */ public function testGetCipher($configValue, $expected) { $this->config->expects($this->once())->method('getSystemValue')->with($this->equalTo('cipher'), $this->equalTo('AES-256-CTR'))->willReturn($configValue); $this->assertSame($expected, $this->crypt->getCipher()); }