Seperti yang disarankan oleh @rqLizard , Anda dapat menggunakan openssl_encrypt
/ openssl_decrypt
fungsi PHP sebagai gantinya yang menyediakan alternatif yang jauh lebih baik untuk mengimplementasikan AES (The Advanced Encryption Standard) yang juga dikenal sebagai enkripsi Rijndael.
Sesuai komentar Scott berikut di php.net :
Jika Anda menulis kode untuk mengenkripsi / mengenkripsi data pada tahun 2015, Anda harus menggunakan openssl_encrypt()
dan openssl_decrypt()
. Pustaka yang mendasari ( libmcrypt
) telah ditinggalkan sejak 2007, dan berkinerja jauh lebih buruk daripada OpenSSL (yang memanfaatkan AES-NI
prosesor modern dan aman untuk pengaturan waktu cache).
Juga, MCRYPT_RIJNDAEL_256
bukan AES-256
, ini adalah varian berbeda dari cipher blok Rijndael. Jika Anda ingin AES-256
di mcrypt
, Anda harus menggunakan MCRYPT_RIJNDAEL_128
dengan kunci 32-byte. OpenSSL membuatnya lebih jelas mode mana yang Anda gunakan (yaitu aes-128-cbc
vs aes-256-ctr
).
OpenSSL juga menggunakan padding PKCS7 dengan mode CBC daripada padding byte NULL mcrypt. Dengan demikian, mcrypt lebih cenderung membuat kode Anda rentan terhadap serangan oracle padding daripada OpenSSL.
Terakhir, jika Anda tidak mengautentikasi ciphertext Anda (Encrypt Then MAC), Anda salah melakukannya.
Bacaan lebih lanjut:
Contoh kode
Contoh 1
Contoh Enkripsi Terautentikasi AES dalam mode GCM untuk 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";
}
?>
Contoh # 2
Contoh AES Authenticated Encryption untuk 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";
}
?>
Contoh # 3
Berdasarkan contoh di atas, saya telah mengubah kode berikut yang bertujuan untuk mengenkripsi id sesi pengguna:
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());
}
}
ke:
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();
}
}
Untuk memperjelas, perubahan di atas bukanlah konversi yang sebenarnya karena kedua enkripsi menggunakan ukuran blok yang berbeda dan data terenkripsi yang berbeda. Selain itu, padding default berbeda, MCRYPT_RIJNDAEL
hanya mendukung padding null non-standar. @faf
Catatan tambahan (dari komentar @zaph):
- Rijndael 128 (
MCRYPT_RIJNDAEL_128
) adalah setara dengan AES , namun Rijndael 256 ( MCRYPT_RIJNDAEL_256
) tidak AES-256 sebagai 256 menspesifikasikan ukuran blok 256-bit, sedangkan AES hanya memiliki satu ukuran blok: 128-bit. Jadi pada dasarnya Rijndael dengan ukuran blok 256-bit ( MCRYPT_RIJNDAEL_256
) telah keliru dinamai karena pilihan oleh pengembang mcrypt . @faf
- Rijndael dengan ukuran blok 256 mungkin kurang aman dibandingkan dengan ukuran blok 128-bit karena yang terakhir memiliki lebih banyak ulasan dan kegunaan. Kedua, interoperabilitas terhalang sementara AES umumnya tersedia, di mana Rijndael dengan ukuran blok 256-bit tidak.
Enkripsi dengan ukuran blok berbeda untuk Rijndael menghasilkan data terenkripsi yang berbeda.
Misalnya, MCRYPT_RIJNDAEL_256
(tidak setara dengan AES-256
) mendefinisikan varian berbeda dari cipher blok Rijndael dengan ukuran 256-bit dan ukuran kunci berdasarkan kunci yang diteruskan, di mana aes-256-cbc
Rijndael dengan ukuran blok 128-bit dengan ukuran kunci 256-bit. Oleh karena itu mereka menggunakan ukuran blok yang berbeda yang menghasilkan data terenkripsi yang sama sekali berbeda karena mcrypt menggunakan nomor tersebut untuk menentukan ukuran blok, di mana OpenSSL menggunakan nomor tersebut untuk menentukan ukuran kunci (AES hanya memiliki satu ukuran blok 128-bit). Jadi pada dasarnya AES adalah Rijndael dengan ukuran blok 128-bit dan ukuran kunci 128, 192 dan 256 bit. Oleh karena itu lebih baik menggunakan AES, yang disebut Rijndael 128 di OpenSSL.
password_hash
dan memverifikasinyapassword_verify
?