/lib/core/Services/Encryption/Controller.php

https://gitlab.com/ElvisAns/tiki · PHP · 191 lines · 158 code · 23 blank · 10 comment · 20 complexity · f18fa920b2bb45aedd04b4e64cef5159 MD5 · raw file

  1. <?php
  2. // (c) Copyright by authors of the Tiki Wiki CMS Groupware Project
  3. //
  4. // All Rights Reserved. See copyright.txt for details and a complete list of authors.
  5. // Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details.
  6. // $Id$
  7. use TQ\Shamir\Secret;
  8. class Services_Encryption_Controller
  9. {
  10. private $encryptionlib;
  11. public function setUp()
  12. {
  13. $this->encryptionlib = TikiLib::lib('encryption');
  14. }
  15. /**
  16. * Returns the section for use with certain features like banning
  17. * @return string
  18. */
  19. public function getSection()
  20. {
  21. return 'security';
  22. }
  23. public function action_save_key($input)
  24. {
  25. global $user, $prefs;
  26. $keyId = $input->keyId->int();
  27. $users = TikiLib::lib('user')->extract_users($input->users->text(), $prefs['user_show_realnames'] == 'y');
  28. $key = null;
  29. if (empty($keyId)) {
  30. $data = [
  31. 'name' => $input->name->text(),
  32. 'description' => $input->description->text(),
  33. 'algo' => $input->algo->text(),
  34. 'shares' => $input->shares->int(),
  35. 'users' => TikiLib::lib('tiki')->str_putcsv($users),
  36. ];
  37. if ($users) {
  38. $data['shares'] = count($users);
  39. }
  40. $key = TikiLib::lib('crypt')->generateKey($data['algo']);
  41. $shares = $this->share($key, $data);
  42. } else {
  43. $data = [
  44. 'name' => $input->name->text(),
  45. 'description' => $input->description->text(),
  46. ];
  47. if ($input->regenerate->int()) {
  48. $data['algo'] = $input->algo->text();
  49. $data['shares'] = $input->shares->int();
  50. $data['users'] = TikiLib::lib('tiki')->str_putcsv($users);
  51. if ($users) {
  52. $data['shares'] = count($users);
  53. }
  54. $key = $this->action_decrypt_key(new JitFilter(['keyId' => $keyId, 'existing' => $input->old_share->text()]));
  55. $shares = $this->share($key, $data);
  56. } else {
  57. $shares = null;
  58. }
  59. }
  60. $keyId = $this->encryptionlib->set_key($keyId, $data);
  61. foreach ($users as $i => $auser) {
  62. if ($auser == $user) {
  63. try {
  64. TikiLib::lib('crypt')->init();
  65. TikiLib::lib('crypt')->setUserData('sk', $shares[$i], $keyId);
  66. } catch (Exception $e) {
  67. TikiLib::lib('tiki')->set_user_preference($auser, 'pe.sk.' . $keyId, $shares[$i]);
  68. }
  69. } else {
  70. TikiLib::lib('tiki')->set_user_preference($auser, 'pe.sk.' . $keyId, $shares[$i]);
  71. }
  72. }
  73. return [
  74. 'keyId' => $keyId,
  75. 'shares' => $shares,
  76. 'key' => $key,
  77. ];
  78. }
  79. public function action_get_key($input)
  80. {
  81. global $prefs;
  82. $keyId = $input->keyId->int();
  83. $encryption_key = $this->encryptionlib->get_key($keyId);
  84. $encryption_key['users_array'] = TikiLib::lib('user')->extract_users($encryption_key['users'], $prefs['user_show_realnames'] == 'y');
  85. return [
  86. 'key' => $encryption_key,
  87. ];
  88. }
  89. public function action_get_keys()
  90. {
  91. $encryption_keys = $this->encryptionlib->get_keys();
  92. return $encryption_keys;
  93. }
  94. public function action_delete_key($input)
  95. {
  96. return $this->encryptionlib->delete_key($input->keyId->int());
  97. }
  98. public function action_get_share_for_key($input)
  99. {
  100. $crypt = TikiLib::lib('crypt');
  101. try {
  102. $crypt->init();
  103. } catch (Exception $e) {
  104. // anonymous users don't have encryption data and thus - no shared key for them
  105. return null;
  106. }
  107. try {
  108. $share = $crypt->getUserData('sk.' . $input->keyId->int());
  109. } catch (Exception $e) {
  110. throw new Services_Exception_Denied($e->getMessage());
  111. }
  112. return $share;
  113. }
  114. public function action_decrypt_key($input)
  115. {
  116. $encryption_key = $this->encryptionlib->get_key($input->keyId->int());
  117. if (empty($encryption_key)) {
  118. throw new Services_Exception_NotFound(tr("Key not found."));
  119. }
  120. $existing = $input->existing->text();
  121. if (! $existing) {
  122. $existing = $this->action_get_share_for_key(new JitFilter(['keyId' => $encryption_key['keyId']]));
  123. }
  124. if (! $existing) {
  125. $existing = @$_SESSION['encryption_shared_keys'][$encryption_key['keyId']];
  126. }
  127. if (empty($existing)) {
  128. throw new Services_Exception_Denied(tr('Shared key not found for your user.'));
  129. }
  130. try {
  131. $key = Secret::recover([$encryption_key['secret'], $existing]);
  132. } catch (RuntimeException $e) {
  133. throw new Services_Exception_Denied($e->getMessage());
  134. }
  135. return $key;
  136. }
  137. public function action_get_encrypted_fields()
  138. {
  139. return $this->encryptionlib->get_encrypted_fields();
  140. }
  141. public function action_enter_key($input)
  142. {
  143. $encryption_key = $this->encryptionlib->get_key($input->keyId->int());
  144. if (empty($encryption_key)) {
  145. throw new Services_Exception_NotFound(tr("Key not found."));
  146. }
  147. if ($_SERVER['REQUEST_METHOD'] == 'POST') {
  148. $shared_key = $input->shared_key->text();
  149. if (! empty($shared_key)) {
  150. $_SESSION['encryption_shared_keys'][$encryption_key['keyId']] = $shared_key;
  151. }
  152. }
  153. return [
  154. 'title' => tr('Enter key'),
  155. 'encryption_key' => $encryption_key,
  156. 'shared_key' => @$_SESSION['encryption_shared_keys'][$encryption_key['keyId']],
  157. ];
  158. }
  159. private function share($key, &$data)
  160. {
  161. if ($data['shares'] + 1 < 2) {
  162. throw new Services_Exception_Denied(tr('Key must be shared with minimum of one user.'));
  163. }
  164. $shares = Secret::share($key, $data['shares'] + 1, 2);
  165. $data['secret'] = $shares[0];
  166. return array_slice($shares, 1, count($shares) - 1);
  167. }
  168. }