diff options
Diffstat (limited to 'apps/encryption/lib/keymanager.php')
-rw-r--r-- | apps/encryption/lib/keymanager.php | 324 |
1 files changed, 254 insertions, 70 deletions
diff --git a/apps/encryption/lib/keymanager.php b/apps/encryption/lib/keymanager.php index 272bf0849c2..83b24c79b8c 100644 --- a/apps/encryption/lib/keymanager.php +++ b/apps/encryption/lib/keymanager.php @@ -22,21 +22,27 @@ namespace OCA\Encryption; +use OC\Encryption\Exceptions\DecryptionFailedException; use OC\Encryption\Exceptions\PrivateKeyMissingException; use OC\Encryption\Exceptions\PublicKeyMissingException; use OCA\Encryption\Crypto\Crypt; -use OCP\Encryption\IKeyStorage; +use OCP\Encryption\Keys\IStorage; +use OCP\ICache; +use OCP\ICacheFactory; use OCP\IConfig; -use OCP\IUser; +use OCP\ILogger; use OCP\IUserSession; class KeyManager { /** - * @var IKeyStorage + * @var ICache + */ + public static $cacheFactory; + /** + * @var IStorage */ private $keyStorage; - /** * @var Crypt */ @@ -53,35 +59,143 @@ class KeyManager { * @var string UserID */ private $keyId; + /** + * @var string + */ + private $publicKeyId = 'public'; + /** + * @var string + */ + private $privateKeyId = 'private'; /** * @var string */ - private $publicKeyId = '.public'; + private $shareKeyId = 'sharekey'; + /** * @var string */ - private $privateKeyId = '.private'; + private $fileKeyId = 'filekey'; /** * @var IConfig */ private $config; + /** + * @var ILogger + */ + private $log; /** - * @param IKeyStorage $keyStorage + * @param IStorage $keyStorage * @param Crypt $crypt * @param IConfig $config * @param IUserSession $userSession + * @param ICacheFactory $cacheFactory + * @param ILogger $log */ - public function __construct(IKeyStorage $keyStorage, Crypt $crypt, IConfig $config, IUserSession $userSession) { + public function __construct(IStorage $keyStorage, Crypt $crypt, IConfig $config, IUserSession $userSession, ICacheFactory $cacheFactory, ILogger $log) { $this->keyStorage = $keyStorage; $this->crypt = $crypt; $this->config = $config; - $this->recoveryKeyId = $this->config->getAppValue('encryption', 'recoveryKeyId'); - $this->publicShareKeyId = $this->config->getAppValue('encryption', 'publicShareKeyId'); + $this->recoveryKeyId = $this->config->getAppValue('encryption', + 'recoveryKeyId'); + $this->publicShareKeyId = $this->config->getAppValue('encryption', + 'publicShareKeyId'); $this->keyId = $userSession && $userSession->isLoggedIn() ? $userSession->getUser()->getUID() : false; + self::$cacheFactory = $cacheFactory; + self::$cacheFactory = self::$cacheFactory->create('encryption'); + $this->log = $log; + } + + /** + * @return bool + */ + public function recoveryKeyExists() { + return (strlen($this->keyStorage->getSystemUserKey($this->recoveryKeyId)) !== 0); + } + + /** + * @param $password + * @return bool + */ + public function checkRecoveryPassword($password) { + $recoveryKey = $this->keyStorage->getSystemUserKey($this->recoveryKeyId); + $decryptedRecoveryKey = $this->crypt->decryptPrivateKey($recoveryKey, + $password); + + if ($decryptedRecoveryKey) { + return true; + } + return false; + } + + /** + * @param string $uid + * @param string $password + * @param string $keyPair + * @return bool + */ + public function storeKeyPair($uid, $password, $keyPair) { + // Save Public Key + $this->setPublicKey($uid, $keyPair['publicKey']); + + $encryptedKey = $this->crypt->symmetricEncryptFileContent($keyPair['privateKey'], + $password); + + if ($encryptedKey) { + $this->setPrivateKey($uid, $encryptedKey); + $this->config->setAppValue('encryption', 'recoveryAdminEnabled', 1); + return true; + } + return false; + } + + /** + * @param $userId + * @param $key + * @return bool + */ + public function setPublicKey($userId, $key) { + return $this->keyStorage->setUserKey($userId, $this->publicKeyId, $key); + } + + /** + * @param $userId + * @param $key + * @return bool + */ + public function setPrivateKey($userId, $key) { + return $this->keyStorage->setUserKey($userId, + $this->privateKeyId, + $key); + } + + /** + * Decrypt private key and store it + * + * @param string $uid userid + * @param string $passPhrase users password + * @return ICache + */ + public function init($uid, $passPhrase) { + try { + $privateKey = $this->getPrivateKey($uid); + $privateKey = $this->crypt->decryptPrivateKey($privateKey, + $passPhrase); + } catch (PrivateKeyMissingException $e) { + return false; + } catch (DecryptionFailedException $e) { + return false; + } + + self::$cacheFactory->set('privateKey', $privateKey); + self::$cacheFactory->set('initStatus', true); + + + return self::$cacheFactory; } /** @@ -90,7 +204,8 @@ class KeyManager { * @throws PrivateKeyMissingException */ public function getPrivateKey($userId) { - $privateKey = $this->keyStorage->getUserKey($userId, $this->privateKeyId); + $privateKey = $this->keyStorage->getUserKey($userId, + $this->privateKeyId); if (strlen($privateKey) !== 0) { return $privateKey; @@ -99,24 +214,105 @@ class KeyManager { } /** - * @param $userId + * @param $path * @return mixed - * @throws PublicKeyMissingException */ - public function getPublicKey($userId) { - $publicKey = $this->keyStorage->getUserKey($userId, $this->publicKeyId); + public function getFileKey($path) { + return $this->keyStorage->getFileKey($path, $this->fileKeyId); + } - if (strlen($publicKey) !== 0) { - return $publicKey; - } - throw new PublicKeyMissingException(); + /** + * @param $path + * @return mixed + */ + public function getShareKey($path) { + return $this->keyStorage->getFileKey($path, $this->keyId . $this->shareKeyId); } /** + * Change a user's encryption passphrase + * + * @param array $params keys: uid, password + * @param IUserSession $user + * @param Util $util * @return bool */ - public function recoveryKeyExists() { - return (strlen($this->keyStorage->getSystemUserKey($this->recoveryKeyId)) !== 0); + public function setPassphrase($params, IUserSession $user, Util $util) { + + // Only attempt to change passphrase if server-side encryption + // is in use (client-side encryption does not have access to + // the necessary keys) + if ($this->crypt->mode() === 'server') { + + // Get existing decrypted private key + $privateKey = self::$cacheFactory->get('privateKey'); + + if ($params['uid'] === $user->getUser()->getUID() && $privateKey) { + + // Encrypt private key with new user pwd as passphrase + $encryptedPrivateKey = $this->crypt->symmetricEncryptFileContent($privateKey, + $params['password']); + + // Save private key + if ($encryptedPrivateKey) { + $this->setPrivateKey($user->getUser()->getUID(), + $encryptedPrivateKey); + } else { + $this->log->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 reencrypt file keys + + $user = $params['uid']; + $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 (($util->recoveryEnabledForUser() && $recoveryPassword) + + || !$this->userHasKeys($user) + || !$util->userHasFiles($user) + ) { + + // backup old keys + $this->backupAllKeys('recovery'); + + $newUserPassword = $params['password']; + + $keypair = $this->crypt->createKeyPair(); + + // Disable encryption proxy to prevent recursive calls + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; + + // Save public key + $this->setPublicKey($user, $keypair['publicKey']); + + // Encrypt private key with new password + $encryptedKey = $this->crypt->symmetricEncryptFileContent($keypair['privateKey'], + $newUserPassword); + + if ($encryptedKey) { + $this->setPrivateKey($user, $encryptedKey); + + if ($recoveryPassword) { // if recovery key is set we can re-encrypt the key files + $util->recoverUsersFiles($recoveryPassword); + } + } else { + $this->log->error('Encryption Could not update users encryption password'); + } + + \OC_FileProxy::$enabled = $proxyStatus; + } + } + } } /** @@ -136,82 +332,70 @@ class KeyManager { } /** - * @param $password - * @return bool + * @param $userId + * @return mixed + * @throws PublicKeyMissingException */ - public function checkRecoveryPassword($password) { - $recoveryKey = $this->keyStorage->getSystemUserKey($this->recoveryKeyId); - $decryptedRecoveryKey = $this->crypt->decryptPrivateKey($recoveryKey, $password); + public function getPublicKey($userId) { + $publicKey = $this->keyStorage->getUserKey($userId, $this->publicKeyId); - if ($decryptedRecoveryKey) { - return true; + if (strlen($publicKey) !== 0) { + return $publicKey; } - return false; + throw new PublicKeyMissingException(); } /** - * @param $userId - * @param $key - * @return bool + * @param $purpose + * @param bool $timestamp + * @param bool $includeUserKeys */ - public function setPublicKey($userId, $key) { - return $this->keyStorage->setUserKey($userId, $this->publicKeyId, $key); + public function backupAllKeys($purpose, $timestamp = true, $includeUserKeys = true) { +// $backupDir = $this->keyStorage->; } /** - * @param $userId - * @param $key - * @return bool + * @param string $uid */ - public function setPrivateKey($userId, $key) { - return $this->keyStorage->setUserKey($userId, $this->privateKeyId, $key); + public function replaceUserKeys($uid) { + $this->backupAllKeys('password_reset'); + $this->deletePublicKey($uid); + $this->deletePrivateKey($uid); } - /** - * @param $password - * @param $keyPair + * @param $uid * @return bool */ - public function storeKeyPair($password, $keyPair) { - // Save Public Key - $this->setPublicKey($this->keyId, $keyPair['publicKey']); - - $encryptedKey = $this->crypt->symmetricEncryptFileContent($keyPair['privateKey'], $password); - - if ($encryptedKey) { - $this->setPrivateKey($this->keyId, $encryptedKey); - $this->config->setAppValue('encryption', 'recoveryAdminEnabled', 1); - return true; - } - return false; + public function deletePublicKey($uid) { + return $this->keyStorage->deleteUserKey($uid, $this->publicKeyId); } /** + * @param $uid * @return bool */ - public function ready() { - return $this->keyStorage->ready(); + private function deletePrivateKey($uid) { + return $this->keyStorage->deleteUserKey($uid, $this->privateKeyId); } - /** - * @return \OCP\ICache - * @throws PrivateKeyMissingException + * @param array $userIds + * @return array + * @throws PublicKeyMissingException */ - public function init() { - try { - $privateKey = $this->getPrivateKey($this->keyId); - } catch (PrivateKeyMissingException $e) { - return false; - } + public function getPublicKeys(array $userIds) { + $keys = []; - $cache = \OC::$server->getMemCacheFactory(); + foreach ($userIds as $userId) { + try { + $keys[$userId] = $this->getPublicKey($userId); + } catch (PublicKeyMissingException $e) { + continue; + } + } - $cacheInstance = $cache->create('Encryption'); - $cacheInstance->set('privateKey', $privateKey); + return $keys; - return $cacheInstance; } - } |