Proyectos de Subversion Moodle

Rev

Rev 1 | Mostrar el archivo completo | | | Autoría | Ultima modificación | Ver Log |

Rev 1 Rev 1441
Línea 22... Línea 22...
22
 * @package core
22
 * @package core
23
 * @copyright 2020 The Open University
23
 * @copyright 2020 The Open University
24
 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24
 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25
 */
25
 */
26
class encryption {
26
class encryption {
-
 
27
 
27
    /** @var string Encryption method: Sodium */
28
    /** @var string Encryption method: Sodium */
28
    const METHOD_SODIUM = 'sodium';
29
    const METHOD_SODIUM = 'sodium';
Línea 29... Línea 30...
29
 
30
 
30
    /**
-
 
31
     * @var string Encryption method: hand-coded OpenSSL (less safe)
-
 
32
     *
-
 
33
     * @deprecated
-
 
34
     */
-
 
35
    const METHOD_OPENSSL = 'openssl-aes-256-ctr';
-
 
36
 
-
 
37
    /**
-
 
38
     * @var string OpenSSL cipher method
-
 
39
     *
-
 
40
     * @deprecated
-
 
41
     */
-
 
42
    const OPENSSL_CIPHER = 'AES-256-CTR';
-
 
43
 
-
 
44
    /**
-
 
45
     * Checks if Sodium is installed.
-
 
46
     *
-
 
47
     * @return bool True if the Sodium extension is available
-
 
48
     *
31
    /**
49
     * @deprecated since Moodle 4.3 Sodium is always present
32
     * @deprecated since Moodle 4.3 Sodium is always present
-
 
33
     */
50
     */
34
    #[\core\attribute\deprecated(null, reason: 'Sodium is always present', since: '4.3', mdl: 'MDL-71421', final: true)]
51
    public static function is_sodium_installed(): bool {
35
    public static function is_sodium_installed() {
52
        debugging(__FUNCTION__ . '() is deprecated, sodium is now always present', DEBUG_DEVELOPER);
-
 
53
        return extension_loaded('sodium');
36
        \core\deprecation::emit_deprecation([self::class, __FUNCTION__]);
Línea 54... Línea 37...
54
    }
37
    }
55
 
38
 
56
    /**
39
    /**
Línea 63... Línea 46...
63
    }
46
    }
Línea 64... Línea 47...
64
 
47
 
65
    /**
48
    /**
66
     * Creates a key for the server.
49
     * Creates a key for the server.
67
     *
-
 
68
     * Note we currently retain support for all methods, in order to decrypt legacy {@see METHOD_OPENSSL} content
-
 
69
     *
50
     *
70
     * @param string|null $method Encryption method (only if you want to create a non-default key)
51
     * @param string|null $method Encryption method (only if you want to create a non-default key)
71
     * @param bool $chmod If true, restricts the file access of the key
52
     * @param bool $chmod If true, restricts the file access of the key
72
     * @throws \moodle_exception If the server already has a key, or there is an error
53
     * @throws \moodle_exception If the server already has a key, or there is an error
73
     */
54
     */
Línea 78... Línea 59...
78
 
59
 
79
        if (self::key_exists($method)) {
60
        if (self::key_exists($method)) {
80
            throw new \moodle_exception('encryption_keyalreadyexists', 'error');
61
            throw new \moodle_exception('encryption_keyalreadyexists', 'error');
Línea 81... Línea 62...
81
        }
62
        }
82
 
63
 
83
        // Don't make it read-only in Behat or it will fail to clear for future runs.
64
        // Don't make it read-only in tests or it will fail to clear for future runs.
84
        if (defined('BEHAT_SITE_RUNNING')) {
65
        if (defined('BEHAT_SITE_RUNNING') || PHPUNIT_TEST) {
Línea 85... Línea 66...
85
            $chmod = false;
66
            $chmod = false;
86
        }
67
        }
87
 
68
 
88
        // Generate the key.
69
        // Generate the key.
89
        switch ($method) {
70
        switch ($method) {
90
            case self::METHOD_SODIUM:
-
 
91
                $key = sodium_crypto_secretbox_keygen();
-
 
92
                break;
-
 
93
            case self::METHOD_OPENSSL:
71
            case self::METHOD_SODIUM:
94
                $key = openssl_random_pseudo_bytes(32);
72
                $key = sodium_crypto_secretbox_keygen();
95
                break;
73
                break;
Línea 96... Línea 74...
96
            default:
74
            default:
Línea 172... Línea 150...
172
    }
150
    }
Línea 173... Línea 151...
173
 
151
 
174
    /**
152
    /**
175
     * Gets the length in bytes of the initial values data required.
153
     * Gets the length in bytes of the initial values data required.
176
     *
-
 
177
     * Note we currently retain support for all methods, in order to decrypt legacy {@see METHOD_OPENSSL} content
-
 
178
     *
154
     *
179
     * @param string $method Crypto method
155
     * @param string $method Crypto method
180
     * @return int Length in bytes
156
     * @return int Length in bytes
181
     */
157
     */
182
    protected static function get_iv_length(string $method): int {
158
    protected static function get_iv_length(string $method): int {
183
        switch ($method) {
159
        switch ($method) {
184
            case self::METHOD_SODIUM:
160
            case self::METHOD_SODIUM:
185
                return SODIUM_CRYPTO_SECRETBOX_NONCEBYTES;
-
 
186
            case self::METHOD_OPENSSL:
-
 
187
                return openssl_cipher_iv_length(self::OPENSSL_CIPHER);
161
                return SODIUM_CRYPTO_SECRETBOX_NONCEBYTES;
188
            default:
162
            default:
189
                throw new \coding_exception('Unknown method: ' . $method);
163
                throw new \coding_exception('Unknown method: ' . $method);
190
        }
164
        }
Línea 206... Línea 180...
206
        } else {
180
        } else {
207
            if ($method === null) {
181
            if ($method === null) {
208
                $method = self::get_encryption_method();
182
                $method = self::get_encryption_method();
209
            }
183
            }
Línea 210... Línea -...
210
 
-
 
211
            // We currently retain support for all methods, falling back to Sodium if deprecated OpenSSL is requested.
-
 
212
            if ($method === self::METHOD_OPENSSL) {
-
 
213
                debugging('Encryption using legacy OpenSSL is deprecated, reverting to Sodium', DEBUG_DEVELOPER);
-
 
214
                $method = self::METHOD_SODIUM;
-
 
215
            }
-
 
216
 
184
 
217
            // Create IV.
185
            // Create IV.
Línea 218... Línea 186...
218
            $iv = random_bytes(self::get_iv_length($method));
186
            $iv = random_bytes(self::get_iv_length($method));
219
 
187
 
Línea 237... Línea 205...
237
    }
205
    }
Línea 238... Línea 206...
238
 
206
 
239
    /**
207
    /**
240
     * Decrypts data using the server's key. The decryption works with either supported method.
208
     * Decrypts data using the server's key. The decryption works with either supported method.
241
     *
-
 
242
     * Note currently we retain support for all methods, in order to decrypt legacy {@see METHOD_OPENSSL} content
-
 
243
     *
209
     *
244
     * @param string $data Data to decrypt
210
     * @param string $data Data to decrypt
245
     * @return string Decrypted data
211
     * @return string Decrypted data
246
     */
212
     */
247
    public static function decrypt(string $data): string {
213
    public static function decrypt(string $data): string {
248
        if ($data === '') {
214
        if ($data === '') {
249
            return '';
215
            return '';
250
        } else {
216
        } else {
251
            if (preg_match('~^(' . self::METHOD_OPENSSL . '|' . self::METHOD_SODIUM . '):~', $data, $matches)) {
217
            if (preg_match('~^(' . self::METHOD_SODIUM . '):~', $data, $matches)) {
252
                $method = $matches[1];
218
                $method = $matches[1];
253
            } else {
219
            } else {
254
                throw new \moodle_exception('encryption_wrongmethod', 'error');
220
                throw new \moodle_exception('encryption_wrongmethod', 'error');
255
            }
221
            }
Línea 279... Línea 245...
279
                    if ($decrypted === false) {
245
                    if ($decrypted === false) {
280
                        throw new \moodle_exception('encryption_decryptfailed', 'error',
246
                        throw new \moodle_exception('encryption_decryptfailed', 'error',
281
                                '', null, 'Integrity check failed');
247
                                '', null, 'Integrity check failed');
282
                    }
248
                    }
283
                    break;
249
                    break;
284
 
-
 
285
                case self::METHOD_OPENSSL:
-
 
286
                    if (strlen($encrypted) < 33) {
-
 
287
                        throw new \moodle_exception('encryption_decryptfailed', 'error',
-
 
288
                                '', null, 'Insufficient data');
-
 
289
                    }
-
 
290
                    $hmac = substr($encrypted, -32);
-
 
291
                    $encrypted = substr($encrypted, 0, -32);
-
 
292
                    $key = self::get_key($method);
-
 
293
                    $expectedhmac = hash_hmac('sha256', $iv . $encrypted, $key, true);
-
 
294
                    if ($hmac !== $expectedhmac) {
-
 
295
                        throw new \moodle_exception('encryption_decryptfailed', 'error',
-
 
296
                                '', null, 'Integrity check failed');
-
 
297
                    }
-
 
298
 
-
 
299
                    debugging('Decryption using legacy OpenSSL is deprecated, please upgrade to Sodium', DEBUG_DEVELOPER);
-
 
300
 
-
 
301
                    $decrypted = @openssl_decrypt($encrypted, self::OPENSSL_CIPHER, $key, OPENSSL_RAW_DATA, $iv);
-
 
302
                    if ($decrypted === false) {
-
 
303
                        throw new \moodle_exception('encryption_decryptfailed', 'error',
-
 
304
                                '', null, openssl_error_string());
-
 
305
                    }
-
 
306
                    break;
-
 
307
 
-
 
308
                default:
250
                default:
309
                    throw new \coding_exception('Unknown method: ' . $method);
251
                    throw new \coding_exception('Unknown method: ' . $method);
310
            }
252
            }
Línea 311... Línea 253...
311
 
253