diff --git a/composer.json b/composer.json index 002359412207034c766c8f87576a8c16e3496c80..e4414595671316b647db013a3cf4ecbe38378430 100755 --- a/composer.json +++ b/composer.json @@ -33,7 +33,8 @@ "psr/log": "1.1", "psr/cache": "1.0.1", "slim/psr7": "1.6", - "jasig/phpcas": "1.5.0" + "jasig/phpcas": "1.5.0", + "ext-openssl": "*" }, "require-dev": { "phpunit/phpunit": "^9" diff --git a/src/app/configuration/controllers/ConfigurationController.php b/src/app/configuration/controllers/ConfigurationController.php index 1d3b74cb1f9b0b3f0aac79f4ebcaf7682cd8202e..b019a8224db400c0a7a503feae21fc026a660f57 100755 --- a/src/app/configuration/controllers/ConfigurationController.php +++ b/src/app/configuration/controllers/ConfigurationController.php @@ -124,7 +124,7 @@ class ConfigurationController } if ($body['value']['auth'] && !empty($body['value']['password'])) { - $body['value']['password'] = AuthenticationModel::encrypt(['password' => $body['value']['password']]); + $body['value']['password'] = AuthenticationModel::encrypt($body['value']['password']); } elseif (!$body['value']['auth']) { $body['value']['user'] = null; $body['value']['password'] = null; @@ -230,7 +230,7 @@ class ConfigurationController $body['value']['password'] = $configuration['value']['password']; } } elseif ($body['value']['auth'] && !empty($body['value']['password'])) { - $body['value']['password'] = AuthenticationModel::encrypt(['password' => $body['value']['password']]); + $body['value']['password'] = AuthenticationModel::encrypt($body['value']['password']); } elseif (!$body['value']['auth']) { $body['value']['user'] = null; $body['value']['password'] = null; diff --git a/src/app/email/controllers/EmailController.php b/src/app/email/controllers/EmailController.php index 7a4d22b9a9eaef0ab51bcbd7daef422bd4164e56..3b07f57fbf1325f06a3ef9f5eaae12453d8116ac 100644 --- a/src/app/email/controllers/EmailController.php +++ b/src/app/email/controllers/EmailController.php @@ -151,7 +151,7 @@ class EmailController if ($configuration['auth']) { $phpmailer->Username = $configuration['user']; if (!empty($configuration['password'])) { - $phpmailer->Password = AuthenticationModel::decrypt(['cryptedPassword' => $configuration['password']]); + $phpmailer->Password = AuthenticationModel::decrypt($configuration['password']); } } } elseif ($configuration['type'] == 'sendmail') { diff --git a/src/app/externalSignatoryBook/controllers/ExternalSignatoryBookController.php b/src/app/externalSignatoryBook/controllers/ExternalSignatoryBookController.php index d311288773d66f5f7e9fd43567c843d1618c6612..dcbf750fb300123e1587b10c37d4eeb73f3aeb53 100755 --- a/src/app/externalSignatoryBook/controllers/ExternalSignatoryBookController.php +++ b/src/app/externalSignatoryBook/controllers/ExternalSignatoryBookController.php @@ -71,7 +71,7 @@ class ExternalSignatoryBookController $connector['apiUri'] = $connectionData['apiUri']; $connector['subscriberId'] = $connectionData['subscriberId']; $connector['certPath'] = $connectionData['certPath']; - $connector['certPass'] = AuthenticationModel::decrypt(['cryptedPassword' => $connectionData['certPass']]); + $connector['certPass'] = AuthenticationModel::decrypt($connectionData['certPass']); $connector['certType'] = $connectionData['certType']; } @@ -102,7 +102,7 @@ class ExternalSignatoryBookController 'apiUri' => $body['apiUri'], 'subscriberId' => $body['subscriberId'], 'certPath' => $body['certPath'], - 'certPass' => AuthenticationModel::encrypt(['password' => $body['certPass']]), + 'certPass' => AuthenticationModel::encrypt($body['certPass']), 'certType' => $body['certType'] ]; } @@ -151,7 +151,7 @@ class ExternalSignatoryBookController 'apiUri' => $body['apiUri'], 'subscriberId' => $body['subscriberId'], 'certPath' => $body['certPath'], - 'certPass' => AuthenticationModel::encrypt(['password' => $body['certPass']]), + 'certPass' => AuthenticationModel::encrypt($body['certPass']), 'certType' => $body['certType'] ]; } diff --git a/src/app/workflow/controllers/FastOTPController.php b/src/app/workflow/controllers/FastOTPController.php index 53c3887211142afdd36a52bcd1626026f522eb24..4578b6a44a0dabc372d4f6e010061c80db342466 100644 --- a/src/app/workflow/controllers/FastOTPController.php +++ b/src/app/workflow/controllers/FastOTPController.php @@ -357,7 +357,7 @@ class FastOTPController 'url' => $args['connection_data']['apiUri'] . "/documents/v2/otp/{$args['connection_data']['subscriberId']}/signature-otp/upload", 'options' => [ CURLOPT_SSLCERT => $args['connection_data']['certPath'], - CURLOPT_SSLCERTPASSWD => AuthenticationModel::decrypt(['cryptedPassword' => $args['connection_data']['certPass']]), + CURLOPT_SSLCERTPASSWD => AuthenticationModel::decrypt($args['connection_data']['certPass']), CURLOPT_SSLCERTTYPE => $args['connection_data']['certType'] ], 'multipartBody' => $args['multipartBody'] @@ -407,7 +407,7 @@ class FastOTPController 'url' => $args['connection_data']['apiUri'] . '/documents/v2/' . $args['documentId'] . '/download', 'options' => [ CURLOPT_SSLCERT => $args['connection_data']['certPath'], - CURLOPT_SSLCERTPASSWD => AuthenticationModel::decrypt(['cryptedPassword' => $args['connection_data']['certPass']]), + CURLOPT_SSLCERTPASSWD => AuthenticationModel::decrypt($args['connection_data']['certPass']), CURLOPT_SSLCERTTYPE => $args['connection_data']['certType'], ], 'fileResponse' => true @@ -435,7 +435,7 @@ class FastOTPController 'method' => 'GET', 'options' => [ CURLOPT_SSLCERT => $args['connection_data']['certPath'], - CURLOPT_SSLCERTPASSWD => AuthenticationModel::decrypt(['cryptedPassword' => $args['connection_data']['certPass']]), + CURLOPT_SSLCERTPASSWD => AuthenticationModel::decrypt($args['connection_data']['certPass']), CURLOPT_SSLCERTTYPE => $args['connection_data']['certType'] ] ]); @@ -475,7 +475,7 @@ class FastOTPController 'url' => $args['connection_data']['apiUri'] . '/documents/v2/' . $args['documentId'], 'options' => [ CURLOPT_SSLCERT => $args['connection_data']['certPath'], - CURLOPT_SSLCERTPASSWD => AuthenticationModel::decrypt(['cryptedPassword' => $args['connection_data']['certPass']]), + CURLOPT_SSLCERTPASSWD => AuthenticationModel::decrypt($args['connection_data']['certPass']), CURLOPT_SSLCERTTYPE => $args['connection_data']['certType'], ] ]); @@ -539,7 +539,7 @@ class FastOTPController 'method' => 'GET', 'options' => [ CURLOPT_SSLCERT => $args['connection_data']['certPath'], - CURLOPT_SSLCERTPASSWD => AuthenticationModel::decrypt(['cryptedPassword' => $args['connection_data']['certPass']]), + CURLOPT_SSLCERTPASSWD => AuthenticationModel::decrypt($args['connection_data']['certPass']), CURLOPT_SSLCERTTYPE => $args['connection_data']['certType'], ], 'fileResponse' => true diff --git a/src/core/controllers/AuthenticationController.php b/src/core/controllers/AuthenticationController.php index 840563feadc86b8c8d81af0da6b58deb67c16fe6..d43ec5536bb5c3337b7c97b2f8d57309432b1314 100755 --- a/src/core/controllers/AuthenticationController.php +++ b/src/core/controllers/AuthenticationController.php @@ -40,7 +40,7 @@ class AuthenticationController public function getInformations(Request $request, Response $response) { $connection = ConfigurationModel::getConnection(); - $encryptKey = CoreConfigModel::getEncryptKey(); + $encryptKeyChanged = CoreConfigModel::hasEncryptKeyChanged(); $path = CoreConfigModel::getConfigPath(); $coreUrl = UrlController::getCoreUrl(); $hashedPath = md5($path); @@ -67,7 +67,7 @@ class AuthenticationController return $response->withJson([ 'connection' => $connection, - 'changeKey' => $encryptKey == 'Security Key Maarch Parapheur #2008', + 'changeKey' => !$encryptKeyChanged, 'instanceId' => $hashedPath, 'coreUrl' => $coreUrl, 'mailServerOnline' => $mailServerOnline, diff --git a/src/core/models/AuthenticationModel.php b/src/core/models/AuthenticationModel.php index 2dd379d7c233e848f06bc01a7161db7002906338..6852ec8d75f81f9e9fcf0a91098121338a072177 100755 --- a/src/core/models/AuthenticationModel.php +++ b/src/core/models/AuthenticationModel.php @@ -14,6 +14,7 @@ namespace SrcCore\models; +use Exception; use Firebase\JWT\JWT; use Firebase\JWT\Key; @@ -43,33 +44,63 @@ class AuthenticationModel return password_verify($args['password'], $aReturn[0]['password']); } - public static function encrypt(array $aArgs) + /** + * @throws Exception + */ + public static function encrypt(string $data): string { - ValidatorModel::notEmpty($aArgs, ['password']); - ValidatorModel::stringType($aArgs, ['password']); - $encryptKey = CoreConfigModel::getEncryptKey(); - $cipher_method = 'AES-128-CTR'; - $enc_iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length($cipher_method)); - $cryptedPassword = openssl_encrypt($aArgs['password'], $cipher_method, $encryptKey, 0, $enc_iv) . "::" . bin2hex($enc_iv); + $cipherMethod = 'AES-256-CTR'; + $encryptKeyHash = openssl_digest($encryptKey, 'sha256'); + + $initialisationVector = openssl_random_pseudo_bytes(openssl_cipher_iv_length($cipherMethod)); + $encrypted = openssl_encrypt($data, $cipherMethod, $encryptKeyHash, OPENSSL_RAW_DATA, $initialisationVector); + + if ($encrypted === false) { + throw new Exception('Encryption failed: ' . openssl_error_string()); + } - return $cryptedPassword; + $encryptedResult = $initialisationVector . $encrypted; + + return base64_encode($encryptedResult); } - public static function decrypt(array $aArgs) + /** + * @throws Exception + */ + public static function decrypt(string $encryptedData): string { - ValidatorModel::notEmpty($aArgs, ['cryptedPassword']); - ValidatorModel::stringType($aArgs, ['cryptedPassword']); + $encryptedData = base64_decode($encryptedData); $encryptKey = CoreConfigModel::getEncryptKey(); - $cipher_method = 'AES-128-CTR'; + $cipherMethod = 'AES-256-CTR'; - list($crypted_token, $enc_iv) = explode("::", $aArgs['cryptedPassword']); - $password = openssl_decrypt($crypted_token, $cipher_method, $encryptKey, 0, hex2bin($enc_iv)); + $initialisationVectorLength = openssl_cipher_iv_length($cipherMethod); - return $password; + // encrypted data integrity check on size of data + if (strlen($encryptedData) < $initialisationVectorLength) { + throw new Exception( + 'Decryption failed: data length ' + . strlen($encryptedData) + . ' is less than iv length ' . $initialisationVectorLength + ); + } + + // Extract the initialisation vector and encrypted data + $initialisationVector = substr($encryptedData, 0, $initialisationVectorLength); + $encryptedData = substr($encryptedData, $initialisationVectorLength); + + $encryptKeyHash = openssl_digest($encryptKey, 'sha256'); + + $result = openssl_decrypt($encryptedData, $cipherMethod, $encryptKeyHash, OPENSSL_RAW_DATA, $initialisationVector); + + if ($result === false) { + throw new Exception('Decryption failed: ' . openssl_error_string()); + } + + return $result; } public static function generatePassword() diff --git a/src/core/models/CoreConfigModel.php b/src/core/models/CoreConfigModel.php index a4132a43afefd298f72ae77c1db5c6f175ab6095..86625b0890c1f6f3c931305d68202c0a2fa9a499 100755 --- a/src/core/models/CoreConfigModel.php +++ b/src/core/models/CoreConfigModel.php @@ -99,15 +99,24 @@ class CoreConfigModel public static function getEncryptKey() { - if (!empty($_SERVER['MAARCH_ENCRYPT_KEY'])) { - $encriptKey = $_SERVER['MAARCH_ENCRYPT_KEY']; - } elseif (!empty($_SERVER['REDIRECT_MAARCH_ENCRYPT_KEY'])) { - $encriptKey = $_SERVER['REDIRECT_MAARCH_ENCRYPT_KEY']; - } else { - $encriptKey = "Security Key Maarch Parapheur #2008"; + $encryptKey = "Security Key Maarch Parapheur #2008"; + + $config = CoreConfigModel::getConfig(); + $encryptKeyPath = $config['config']['privateKeyPath'] ?? null; + + if (!empty($encryptKeyPath) && is_file($encryptKeyPath) && is_readable($encryptKeyPath)) { + $encryptKey = file_get_contents($encryptKeyPath); + $encryptKey = trim($encryptKey); } - return $encriptKey; + return $encryptKey; + } + + public static function hasEncryptKeyChanged(): bool + { + $encryptKey = CoreConfigModel::getEncryptKey(); + + return $encryptKey !== "Security Key Maarch Parapheur #2008" && $encryptKey !== "Security Key Maarch Parapheur 2008"; } public static function getLibrariesDirectory()