Come suggerito da @rqLizard , puoi invece usare le funzioni openssl_encrypt
/ openssl_decrypt
PHP che forniscono un'alternativa molto migliore per implementare AES (The Advanced Encryption Standard) noto anche come crittografia Rijndael.
Secondo il seguente commento di Scott su php.net :
Se stai scrivendo codice per crittografare / crittografare i dati nel 2015, dovresti usare openssl_encrypt()
e openssl_decrypt()
. La libreria sottostante ( libmcrypt
) è stata abbandonata dal 2007 e ha prestazioni di gran lunga peggiori di OpenSSL (che utilizzaAES-NI
processori moderni ed è sicura per il timing della cache).
Inoltre, MCRYPT_RIJNDAEL_256
non lo è AES-256
, è una variante diversa del cifrario a blocchi Rijndael. Se si desidera AES-256
in mcrypt
, è necessario utilizzare MCRYPT_RIJNDAEL_128
con una chiave a 32 byte. OpenSSL rende più ovvio quale modalità stai utilizzando (cioè aes-128-cbc
vs aes-256-ctr
).
OpenSSL utilizza anche il riempimento PKCS7 con la modalità CBC piuttosto che il riempimento dei byte NULL di mcrypt. Pertanto, è più probabile che mcrypt renda il tuo codice vulnerabile agli attacchi di padding Oracle rispetto a OpenSSL.
Infine, se non stai autenticando i tuoi testi cifrati (Encrypt Then MAC), stai sbagliando.
Ulteriore lettura:
Esempi di codice
Esempio 1
Esempio di crittografia autenticata AES in modalità GCM per 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";
}
?>
Esempio n. 2
Esempio di crittografia autenticata AES per 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";
}
?>
Esempio n. 3
Sulla base degli esempi precedenti, ho modificato il seguente codice che mira a crittografare l'ID di sessione dell'utente:
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());
}
}
in:
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();
}
}
Per chiarire, la modifica di cui sopra non è una vera conversione poiché le due crittografie utilizzano una dimensione di blocco diversa e dati crittografati diversi. Inoltre, il riempimento predefinito è diverso, MCRYPT_RIJNDAEL
supporta solo il riempimento nullo non standard. @zaph
Note aggiuntive (dai commenti di @zaph):
- Rijndael 128 (
MCRYPT_RIJNDAEL_128
) è equivalente ad AES , tuttavia Rijndael 256 ( MCRYPT_RIJNDAEL_256
) non è AES-256 poiché 256 specifica una dimensione del blocco di 256 bit, mentre AES ha solo una dimensione del blocco: 128 bit. Quindi fondamentalmente Rijndael con una dimensione del blocco di 256 bit ( MCRYPT_RIJNDAEL_256
) è stato erroneamente chiamato a causa delle scelte degli sviluppatori di mcrypt . @zaph
- Rijndael con una dimensione del blocco di 256 potrebbe essere meno sicuro rispetto a una dimensione del blocco di 128 bit perché quest'ultimo ha avuto molte più revisioni e utilizzi. In secondo luogo, l'interoperabilità è ostacolata dal fatto che mentre AES è generalmente disponibile, mentre Rijndael con una dimensione del blocco di 256 bit non lo è.
La crittografia con blocchi di dimensioni diverse per Rijndael produce dati crittografati diversi.
Ad esempio, MCRYPT_RIJNDAEL_256
(non equivalente a AES-256
) definisce una variante diversa del codice a blocchi Rijndael con dimensione di 256 bit e una dimensione della chiave basata sulla chiave passata, dove aes-256-cbc
è Rijndael con una dimensione del blocco di 128 bit con una dimensione della chiave di 256 bit. Pertanto stanno utilizzando blocchi di dimensioni diverse che producono dati crittografati completamente diversi poiché mcrypt utilizza il numero per specificare la dimensione del blocco, dove OpenSSL ha utilizzato il numero per specificare la dimensione della chiave (AES ha solo una dimensione del blocco di 128 bit). Quindi fondamentalmente AES è Rijndael con una dimensione del blocco di 128 bit e dimensioni della chiave di 128, 192 e 256 bit. Quindi è meglio usare AES, che si chiama Rijndael 128 in OpenSSL.
password_hash
e verificarli conpassword_verify
?