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
|
<?php
namespace WPForms\Helpers;
// WP 5.2+ already load Sodium Compat polyfill for libsodium-fallback. // We need to do the same for under 5.2 versions (4.9-5.1). if ( ! version_compare( get_bloginfo( 'version' ), '5.2', '>=' ) && ! function_exists( 'sodium_crypto_box' ) ) { require_once WPFORMS_PLUGIN_DIR . 'libs/sodium_compat/autoload.php'; }
/** * Class for encryption functionality. * * @since 1.6.1.2 * * @link https://www.php.net/manual/ru/intro.sodium.php */ class Crypto {
/** * Get a secret key for encrypt/decrypt. * * @since 1.6.1.2 * * @return string */ public static function get_secret_key() {
$secret_key = get_option( 'wpforms_crypto_secret_key' );
// If we already have the secret, send it back. if ( false !== $secret_key ) { return base64_decode( $secret_key ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode }
// We don't have a secret, so let's generate one. $secret_key = sodium_crypto_secretbox_keygen(); add_option( 'wpforms_crypto_secret_key', base64_encode( $secret_key ) ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
return $secret_key; }
/** * Encrypt a message. * * @since 1.6.1.2 * * @param string $message Message to encrypt. * @param string $key Encryption key. * * @return string */ public static function encrypt( $message, $key = '' ) {
// Create a nonce for this operation. It will be stored and recovered in the message itself. $nonce = random_bytes( SODIUM_CRYPTO_SECRETBOX_NONCEBYTES );
if ( empty( $key ) ) { $key = self::get_secret_key(); }
// Encrypt message and combine with nonce. $cipher = base64_encode( // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode $nonce . sodium_crypto_secretbox( $message, $nonce, $key ) );
try { sodium_memzero( $message ); sodium_memzero( $key ); } catch ( \Exception $e ) { return $cipher; }
return $cipher; }
/** * Decrypt a message. * * @since 1.6.1.2 * * @param string $encrypted Encrypted message. * @param string $key Encryption key. * * @return string */ public static function decrypt( $encrypted, $key = '' ) {
// Unpack base64 message. $decoded = base64_decode( $encrypted ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode
if ( false === $decoded ) { return false; }
if ( mb_strlen( $decoded, '8bit' ) < ( SODIUM_CRYPTO_SECRETBOX_NONCEBYTES + SODIUM_CRYPTO_SECRETBOX_MACBYTES ) ) { return false; }
// Pull nonce and ciphertext out of unpacked message. $nonce = mb_substr( $decoded, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, '8bit' ); $ciphertext = mb_substr( $decoded, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, null, '8bit' );
if ( empty( $key ) ) { $key = self::get_secret_key(); }
// Decrypt it. $message = sodium_crypto_secretbox_open( $ciphertext, $nonce, $key );
// Check for decrpytion failures. if ( false === $message ) { return false; }
try { sodium_memzero( $ciphertext ); sodium_memzero( $key ); } catch ( \Exception $e ) { return $message; }
return $message; } }
|