diff options
author | Maurício Meneghini Fauth <mauricio@fauth.dev> | 2021-10-16 20:23:02 +0300 |
---|---|---|
committer | Maurício Meneghini Fauth <mauricio@fauth.dev> | 2022-01-10 18:19:42 +0300 |
commit | 3c11d62b31acdc994ae426999b5cf639cbdd32c9 (patch) | |
tree | a4364ee4db80ea7a5baaafc99fcc13b630f7ea22 /libraries | |
parent | 28ad63c96916ac1f81b7266faab65d3e7c9205ef (diff) |
Add support for Sodium encryption
Signed-off-by: Maurício Meneghini Fauth <mauricio@fauth.dev>
Diffstat (limited to 'libraries')
-rw-r--r-- | libraries/classes/Crypto/Crypto.php | 95 | ||||
-rw-r--r-- | libraries/classes/Url.php | 8 | ||||
-rw-r--r-- | libraries/config.default.php | 7 |
3 files changed, 96 insertions, 14 deletions
diff --git a/libraries/classes/Crypto/Crypto.php b/libraries/classes/Crypto/Crypto.php index 128598639d..5f12fbdcae 100644 --- a/libraries/classes/Crypto/Crypto.php +++ b/libraries/classes/Crypto/Crypto.php @@ -7,14 +7,34 @@ use phpseclib\Crypt\Random; final class Crypto { + /** @var bool */ + private $hasRandomBytesSupport; + + /** @var bool */ + private $hasSodiumSupport; + + public function __construct() + { + $this->hasRandomBytesSupport = is_callable('random_bytes'); + $this->hasSodiumSupport = $this->hasRandomBytesSupport + && is_callable('sodium_crypto_secretbox') + && is_callable('sodium_crypto_secretbox_open') + && defined('SODIUM_CRYPTO_SECRETBOX_NONCEBYTES') + && defined('SODIUM_CRYPTO_SECRETBOX_KEYBYTES'); + } + /** * @param string $plaintext * * @return string */ - public static function encrypt($plaintext) + public function encrypt($plaintext) { - return self::encryptWithPhpseclib($plaintext); + if ($this->hasSodiumSupport) { + return $this->encryptWithSodium($plaintext); + } + + return $this->encryptWithPhpseclib($plaintext); } /** @@ -22,9 +42,38 @@ final class Crypto * * @return string */ - public static function decrypt($ciphertext) + public function decrypt($ciphertext) { - return self::decryptWithPhpseclib($ciphertext); + if ($this->hasSodiumSupport) { + return $this->decryptWithSodium($ciphertext); + } + + return $this->decryptWithPhpseclib($ciphertext); + } + + /** + * @return string + */ + private function getEncryptionKey() + { + global $PMA_Config; + + $keyLength = $this->hasSodiumSupport ? SODIUM_CRYPTO_SECRETBOX_KEYBYTES : 32; + + $key = $PMA_Config->get('URLQueryEncryptionSecretKey'); + if (is_string($key) && mb_strlen($key, '8bit') === $keyLength) { + return $key; + } + + $key = isset($_SESSION['URLQueryEncryptionSecretKey']) ? $_SESSION['URLQueryEncryptionSecretKey'] : null; + if (is_string($key) && mb_strlen($key, '8bit') === $keyLength) { + return $key; + } + + $key = $this->hasRandomBytesSupport ? random_bytes($keyLength) : Random::string($keyLength); + $_SESSION['URLQueryEncryptionSecretKey'] = $key; + + return $key; } /** @@ -32,11 +81,11 @@ final class Crypto * * @return string */ - private static function encryptWithPhpseclib($plaintext) + private function encryptWithPhpseclib($plaintext) { - $key = self::getEncryptionKey(); + $key = $this->getEncryptionKey(); $cipher = new AES(AES::MODE_CBC); - $iv = Random::string(16); + $iv = $this->hasRandomBytesSupport ? random_bytes(16) : Random::string(16); $cipher->setIV($iv); $cipher->setKey($key); $ciphertext = $cipher->encrypt($plaintext); @@ -50,9 +99,9 @@ final class Crypto * * @return string|null */ - private static function decryptWithPhpseclib($encrypted) + private function decryptWithPhpseclib($encrypted) { - $key = self::getEncryptionKey(); + $key = $this->getEncryptionKey(); $hmac = mb_substr($encrypted, 0, 32, '8bit'); $iv = mb_substr($encrypted, 32, 16, '8bit'); $ciphertext = mb_substr($encrypted, 48, null, '8bit'); @@ -69,12 +118,34 @@ final class Crypto } /** + * @param string $plaintext + * * @return string */ - private static function getEncryptionKey() + private function encryptWithSodium($plaintext) { - global $PMA_Config; + $key = $this->getEncryptionKey(); + $nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES); + $ciphertext = sodium_crypto_secretbox($plaintext, $nonce, $key); + + return $nonce . $ciphertext; + } + + /** + * @param string $encrypted + * + * @return string|null + */ + private function decryptWithSodium($encrypted) + { + $key = $this->getEncryptionKey(); + $nonce = mb_substr($encrypted, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, '8bit'); + $ciphertext = mb_substr($encrypted, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, null, '8bit'); + $decrypted = sodium_crypto_secretbox_open($ciphertext, $nonce, $key); + if ($decrypted === false) { + return null; + } - return $_SESSION[' HMAC_secret '] . $PMA_Config->get('blowfish_secret'); + return $decrypted; } } diff --git a/libraries/classes/Url.php b/libraries/classes/Url.php index c5c411df0b..b5594b38ed 100644 --- a/libraries/classes/Url.php +++ b/libraries/classes/Url.php @@ -240,7 +240,9 @@ class Url */ public static function encryptQuery($query) { - return strtr(base64_encode(Crypto::encrypt($query)), '+/', '-_'); + $crypto = new Crypto(); + + return strtr(base64_encode($crypto->encrypt($query)), '+/', '-_'); } /** @@ -249,7 +251,9 @@ class Url */ public static function decryptQuery($query) { - return Crypto::decrypt(base64_decode(strtr($query, '-_', '+/'))); + $crypto = new Crypto(); + + return $crypto->decrypt(base64_decode(strtr($query, '-_', '+/'))); } /** diff --git a/libraries/config.default.php b/libraries/config.default.php index fdd7c13639..b81981ba45 100644 --- a/libraries/config.default.php +++ b/libraries/config.default.php @@ -825,6 +825,13 @@ $cfg['IgnoreMultiSubmitErrors'] = false; $cfg['URLQueryEncryption'] = true; /** + * A secret key used to encrypt/decrypt the URL query string. Should be 32 bytes long. + * + * @global string $cfg['URLQueryEncryptionSecretKey'] + */ +$cfg['URLQueryEncryptionSecretKey'] = ''; + +/** * allow login to any user entered server in cookie based authentication * * @global boolean $cfg['AllowArbitraryServer'] |