Comme le suggère @rqLizard vous pouvez utiliser openssl_encrypt
/ openssl_decrypt
fonctions PHP à la place, ce qui constitue une meilleure alternative pour implémenter AES (The Advanced Encryption Standard) également connu sous le nom de cryptage Rijndael.
Conformément à ce qui suit Commentaire de Scott sur php.net :
Si vous écrivez du code pour crypter/chiffrer des données en 2015, vous devriez utiliser openssl_encrypt()
et openssl_decrypt()
. La bibliothèque sous-jacente ( libmcrypt
) a été abandonné depuis 2007, et est bien moins performant qu'OpenSSL (qui exploite AES-NI
sur les processeurs modernes et est sans danger pour le cache).
Aussi, MCRYPT_RIJNDAEL_256
n'est pas AES-256
il s'agit d'une variante différente du chiffrement par blocs Rijndael. Si vous voulez AES-256
sur mcrypt
vous devez utiliser MCRYPT_RIJNDAEL_128
avec une clé de 32 octets. OpenSSL rend plus évident le mode que vous utilisez (i.e. aes-128-cbc
vs aes-256-ctr
).
OpenSSL utilise également le remplissage PKCS7 avec le mode CBC plutôt que le remplissage NULL byte de mcrypt. Ainsi, mcrypt est plus susceptible de rendre votre code vulnérable aux attaques de type padding oracle qu'OpenSSL.
Enfin, si vous n'authentifiez pas vos ciphertexts (Encrypt Then MAC), vous vous y prenez mal.
Pour en savoir plus :
Exemples de code
Exemple n° 1
Exemple de chiffrement authentifié AES en mode GCM pour PHP 7.1+.
<?php
//$key should have been previously generated in a cryptographically safe way, like openssl_random_pseudo_bytes
$plaintext = "message to be encrypted";
$cipher = "aes-128-gcm";
if (in_array($cipher, openssl_get_cipher_methods()))
{
$ivlen = openssl_cipher_iv_length($cipher);
$iv = openssl_random_pseudo_bytes($ivlen);
$ciphertext = openssl_encrypt($plaintext, $cipher, $key, $options=0, $iv, $tag);
//store $cipher, $iv, and $tag for decryption later
$original_plaintext = openssl_decrypt($ciphertext, $cipher, $key, $options=0, $iv, $tag);
echo $original_plaintext."\n";
}
?>
Exemple n° 2
Exemple de chiffrement authentifié AES en PHP 5.6+.
<?php
//$key previously generated safely, ie: openssl_random_pseudo_bytes
$plaintext = "message to be encrypted";
$ivlen = openssl_cipher_iv_length($cipher="AES-128-CBC");
$iv = openssl_random_pseudo_bytes($ivlen);
$ciphertext_raw = openssl_encrypt($plaintext, $cipher, $key, $options=OPENSSL_RAW_DATA, $iv);
$hmac = hash_hmac('sha256', $ciphertext_raw, $key, $as_binary=true);
$ciphertext = base64_encode( $iv.$hmac.$ciphertext_raw );
//decrypt later....
$c = base64_decode($ciphertext);
$ivlen = openssl_cipher_iv_length($cipher="AES-128-CBC");
$iv = substr($c, 0, $ivlen);
$hmac = substr($c, $ivlen, $sha2len=32);
$ciphertext_raw = substr($c, $ivlen+$sha2len);
$original_plaintext = openssl_decrypt($ciphertext_raw, $cipher, $key, $options=OPENSSL_RAW_DATA, $iv);
$calcmac = hash_hmac('sha256', $ciphertext_raw, $key, $as_binary=true);
if (hash_equals($hmac, $calcmac))//PHP 5.6+ timing attack safe comparison
{
echo $original_plaintext."\n";
}
?>
Exemple n° 3
Sur la base des exemples ci-dessus, j'ai modifié le code suivant qui vise à crypter l'identifiant de session de l'utilisateur :
class Session {
/**
* Encrypts the session ID and returns it as a base 64 encoded string.
*
* @param $session_id
* @return string
*/
public function encrypt($session_id) {
// Get the MD5 hash salt as a key.
$key = $this->_getSalt();
// For an easy iv, MD5 the salt again.
$iv = $this->_getIv();
// Encrypt the session ID.
$encrypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $session_id, MCRYPT_MODE_CBC, $iv);
// Base 64 encode the encrypted session ID.
$encryptedSessionId = base64_encode($encrypt);
// Return it.
return $encryptedSessionId;
}
/**
* Decrypts a base 64 encoded encrypted session ID back to its original form.
*
* @param $encryptedSessionId
* @return string
*/
public function decrypt($encryptedSessionId) {
// Get the MD5 hash salt as a key.
$key = $this->_getSalt();
// For an easy iv, MD5 the salt again.
$iv = $this->_getIv();
// Decode the encrypted session ID from base 64.
$decoded = base64_decode($encryptedSessionId);
// Decrypt the string.
$decryptedSessionId = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $decoded, MCRYPT_MODE_CBC, $iv);
// Trim the whitespace from the end.
$session_id = rtrim($decryptedSessionId, "\0");
// Return it.
return $session_id;
}
public function _getIv() {
return md5($this->_getSalt());
}
public function _getSalt() {
return md5($this->drupal->drupalGetHashSalt());
}
}
dans :
class Session {
const SESS_CIPHER = 'aes-128-cbc';
/**
* Encrypts the session ID and returns it as a base 64 encoded string.
*
* @param $session_id
* @return string
*/
public function encrypt($session_id) {
// Get the MD5 hash salt as a key.
$key = $this->_getSalt();
// For an easy iv, MD5 the salt again.
$iv = $this->_getIv();
// Encrypt the session ID.
$ciphertext = openssl_encrypt($session_id, self::SESS_CIPHER, $key, $options=OPENSSL_RAW_DATA, $iv);
// Base 64 encode the encrypted session ID.
$encryptedSessionId = base64_encode($ciphertext);
// Return it.
return $encryptedSessionId;
}
/**
* Decrypts a base 64 encoded encrypted session ID back to its original form.
*
* @param $encryptedSessionId
* @return string
*/
public function decrypt($encryptedSessionId) {
// Get the Drupal hash salt as a key.
$key = $this->_getSalt();
// Get the iv.
$iv = $this->_getIv();
// Decode the encrypted session ID from base 64.
$decoded = base64_decode($encryptedSessionId, TRUE);
// Decrypt the string.
$decryptedSessionId = openssl_decrypt($decoded, self::SESS_CIPHER, $key, $options=OPENSSL_RAW_DATA, $iv);
// Trim the whitespace from the end.
$session_id = rtrim($decryptedSessionId, '\0');
// Return it.
return $session_id;
}
public function _getIv() {
$ivlen = openssl_cipher_iv_length(self::SESS_CIPHER);
return substr(md5($this->_getSalt()), 0, $ivlen);
}
public function _getSalt() {
return $this->drupal->drupalGetHashSalt();
}
}
Pour clarifier, le changement ci-dessus n'est pas une véritable conversion puisque les deux cryptages utilisent une taille de bloc différente et des données cryptées différentes. De plus, le remplissage par défaut est différent, MCRYPT_RIJNDAEL
ne prend en charge que les remplissages nuls non standard. @zaph
Notes supplémentaires (tirées des commentaires de @zaph) :
-
Rijndael 128 (
MCRYPT_RIJNDAEL_128
) est équivalent à AES Cependant Rijndael 256 ( MCRYPT_RIJNDAEL_256
) n'est pas AES-256 car le 256 spécifie une taille de bloc de 256 bits, tandis que le AES n'a qu'une seule taille de bloc : 128-bits. Donc, fondamentalement, Rijndael avec une taille de bloc de 256 bits ( MCRYPT_RIJNDAEL_256
) a été nommé par erreur en raison des choix de l mcrypt développeurs. @zaph
- Rijndael avec une taille de bloc de 256 bits peut être moins sûr qu'avec une taille de bloc de 128 bits, car ce dernier a fait l'objet de beaucoup plus d'examens et d'utilisations. Deuxièmement, l'interopérabilité est entravée par le fait que si AES est généralement disponible, Rijndael avec une taille de bloc de 256 bits ne l'est pas.
-
Le chiffrement avec différentes tailles de blocs pour Rijndael produit différentes données chiffrées.
Par exemple, MCRYPT_RIJNDAEL_256
(non équivalent à AES-256
) définit une variante différente du chiffrement par blocs de Rijndael avec une taille de 256 bits et une taille de clé basée sur la clé transmise, où aes-256-cbc
est Rijndael avec une taille de bloc de 128 bits et une taille de clé de 256 bits. Par conséquent, ils utilisent des tailles de bloc différentes, ce qui produit des données cryptées entièrement différentes, car mcrypt utilise le nombre pour spécifier la taille du bloc, alors qu'OpenSSL utilise le nombre pour spécifier la taille de la clé (AES n'a qu'une seule taille de bloc de 128 bits). Donc, AES est essentiellement Rijndael avec une taille de bloc de 128 bits et des tailles de clé de 128, 192 et 256 bits. Il est donc préférable d'utiliser AES, qui est appelé Rijndael 128 dans OpenSSL.