diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/ImapClient.php b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/ImapClient.php index 4db46dfe7..35674b06d 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/ImapClient.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/ImapClient.php @@ -110,9 +110,9 @@ class ImapClient extends \MailSo\Net\NetClient return $this; } - if (!empty($oSettings->ProxyAuthUser) && !empty($oSettings->ProxyAuthPassword)) { + if (!empty($oSettings->ProxyAuthUser) && $oSettings->ProxyAuthPassword) { $sLogin = $oSettings->ProxyAuthUser; - $sPassword = $oSettings->ProxyAuthPassword; + $sPassword = $oSettings->ProxyAuthPassword->getValue(); $sProxyAuthUser = $oSettings->Login; } else { $sLogin = $oSettings->Login; diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Log/Inherit.php b/snappymail/v/0.0.0/app/libraries/MailSo/Log/Inherit.php index 521a1b641..a82d0b2a0 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Log/Inherit.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Log/Inherit.php @@ -40,7 +40,10 @@ trait Inherit $this->oLogger && $this->oLogger->WriteException($oException, $iType, $sName); } - public function logMask(string $sWord): void + public function logMask( + #[\SensitiveParameter] + string $sWord + ): void { $this->oLogger && $this->oLogger->AddSecret($sWord); } diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Log/Logger.php b/snappymail/v/0.0.0/app/libraries/MailSo/Log/Logger.php index f447d1f72..f6aa4f608 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Log/Logger.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Log/Logger.php @@ -107,7 +107,10 @@ class Logger extends \SplFixedArray return 0 < $this->count(); } - public function AddSecret(string $sWord) : void + public function AddSecret( + #[\SensitiveParameter] + string $sWord + ) : void { // $this->bShowSecrets && $this->Write("AddSecret '{$sWord}'", \LOG_INFO, '', false); $sWord = \trim($sWord); diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Net/ConnectSettings.php b/snappymail/v/0.0.0/app/libraries/MailSo/Net/ConnectSettings.php index f37c3cca3..f706b99e3 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Net/ConnectSettings.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Net/ConnectSettings.php @@ -11,6 +11,8 @@ namespace MailSo\Net; +use SnappyMail\SensitiveString; + /** * @category MailSo * @package Net @@ -47,15 +49,29 @@ class ConnectSettings implements \JsonSerializable 'LOGIN' ]; public string $Login = ''; - public string $Password = ''; + private ?SensitiveString $Password = null; public string $ProxyAuthUser = ''; - public string $ProxyAuthPassword = ''; + public ?SensitiveString $ProxyAuthPassword = null; public function __construct() { $this->ssl = new SSLContext; } + public function __get(string $name) + { + if ('Password' === $name) { + return $this->Password ? $this->Password->getValue() : ''; + } + } + + public function __set(string $name, $value) + { + if ('Password' === $name) { + $this->Password = \is_string($value) ? new SensitiveString($value) : $value; + } + } + public static function Host() : string { return \SnappyMail\IDN::toAscii($this->host); diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/UserAuth.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/UserAuth.php index c6af9eb5e..4ebf93fc3 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/UserAuth.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/UserAuth.php @@ -22,7 +22,10 @@ trait UserAuth /** * @throws \RainLoop\Exceptions\ClientException */ - public function resolveLoginCredentials(string &$sEmail, string &$sPassword, string &$sLogin): void + public function resolveLoginCredentials(string &$sEmail, + #[\SensitiveParameter] + string &$sPassword, + string &$sLogin): void { $this->Plugins()->RunHook('login.credentials.step-1', array(&$sEmail)); @@ -113,7 +116,11 @@ trait UserAuth /** * @throws \RainLoop\Exceptions\ClientException */ - public function LoginProcess(string &$sEmail, string &$sPassword, bool $bMainAccount = true): Account + public function LoginProcess(string &$sEmail, + #[\SensitiveParameter] + string &$sPassword, + bool $bMainAccount = true + ): Account { $sInputEmail = $sEmail; diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Api.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Api.php index 16200a64e..5b8e8796b 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Api.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Api.php @@ -77,7 +77,11 @@ abstract class Api return APP_VERSION; } - public static function CreateUserSsoHash(string $sEmail, string $sPassword, array $aAdditionalOptions = array(), bool $bUseTimeout = true) : ?string + public static function CreateUserSsoHash(string $sEmail, + #[\SensitiveParameter] + string $sPassword, + array $aAdditionalOptions = array(), bool $bUseTimeout = true + ) : ?string { $sSsoHash = \MailSo\Base\Utils::Sha1Rand(\sha1($sPassword.$sEmail)); diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Config/Application.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Config/Application.php index 8f7bdf1a1..29773aec8 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Config/Application.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Config/Application.php @@ -116,12 +116,18 @@ class Application extends \RainLoop\Config\AbstractConfig parent::Set($sSectionKey, $sParamKey, $mParamValue); } - public function SetPassword(string $sPassword) : void + public function SetPassword( + #[\SensitiveParameter] + string $sPassword + ) : void { $this->Set('security', 'admin_password', \password_hash($sPassword, PASSWORD_DEFAULT)); } - public function ValidatePassword(string $sPassword) : bool + public function ValidatePassword( + #[\SensitiveParameter] + string $sPassword + ) : bool { $sConfigPassword = (string) $this->Get('security', 'admin_password', ''); if (32 == \strlen($sPassword) && \md5(APP_SALT.$sPassword.APP_SALT) === $sConfigPassword) { diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Model/Account.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Model/Account.php index 38b67814f..26b73bb16 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Model/Account.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Model/Account.php @@ -5,6 +5,7 @@ namespace RainLoop\Model; use RainLoop\Utils; use RainLoop\Notifications; use RainLoop\Exceptions\ClientException; +use SnappyMail\SensitiveString; abstract class Account implements \JsonSerializable { @@ -14,15 +15,15 @@ abstract class Account implements \JsonSerializable private string $sLogin = ''; - private string $sPassword = ''; + private ?SensitiveString $sPassword = null; private string $sSmtpLogin = ''; - private string $sSmtpPassword = ''; + private ?SensitiveString $sSmtpPassword = null; private string $sProxyAuthUser = ''; - private string $sProxyAuthPassword = ''; + private ?SensitiveString $sProxyAuthPassword = null; private Domain $oDomain; @@ -45,7 +46,7 @@ abstract class Account implements \JsonSerializable public function IncPassword() : string { - return $this->sPassword; + return $this->sPassword ? $this->sPassword->getValue() : ''; } public function OutLogin() : string @@ -69,14 +70,20 @@ abstract class Account implements \JsonSerializable ])); } - public function SetPassword(string $sPassword) : void + public function SetPassword( + #[\SensitiveParameter] + string $sPassword + ) : void { - $this->sPassword = $sPassword; + $this->sPassword = new SensitiveString($sPassword); } - public function SetSmtpPassword(string $sPassword) : void + public function SetSmtpPassword( + #[\SensitiveParameter] + string $sPassword + ) : void { - $this->sSmtpPassword = $sPassword; + $this->sSmtpPassword = new SensitiveString($sPassword); } public function SetProxyAuthUser(string $sProxyAuthUser) : void @@ -84,39 +91,43 @@ abstract class Account implements \JsonSerializable $this->sProxyAuthUser = $sProxyAuthUser; } - public function SetProxyAuthPassword(string $sProxyAuthPassword) : void + public function SetProxyAuthPassword( + #[\SensitiveParameter] + string $sProxyAuthPassword + ) : void { - $this->sProxyAuthPassword = $sProxyAuthPassword; + $this->sProxyAuthPassword = new SensitiveString($sProxyAuthPassword); } #[\ReturnTypeWillChange] public function jsonSerialize() { $result = [ -// 'account', // 0 - 'email' => $this->sEmail, // 1 - 'login' => $this->sLogin, // 2 - 'pass' => $this->sPassword, // 3 -// '', // 4 sClientCert + 'email' => $this->sEmail, + 'login' => $this->sLogin, + 'pass' => $this->IncPassword(), 'name' => $this->sName ]; if ($this->sSmtpLogin && $this->sSmtpPassword) { $result['smtp'] = [ 'user' => $this->sSmtpLogin, - 'pass' => $this->sSmtpPassword + 'pass' => $this->sSmtpPassword->getValue() ]; } if ($this->sProxyAuthUser && $this->sProxyAuthPassword) { $result['proxy'] = [ - 'user' => $this->sProxyAuthUser, // 5 - 'pass' => $this->sProxyAuthPassword // 6 + 'user' => $this->sProxyAuthUser, + 'pass' => $this->sProxyAuthPassword->getValue() ]; } return $result; } public static function NewInstanceFromCredentials(\RainLoop\Actions $oActions, - string $sEmail, string $sLogin, string $sPassword, bool $bThrowException = false): ?self + string $sEmail, string $sLogin, + #[\SensitiveParameter] + string $sPassword, + bool $bThrowException = false): ?self { $oAccount = null; if ($sEmail && $sLogin && $sPassword) { @@ -127,7 +138,7 @@ abstract class Account implements \JsonSerializable $oAccount->sEmail = \MailSo\Base\Utils::IdnToAscii($sEmail, true); $oAccount->sLogin = \MailSo\Base\Utils::IdnToAscii($sLogin); - $oAccount->sPassword = $sPassword; + $oAccount->SetPassword($sPassword); $oAccount->oDomain = $oDomain; $oActions->Plugins()->RunHook('filter.account', array($oAccount)); @@ -190,17 +201,17 @@ abstract class Account implements \JsonSerializable if (isset($aAccountHash['name'])) { $oAccount->sName = $aAccountHash['name']; } - $oActions->logMask($oAccount->sPassword); + $oActions->logMask($oAccount->IncPassword()); // init smtp user/password if (isset($aAccountHash['smtp'])) { $oAccount->sSmtpLogin = $aAccountHash['smtp']['user']; - $oAccount->sSmtpPassword = $aAccountHash['smtp']['pass']; + $oAccount->SetSmtpPassword($aAccountHash['smtp']['pass']); $oActions->logMask($oAccount->sSmtpPassword); } // init proxy user/password if (isset($aAccountHash['proxy'])) { $oAccount->sProxyAuthUser = $aAccountHash['proxy']['user']; - $oAccount->sProxyAuthPassword = $aAccountHash['proxy']['pass']; + $oAccount->SetProxyAuthPassword($aAccountHash['proxy']['pass']); $oActions->logMask($oAccount->sProxyAuthPassword); } } @@ -208,11 +219,6 @@ abstract class Account implements \JsonSerializable return $oAccount; } - // Deprecated - public function ImapConnectAndLoginHelper(\RainLoop\Plugins\Manager $oPlugins, \MailSo\Imap\ImapClient $oImapClient, \RainLoop\Config\Application $oConfig) : bool - { - return $this->ImapConnectAndLogin($oPlugins, $oImapClient, $oConfig); - } public function ImapConnectAndLogin(\RainLoop\Plugins\Manager $oPlugins, \MailSo\Imap\ImapClient $oImapClient, \RainLoop\Config\Application $oConfig) : bool { $oSettings = $this->Domain()->ImapSettings(); @@ -234,7 +240,7 @@ abstract class Account implements \JsonSerializable $oImapClient->Connect($oSettings); $oPlugins->RunHook('imap.after-connect', array($this, $oImapClient, $oSettings)); - $oSettings->Password = $this->IncPassword(); + $oSettings->Password = $this->sPassword; return $this->netClientLogin($oImapClient, $oPlugins); } @@ -273,7 +279,7 @@ abstract class Account implements \JsonSerializable $oSieveClient->Connect($oSettings); $oPlugins->RunHook('sieve.after-connect', array($this, $oSieveClient, $oSettings)); - $oSettings->Password = $this->IncPassword(); + $oSettings->Password = $this->sPassword; return $this->netClientLogin($oSieveClient, $oPlugins); } diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/CardDAV.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/CardDAV.php index 8c7becdcb..2833a9422 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/CardDAV.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/CardDAV.php @@ -130,7 +130,10 @@ trait CardDAV return null; } - private function getContactsPaths(DAVClient $oClient, string $sPath, string $sUser, string $sPassword, string $sProxy = '') : array + private function getContactsPaths(DAVClient $oClient, string $sPath, string $sUser, + #[\SensitiveParameter] + string $sPassword, + string $sProxy = '') : array { $aContactsPaths = array(); @@ -291,7 +294,11 @@ trait CardDAV return $bGood; } - private function getDavClientFromUrl(string $sUrl, string $sUser, string $sPassword, string $sProxy = '') : DAVClient + private function getDavClientFromUrl(string $sUrl, string $sUser, + #[\SensitiveParameter] + string $sPassword, + string $sProxy = '' + ) : DAVClient { if (!\preg_match('/^http[s]?:\/\//i', $sUrl)) { $sUrl = \preg_replace('/^fruux\.com/i', 'dav.fruux.com', $sUrl); diff --git a/snappymail/v/0.0.0/app/libraries/snappymail/crypt.php b/snappymail/v/0.0.0/app/libraries/snappymail/crypt.php index 8028bd251..c58905ee6 100644 --- a/snappymail/v/0.0.0/app/libraries/snappymail/crypt.php +++ b/snappymail/v/0.0.0/app/libraries/snappymail/crypt.php @@ -43,7 +43,10 @@ abstract class Crypt /** * When $key is empty, it will use the smctoken. */ - private static function Passphrase(?string $key) : string + private static function Passphrase( + #[\SensitiveParameter] + ?string $key + ) : string { if (!$key) { if (empty($_COOKIE['smctoken'])) { @@ -55,7 +58,10 @@ abstract class Crypt return \sha1($key . APP_SALT, true); } - public static function Decrypt(array $data, string $key = null) /* : mixed */ + public static function Decrypt(array $data, + #[\SensitiveParameter] + string $key = null + ) /* : mixed */ { if (3 === \count($data) && isset($data[0], $data[1], $data[2]) && \strlen($data[0])) { try { @@ -75,7 +81,10 @@ abstract class Crypt } } - public static function DecryptFromJSON(string $data, string $key = null) /* : mixed */ + public static function DecryptFromJSON(string $data, + #[\SensitiveParameter] + string $key = null + ) /* : mixed */ { $data = static::jsonDecode($data); if (!\is_array($data)) { @@ -85,7 +94,10 @@ abstract class Crypt return static::Decrypt(\array_map('base64_decode', $data), $key); } - public static function DecryptUrlSafe(string $data, string $key = null) /* : mixed */ + public static function DecryptUrlSafe(string $data, + #[\SensitiveParameter] + string $key = null + ) /* : mixed */ { $data = \explode('.', $data); if (!\is_array($data)) { @@ -95,7 +107,12 @@ abstract class Crypt return static::Decrypt(\array_map('MailSo\\Base\\Utils::UrlSafeBase64Decode', $data), $key); } - public static function Encrypt($data, string $key = null) : array + public static function Encrypt( + #[\SensitiveParameter] + $data, + #[\SensitiveParameter] + string $key = null + ) : array { $data = \json_encode($data); @@ -128,17 +145,30 @@ abstract class Crypt */ } - public static function EncryptToJSON($data, string $key = null) : string + public static function EncryptToJSON( + #[\SensitiveParameter] + $data, + #[\SensitiveParameter] + string $key = null + ) : string { return \json_encode(\array_map('base64_encode', static::Encrypt($data, $key))); } - public static function EncryptUrlSafe($data, string $key = null) : string + public static function EncryptUrlSafe( + #[\SensitiveParameter] + $data, + #[\SensitiveParameter] + string $key = null + ) : string { return \implode('.', \array_map('MailSo\\Base\\Utils::UrlSafeBase64Encode', static::Encrypt($data, $key))); } - public static function SodiumDecrypt(string $data, string $nonce, string $key = null) /* : string|false */ + public static function SodiumDecrypt(string $data, string $nonce, + #[\SensitiveParameter] + string $key = null + ) /* : string|false */ { if (!\is_callable('sodium_crypto_aead_xchacha20poly1305_ietf_decrypt')) { throw new \Exception('sodium_crypto_aead_xchacha20poly1305_ietf_decrypt not callable'); @@ -151,7 +181,13 @@ abstract class Crypt ); } - public static function SodiumEncrypt(string $data, string $nonce, string $key = null) : string + public static function SodiumEncrypt( + #[\SensitiveParameter] + string $data, + string $nonce, + #[\SensitiveParameter] + string $key = null + ) : string { if (!\is_callable('sodium_crypto_aead_xchacha20poly1305_ietf_encrypt')) { throw new \Exception('sodium_crypto_aead_xchacha20poly1305_ietf_encrypt not callable'); @@ -168,7 +204,10 @@ abstract class Crypt return $result; } - public static function OpenSSLDecrypt(string $data, string $iv, string $key = null) /* : string|false */ + public static function OpenSSLDecrypt(string $data, string $iv, + #[\SensitiveParameter] + string $key = null + ) /* : string|false */ { if (!$data || !$iv) { throw new \InvalidArgumentException('$data or $iv is empty string'); @@ -189,7 +228,13 @@ abstract class Crypt ); } - public static function OpenSSLEncrypt(string $data, string $iv, string $key = null) : string + public static function OpenSSLEncrypt( + #[\SensitiveParameter] + string $data, + string $iv, + #[\SensitiveParameter] + string $key = null + ) : string { if (!$data || !$iv) { throw new \InvalidArgumentException('$data or $iv is empty string'); @@ -214,7 +259,10 @@ abstract class Crypt return $result; } - public static function XxteaDecrypt(string $data, string $salt, string $key = null) /* : mixed */ + public static function XxteaDecrypt(string $data, string $salt, + #[\SensitiveParameter] + string $key = null + ) /* : mixed */ { if (!$data || !$salt) { throw new \InvalidArgumentException('$data or $salt is empty string'); @@ -225,7 +273,13 @@ abstract class Crypt : \MailSo\Base\Xxtea::decrypt($data, $key); } - public static function XxteaEncrypt(string $data, string $salt, string $key = null) : string + public static function XxteaEncrypt( + #[\SensitiveParameter] + string $data, + string $salt, + #[\SensitiveParameter] + string $key = null + ) : string { if (!$data || !$salt) { throw new \InvalidArgumentException('$data or $salt is empty string'); diff --git a/snappymail/v/0.0.0/app/libraries/snappymail/http/request.php b/snappymail/v/0.0.0/app/libraries/snappymail/http/request.php index 301d87c34..ffbddeea3 100644 --- a/snappymail/v/0.0.0/app/libraries/snappymail/http/request.php +++ b/snappymail/v/0.0.0/app/libraries/snappymail/http/request.php @@ -48,7 +48,10 @@ abstract class Request $this->user_agent = 'SnappyMail/' . APP_VERSION; } - public function setAuth(int $type, string $user, string $pass) : void + public function setAuth(int $type, string $user, + #[\SensitiveParameter] + string $pass + ) : void { $this->auth = [ 'type' => $type, diff --git a/snappymail/v/0.0.0/app/libraries/snappymail/pgp/gnupg.php b/snappymail/v/0.0.0/app/libraries/snappymail/pgp/gnupg.php index 4e420a734..19f979d69 100644 --- a/snappymail/v/0.0.0/app/libraries/snappymail/pgp/gnupg.php +++ b/snappymail/v/0.0.0/app/libraries/snappymail/pgp/gnupg.php @@ -84,7 +84,10 @@ class GnuPG /** * Add a key for decryption */ - public function addDecryptKey(string $fingerprint, string $passphrase) : bool + public function addDecryptKey(string $fingerprint, + #[\SensitiveParameter] + string $passphrase + ) : bool { return $this->handler()->adddecryptkey($fingerprint, $passphrase); } @@ -100,7 +103,10 @@ class GnuPG /** * Add a key for signing */ - public function addSignKey(string $fingerprint, ?string $passphrase) : bool + public function addSignKey(string $fingerprint, + #[\SensitiveParameter] + ?string $passphrase + ) : bool { return $this->handler()->addsignkey($fingerprint, $passphrase); } @@ -218,7 +224,10 @@ class GnuPG /** * Exports a key */ - public function export(string $fingerprint, string $passphrase = '') /*: string|false*/ + public function export(string $fingerprint, + #[\SensitiveParameter] + string $passphrase = '' + ) /*: string|false*/ { if ($passphrase) { return $this->getGPG() @@ -265,7 +274,10 @@ class GnuPG /** * Generates a key */ - public function generateKey(string $uid, string $passphrase) /*: string|false*/ + public function generateKey(string $uid, + #[\SensitiveParameter] + string $passphrase + ) /*: string|false*/ { $GPG = $this->getGPG(false); return $GPG ? $GPG->generateKey($uid, $passphrase) : false; diff --git a/snappymail/v/0.0.0/app/libraries/snappymail/pgp/gpg.php b/snappymail/v/0.0.0/app/libraries/snappymail/pgp/gpg.php index eb02644f7..f5f51252c 100644 --- a/snappymail/v/0.0.0/app/libraries/snappymail/pgp/gpg.php +++ b/snappymail/v/0.0.0/app/libraries/snappymail/pgp/gpg.php @@ -136,7 +136,10 @@ class GPG /** * Add a key for decryption */ - public function addDecryptKey(string $fingerprint, string $passphrase) : bool + public function addDecryptKey(string $fingerprint, + #[\SensitiveParameter] + string $passphrase + ) : bool { $this->decryptKeys[$fingerprint] = $passphrase; // $this->decryptKeys[\substr($fingerprint, -16)] = $passphrase; @@ -155,7 +158,10 @@ class GPG /** * Add a key for signing */ - public function addSignKey(string $fingerprint, string $passphrase) : bool + public function addSignKey(string $fingerprint, + #[\SensitiveParameter] + string $passphrase + ) : bool { $this->signKeys[$fingerprint] = $passphrase; // $this->signKeys[\substr($fingerprint, -16)] = $passphrase; @@ -419,7 +425,10 @@ class GPG return 0; } - public function addPassphrase($keyId, $passphrase) + public function addPassphrase($keyId, + #[\SensitiveParameter] + $passphrase + ) { $this->passphrases[$keyId] = $passphrase; return $this; diff --git a/snappymail/v/0.0.0/app/libraries/snappymail/sasl/cram.php b/snappymail/v/0.0.0/app/libraries/snappymail/sasl/cram.php index 4ed7f6b7e..f321496bd 100644 --- a/snappymail/v/0.0.0/app/libraries/snappymail/sasl/cram.php +++ b/snappymail/v/0.0.0/app/libraries/snappymail/sasl/cram.php @@ -14,7 +14,11 @@ class Cram extends \SnappyMail\SASL $this->algo = $algo; } - public function authenticate(string $authcid, string $passphrase, ?string $challenge = null) : string + public function authenticate(string $authcid, + #[\SensitiveParameter] + string $passphrase, + ?string $challenge = null + ) : string { return $this->encode($authcid . ' ' . \hash_hmac($this->algo, $this->decode($challenge), $passphrase)); } diff --git a/snappymail/v/0.0.0/app/libraries/snappymail/sasl/login.php b/snappymail/v/0.0.0/app/libraries/snappymail/sasl/login.php index 52608a49f..2f0441fcb 100644 --- a/snappymail/v/0.0.0/app/libraries/snappymail/sasl/login.php +++ b/snappymail/v/0.0.0/app/libraries/snappymail/sasl/login.php @@ -2,19 +2,24 @@ namespace SnappyMail\SASL; +use SnappyMail\SensitiveString; + class Login extends \SnappyMail\SASL { protected - $passphrase; + SensitiveString $passphrase; - public function authenticate(string $username, string $passphrase, ?string $challenge = null) : string + public function authenticate(string $username, + #[\SensitiveParameter] + string $passphrase, + ?string $challenge = null) : string { // $challenge should be 'VXNlcm5hbWU6', but broken on some systems // See https://github.com/the-djmaze/snappymail/issues/693 if ($challenge && !\str_starts_with($this->decode($challenge), 'Username:')) { throw new \Exception("Invalid response: {$this->decode($challenge)}"); } - $this->passphrase = $passphrase; + $this->passphrase = new SensitiveString($passphrase); return $this->encode($username); } @@ -24,7 +29,7 @@ class Login extends \SnappyMail\SASL if ($challenge && 'Password:' !== $this->decode($challenge)) { throw new \Exception("invalid response: {$challenge}"); } - return $this->encode($this->passphrase); + return $this->encode($this->passphrase->getValue()); } public static function isSupported(string $param) : bool diff --git a/snappymail/v/0.0.0/app/libraries/snappymail/sasl/oauthbearer.php b/snappymail/v/0.0.0/app/libraries/snappymail/sasl/oauthbearer.php index 66bfb84a2..e6e8dc1a2 100644 --- a/snappymail/v/0.0.0/app/libraries/snappymail/sasl/oauthbearer.php +++ b/snappymail/v/0.0.0/app/libraries/snappymail/sasl/oauthbearer.php @@ -4,12 +4,15 @@ * https://developers.google.com/gmail/imap/xoauth2-protocol */ - namespace SnappyMail\SASL; class OAuthBearer extends \SnappyMail\SASL { - public function authenticate(string $username, string $passphrase, ?string $authzid = null) : string + public function authenticate(string $username, + #[\SensitiveParameter] + string $passphrase, + ?string $authzid = null + ) : string { return $this->encode("n,a={$username},\x01auth=Bearer {$passphrase}\x01\x01"); } diff --git a/snappymail/v/0.0.0/app/libraries/snappymail/sasl/plain.php b/snappymail/v/0.0.0/app/libraries/snappymail/sasl/plain.php index dca6aa103..92ccc0d4f 100644 --- a/snappymail/v/0.0.0/app/libraries/snappymail/sasl/plain.php +++ b/snappymail/v/0.0.0/app/libraries/snappymail/sasl/plain.php @@ -5,7 +5,10 @@ namespace SnappyMail\SASL; class Plain extends \SnappyMail\SASL { - public function authenticate(string $username, string $passphrase, ?string $authzid = null) : string + public function authenticate(string $username, + #[\SensitiveParameter] + string $passphrase, + ?string $authzid = null) : string { return $this->encode("{$authzid}\x00{$username}\x00{$passphrase}"); } diff --git a/snappymail/v/0.0.0/app/libraries/snappymail/sasl/scram.php b/snappymail/v/0.0.0/app/libraries/snappymail/sasl/scram.php index a74c4ecc8..10e824741 100644 --- a/snappymail/v/0.0.0/app/libraries/snappymail/sasl/scram.php +++ b/snappymail/v/0.0.0/app/libraries/snappymail/sasl/scram.php @@ -4,16 +4,16 @@ * https://tools.ietf.org/html/rfc7677 */ - namespace SnappyMail\SASL; +use SnappyMail\SensitiveString; + class Scram extends \SnappyMail\SASL { - + protected ?SensitiveString $passphrase; protected $algo, $nonce, - $passphrase, $gs2_header, $auth_message, $server_key; @@ -31,13 +31,17 @@ class Scram extends \SnappyMail\SASL $this->algo = $algo; } - public function authenticate(string $authcid, string $passphrase, ?string $authzid = null) : string + public function authenticate(string $authcid, + #[\SensitiveParameter] + string $passphrase, + ?string $authzid = null + ) : string { // SASLprep $authcid = \str_replace(array('=',','), array('=3D','=2C'), $authcid); $this->nonce = \bin2hex(\random_bytes(16)); - $this->passphrase = $passphrase; + $this->passphrase = new SensitiveString($passphrase); $this->gs2_header = 'n,' . (empty($authzid) ? '' : 'a=' . $authzid) . ','; $this->auth_message = "n={$authcid},r={$this->nonce}"; return $this->encode($this->gs2_header . $this->auth_message); @@ -67,7 +71,7 @@ class Scram extends \SnappyMail\SASL throw new \Exception('Server invalid salt'); } - $pass = \hash_pbkdf2($this->algo, $this->passphrase, $salt, \intval($values['i']), 0, true); + $pass = \hash_pbkdf2($this->algo, $this->passphrase->getValue(), $salt, \intval($values['i']), 0, true); $this->passphrase = null; $ckey = \hash_hmac($this->algo, 'Client Key', $pass, true); diff --git a/snappymail/v/0.0.0/app/libraries/snappymail/sasl/xoauth2.php b/snappymail/v/0.0.0/app/libraries/snappymail/sasl/xoauth2.php index bf1563013..48eb3fa40 100644 --- a/snappymail/v/0.0.0/app/libraries/snappymail/sasl/xoauth2.php +++ b/snappymail/v/0.0.0/app/libraries/snappymail/sasl/xoauth2.php @@ -4,12 +4,15 @@ * https://developers.google.com/gmail/imap/xoauth2-protocol */ - namespace SnappyMail\SASL; class XOAuth2 extends \SnappyMail\SASL { - public function authenticate(string $username, string $passphrase, ?string $authzid = null) : string + public function authenticate(string $username, + #[\SensitiveParameter] + string $passphrase, + ?string $authzid = null + ) : string { return $this->encode("user={$username}\x01auth=Bearer {$passphrase}\x01\x01"); } diff --git a/snappymail/v/0.0.0/app/libraries/snappymail/sensitivestring.php b/snappymail/v/0.0.0/app/libraries/snappymail/sensitivestring.php new file mode 100644 index 000000000..449215c1d --- /dev/null +++ b/snappymail/v/0.0.0/app/libraries/snappymail/sensitivestring.php @@ -0,0 +1,72 @@ +setValue($value); + } + + public function getValue(): string + { + if (\is_callable('sodium_crypto_secretbox')) { + return \sodium_crypto_secretbox_open($this->value, $this->nonce, APP_SALT); + } + return xorIt($this->value); + } + + public function setValue( + #[\SensitiveParameter] + string $value + ) : void + { + if (\is_callable('sodium_crypto_secretbox')) { + $this->nonce = \random_bytes(\SODIUM_CRYPTO_SECRETBOX_NONCEBYTES); +// $this->key = \sodium_crypto_secretbox_keygen(); + $this->value = \sodium_crypto_secretbox($value, $this->nonce, APP_SALT); + } else { + $this->value = xorIt($value); + } + } + + public function __toString(): string + { + return $this->getValue(); + } + + public function __debugInfo(): array + { + return []; + } + + public function __serialize(): array + { + throw new \Exception("Serialization of 'SensitiveString' is not allowed"); + } + + public function __unserialize(array $data): void + { + throw new \Exception("Unserialization of 'SensitiveString' is not allowed"); + } +}