Added support for sodium_crypto_aead_xchacha20poly1305_ietf encryption

This commit is contained in:
djmaze 2021-11-10 10:36:16 +01:00
parent 492dee5e1a
commit 414a9509aa
4 changed files with 66 additions and 21 deletions

View file

@ -696,7 +696,7 @@ trait Admin
public function DoAdminPHPExtensions() : array public function DoAdminPHPExtensions() : array
{ {
$aResult = []; $aResult = [];
foreach (['APCu', 'cURL','GD','Gmagick','Imagick','intl','LDAP','pdo_mysql','pdo_pgsql','pdo_sqlite','XXTEA','Zip'] as $name) { foreach (['APCu', 'cURL','GD','Gmagick','Imagick','intl','LDAP','OpenSSL','pdo_mysql','pdo_pgsql','pdo_sqlite','Sodium','XXTEA','Zip'] as $name) {
$aResult[] = [ $aResult[] = [
'name' => $name, 'name' => $name,
'loaded' => \extension_loaded(\strtolower($name)) 'loaded' => \extension_loaded(\strtolower($name))

View file

@ -235,9 +235,15 @@ trait UserAuth
$uuid = \SnappyMail\UUID::generate(); $uuid = \SnappyMail\UUID::generate();
\SnappyMail\Crypt::setCipher($this->Config()->Get('security', 'encrypt_cipher', '')); \SnappyMail\Crypt::setCipher($this->Config()->Get('security', 'encrypt_cipher', ''));
$data = \SnappyMail\Crypt::EncryptRaw($oAccount); $data = \SnappyMail\Crypt::Encrypt($oAccount);
if ('xxtea' === $data[0]) { if ('xxtea' === $data[0]) {
static::SetSignMeTokenCookie(array(
'e' => $oAccount->Email(),
'u' => $uuid,
'x' => \base64_encode($data[1])
));
} else if ('sodium' === $data[0]) {
static::SetSignMeTokenCookie(array( static::SetSignMeTokenCookie(array(
'e' => $oAccount->Email(), 'e' => $oAccount->Email(),
'u' => $uuid, 'u' => $uuid,
@ -247,7 +253,7 @@ trait UserAuth
static::SetSignMeTokenCookie(array( static::SetSignMeTokenCookie(array(
'e' => $oAccount->Email(), 'e' => $oAccount->Email(),
'u' => $uuid, 'u' => $uuid,
'i' => \base64_encode($data[1]) 'o' => \base64_encode($data[1])
)); ));
} }
@ -274,10 +280,12 @@ trait UserAuth
return null; return null;
} }
\SnappyMail\Crypt::setCipher($this->Config()->Get('security', 'encrypt_cipher', '')); \SnappyMail\Crypt::setCipher($this->Config()->Get('security', 'encrypt_cipher', ''));
if (!empty($aTokenData['s'])) { if (!empty($aTokenData['x'])) {
$aAccountHash = \SnappyMail\Crypt::XxteaDecrypt($sAuthToken, \base64_decode($aTokenData['s'])); $aAccountHash = \SnappyMail\Crypt::XxteaDecrypt($sAuthToken, \base64_decode($aTokenData['x']));
} else if (!empty($aTokenData['i'])) { } else if (!empty($aTokenData['s'])) {
$aAccountHash = \SnappyMail\Crypt::OpenSSLDecrypt($sAuthToken, \base64_decode($aTokenData['i'])); $aAccountHash = \SnappyMail\Crypt::SodiumDecrypt($sAuthToken, \base64_decode($aTokenData['s']));
} else if (!empty($aTokenData['o'])) {
$aAccountHash = \SnappyMail\Crypt::OpenSSLDecrypt($sAuthToken, \base64_decode($aTokenData['o']));
} }
if (!empty($aAccountHash) && \is_array($aAccountHash)) { if (!empty($aAccountHash) && \is_array($aAccountHash)) {
$oAccount = Account::NewInstanceFromTokenArray($this, $aAccountHash); $oAccount = Account::NewInstanceFromTokenArray($this, $aAccountHash);

View file

@ -68,31 +68,53 @@ abstract class Crypt
); );
} }
public static function EncryptRaw($data) : array public static function Encrypt($data) : array
{ {
if (\is_callable('sodium_crypto_aead_xchacha20poly1305_ietf_encrypt')) {
$nonce = \random_bytes(24);
return ['sodium', $nonce, static::SodiumEncrypt($data, $nonce)];
}
if (static::$cipher && \is_callable('openssl_encrypt')) { if (static::$cipher && \is_callable('openssl_encrypt')) {
$iv = \random_bytes(\openssl_cipher_iv_length(static::$cipher)); $iv = \random_bytes(\openssl_cipher_iv_length(static::$cipher));
$data = \openssl_encrypt( return ['openssl', $nonce, static::OpenSSLEncrypt($data, $iv)];
\json_encode($data),
static::$cipher,
static::Passphrase(),
OPENSSL_RAW_DATA,
$iv
);
return [static::$cipher, $iv, $data];
} }
$salt = \random_bytes(16); $salt = \random_bytes(16);
return ['xxtea', $salt, static::XxteaEncrypt($data, $salt)]; return ['xxtea', $salt, static::XxteaEncrypt($data, $salt)];
} }
public static function OpenSSLDecrypt(string $data, string $iv) public static function SodiumDecrypt(string $data, string $nonce)
{ {
if (!$data || !$iv) { if (!\is_callable('sodium_crypto_aead_xchacha20poly1305_ietf_decrypt')) {
return null; return null;
} }
if (!static::$cipher || !\is_callable('openssl_decrypt')) { return \json_decode(\sodium_crypto_aead_xchacha20poly1305_ietf_decrypt(
return static::XxteaDecrypt($data, $iv); $data,
APP_SALT,
$nonce,
static::Passphrase()
));
}
public static function SodiumEncrypt($data, string $nonce) : ?string
{
if (!\is_callable('sodium_crypto_aead_xchacha20poly1305_ietf_encrypt')) {
return null;
}
return \sodium_crypto_aead_xchacha20poly1305_ietf_encrypt(
\json_encode($data),
APP_SALT,
$nonce,
\str_pad('', \SODIUM_CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES, static::Passphrase())
);
}
public static function OpenSSLDecrypt(string $data, string $iv)
{
if (!$data || !$iv || !static::$cipher || !\is_callable('openssl_decrypt')) {
return null;
} }
return \json_decode(\openssl_decrypt( return \json_decode(\openssl_decrypt(
$data, $data,
@ -103,6 +125,20 @@ abstract class Crypt
), true); ), true);
} }
public static function OpenSSLEncrypt($data, string $iv) : ?string
{
if (!$data || !$iv || !static::$cipher || !\is_callable('openssl_encrypt')) {
return null;
}
return \openssl_encrypt(
\json_encode($data),
static::$cipher,
static::Passphrase(),
OPENSSL_RAW_DATA,
$iv
);
}
public static function XxteaDecrypt(string $data, string $salt) public static function XxteaDecrypt(string $data, string $salt)
{ {
if (!$data || !$salt) { if (!$data || !$salt) {
@ -115,7 +151,7 @@ abstract class Crypt
, true); , true);
} }
public static function XxteaEncrypt($data, string $salt) : string public static function XxteaEncrypt($data, string $salt) : ?string
{ {
if (!$data || !$salt) { if (!$data || !$salt) {
return null; return null;

View file

@ -20,6 +20,7 @@
'OpenSSL' => extension_loaded('openssl'), 'OpenSSL' => extension_loaded('openssl'),
'mysql' => extension_loaded('pdo_mysql'), 'mysql' => extension_loaded('pdo_mysql'),
'pgsql' => extension_loaded('pdo_pgsql'), 'pgsql' => extension_loaded('pdo_pgsql'),
'Sodium' => extension_loaded('sodium'),
'sqlite' => extension_loaded('pdo_sqlite'), 'sqlite' => extension_loaded('pdo_sqlite'),
'xxtea' => extension_loaded('xxtea'), 'xxtea' => extension_loaded('xxtea'),
'zip' => extension_loaded('zip') 'zip' => extension_loaded('zip')