forked from eventum/eventum
-
Notifications
You must be signed in to change notification settings - Fork 0
/
CryptoUpgradeManager.php
197 lines (169 loc) · 5.64 KB
/
CryptoUpgradeManager.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
<?php
/*
* This file is part of the Eventum (Issue Tracking System) package.
*
* @copyright (c) Eventum Team
* @license GNU General Public License, version 2 or later (GPL-2+)
*
* For the full copyright and license information,
* please see the COPYING and AUTHORS files
* that were distributed with this source code.
*/
namespace Eventum\Crypto;
use Email_Account;
use Setup;
use Workflow;
use Zend\Config\Config;
class CryptoUpgradeManager
{
/** @var Config */
private $config;
public function __construct()
{
$this->config = Setup::get();
}
/**
* Perform few checks that enable/disable can be performed
*
* @param bool $enable TRUE if action is to enable, FALSE if action is to disable
* @throws CryptoException
*/
private function canPerform($enable)
{
$enabled = CryptoManager::encryptionEnabled();
if (($enabled && $enable) || (!$enabled && !$enable)) {
$state = $enabled ? 'enabled' : 'disabled';
throw new CryptoException("Can not perform, already $state");
}
CryptoManager::canEncrypt();
// test that config can be saved before doing anything
$res = Setup::save();
if ($res !== 1) {
throw new CryptoException('Can not save config');
}
// test that key file can be updated
$km = new CryptoKeyManager();
$km->canUpdate();
}
/**
* Enable encryption
*
* @throws CryptoException if that can not be performed
*/
public function enable()
{
$this->canPerform(true);
$this->config['encryption'] = 'enabled';
if (!CryptoManager::encryptionEnabled()) {
throw new CryptoException('bug');
}
$this->upgradeConfig();
$this->upgradeEmailAccounts();
Setup::save();
}
/**
* Disable encryption
*/
public function disable()
{
$this->canPerform(false);
$this->downgradeConfig();
$this->downgradeEmailAccounts();
$this->config['encryption'] = 'disabled';
if (CryptoManager::encryptionEnabled()) {
throw new CryptoException('bug');
}
Setup::save();
}
/**
* Generate new encryption key and re-encrypt data
*/
public function regenerateKey()
{
if (!CryptoManager::encryptionEnabled()) {
throw new CryptoException('Encryption not enabled');
}
$this->disable();
$km = new CryptoKeyManager();
$km->regen();
$this->enable();
}
/**
* Upgrade config so that values contain EncryptedValue where some secrecy is wanted
*/
private function upgradeConfig()
{
if (!$this->config['database']['password'] instanceof EncryptedValue) {
$this->config['database']['password'] = new EncryptedValue(
CryptoManager::encrypt($this->config['database']['password'])
);
}
if (count($this->config['ldap']) && !$this->config['ldap']['bindpw'] instanceof EncryptedValue) {
$this->config['ldap']['bindpw'] = new EncryptedValue(
CryptoManager::encrypt($this->config['ldap']['bindpw'])
);
}
Workflow::cryptoUpgradeConfig();
}
/**
* Downgrade config: remove all EncryptedValue elements
*/
private function downgradeConfig()
{
if ($this->config['database']['password'] instanceof EncryptedValue) {
/** @var EncryptedValue $value */
$value = $this->config['database']['password'];
$this->config['database']['password'] = $value->getValue();
}
if (count($this->config['ldap']) && $this->config['ldap']['bindpw'] instanceof EncryptedValue) {
/** @var EncryptedValue $value */
$value = $this->config['ldap']['bindpw'];
$this->config['ldap']['bindpw'] = $value->getValue();
}
Workflow::cryptoDowngradeConfig();
}
private function upgradeEmailAccounts()
{
// encrypt email account passwords
$accounts = Email_Account::getList();
foreach ($accounts as $account) {
$account = Email_Account::getDetails($account['ema_id'], true);
/** @var EncryptedValue $password */
$password = $account['ema_password'];
// the raw value contains the original plaintext
Email_Account::updatePassword($account['ema_id'], $password->getEncrypted());
}
}
private function downgradeEmailAccounts()
{
$accounts = Email_Account::getList();
// collect passwords when encryption enabled
$passwords = [];
$this->config['encryption'] = 'enabled';
foreach ($accounts as $account) {
$account = Email_Account::getDetails($account['ema_id'], true);
/** @var EncryptedValue $password */
$password = $account['ema_password'];
$passwords[$account['ema_id']] = $password->getValue();
}
// save passwords when encryption disabled
$this->config['encryption'] = 'disabled';
foreach ($passwords as $ema_id => $password) {
Email_Account::updatePassword($ema_id, $password);
}
}
/**
* Key rotation method -- decrypt with your old key then re-encrypt with your new key
*
* @param string $ciphertext
* @param string $key the new key
* @return string
*/
public function rotate($ciphertext, $key)
{
if (!CryptoManager::encryptionEnabled()) {
return $ciphertext;
}
return CryptoManager::encrypt(CryptoManager::decrypt($ciphertext), $key);
}
}