Valider 6437b745 rédigé par marcimat's avatar marcimat
Parcourir les fichiers

Chiffrement plus poussé : pad / unpad du message + hash si password (g0uZ)

- Utiliser sodium_pad et sodium_unpad sur le message à chiffrer
- Hacher un password en sha256 dans le chiffrement s’il sert comme clé.
C’est un compromis suffisant.
parent 87fcf64d
Chargement en cours
Chargement en cours
Chargement en cours
Chargement en cours
+30 −15
Numéro de ligne d'origine Numéro de ligne de diff Ligne de diff
@@ -19,10 +19,8 @@ namespace Spip\Chiffrer;
 * @link https://www.php.net/manual/fr/book.sodium.php
 */
class Chiffrement {
	public static function keygen(): string {
		return sodium_crypto_secretbox_keygen();
	}

	/** Chiffre un message en utilisant une clé (le secret_du_site par défaut) ou un mot de passe */
	public static function chiffrer(
		string $message,
		#[\SensitiveParameter]
@@ -33,14 +31,12 @@ class Chiffrement {
			spip_log("chiffrer() sans clé `$message`", 'chiffrer' . _LOG_INFO_IMPORTANTE);
			return null;
		}
		if (strlen($key) !== SODIUM_CRYPTO_SECRETBOX_KEYBYTES) {
			while (strlen($key) < SODIUM_CRYPTO_SECRETBOX_KEYBYTES) {
				$key .= $key;
			}
			$key = substr($key, 0, SODIUM_CRYPTO_SECRETBOX_KEYBYTES);
		if (strlen($key) !== \SODIUM_CRYPTO_SECRETBOX_KEYBYTES) {
			$key = self::generateKeyFromPassword($key);
		}
		$nonce = random_bytes(\SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
		$encrypted = sodium_crypto_secretbox($message, $nonce, $key);
		$padded_message = sodium_pad($message, 16);
		$encrypted = sodium_crypto_secretbox($padded_message, $nonce, $key);
		$encoded = base64_encode($nonce . $encrypted);
		sodium_memzero($key);
		sodium_memzero($nonce);
@@ -48,6 +44,7 @@ class Chiffrement {
		return $encoded;
	}

	/** Déchiffre un message en utilisant une clé (le secret_du_site par défaut) ou un mot de passe */	
	public static function dechiffrer(
		string $encoded,
		#[\SensitiveParameter]
@@ -58,16 +55,14 @@ class Chiffrement {
			spip_log("dechiffrer() sans clé `$encoded`", 'chiffrer' . _LOG_INFO_IMPORTANTE);
			return null;
		}
		if (strlen($key) !== SODIUM_CRYPTO_SECRETBOX_KEYBYTES) {
			while (strlen($key) < SODIUM_CRYPTO_SECRETBOX_KEYBYTES) {
				$key .= $key;
			}
			$key = substr($key, 0, SODIUM_CRYPTO_SECRETBOX_KEYBYTES);
		if (strlen($key) !== \SODIUM_CRYPTO_SECRETBOX_KEYBYTES) {
			$key = self::generateKeyFromPassword($key);
		}
		$decoded = base64_decode($encoded);
		$nonce = mb_substr($decoded, 0, \SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, '8bit');
		$encrypted_result = mb_substr($decoded, \SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, null, '8bit');
		$message = sodium_crypto_secretbox_open($encrypted_result, $nonce, $key);
		$padded_message = sodium_crypto_secretbox_open($encrypted_result, $nonce, $key);
		$message = sodium_unpad($padded_message, 16);
		sodium_memzero($key);
		sodium_memzero($nonce);
		if ($message !== false) {
@@ -78,6 +73,26 @@ class Chiffrement {
		return null;
	}

	/** Génère une clé de la taille attendue pour le chiffrement */
	public static function keygen(): string {
		return sodium_crypto_secretbox_keygen();
	}

	/**
	 * Retourne une clé de la taille attendue pour le chiffrement
	 *
	 * Notamment si on utilise un mot de passe comme clé, il faut le hacher
	 * pour servir de clé à la taille correspondante.
	 */
	private static function generateKeyFromPassword(string $password): string {
		if (strlen($password) === \SODIUM_CRYPTO_SECRETBOX_KEYBYTES) {
			return $password;
		}
		$hashed = hash('sha256', $password);
		return substr($hashed, 0, \SODIUM_CRYPTO_SECRETBOX_KEYBYTES);
	}

	/** Retourne la clé de chiffrement par défaut (le secret_du_site) */
	private static function getDefaultKey(): ?string {
		$keys = SpipCles::instance();
		return $keys->getSecretSite();