Conforme sugerido por @rqLizard , você pode usar funções openssl_encrypt
/ openssl_decrypt
PHP em vez disso, o que fornece uma alternativa muito melhor para implementar AES (The Advanced Encryption Standard) também conhecido como criptografia Rijndael.
De acordo com o seguinte comentário de Scott em php.net :
Se você estiver escrevendo código para criptografar / criptografar dados em 2015, deve usar openssl_encrypt()
e openssl_decrypt()
. A biblioteca subjacente ( libmcrypt
) foi abandonada desde 2007 e tem um desempenho muito pior do que o OpenSSL (que aproveitaAES-NI
de processadores modernos e é seguro para temporização de cache).
Além disso, MCRYPT_RIJNDAEL_256
não é AES-256
, é uma variante diferente da cifra de bloco Rijndael. Se você quiser AES-256
em mcrypt
, você tem que usar MCRYPT_RIJNDAEL_128
com uma chave de 32 bytes. O OpenSSL torna mais óbvio qual modo você está usando (ou seja, aes-128-cbc
vs aes-256-ctr
).
OpenSSL também usa preenchimento PKCS7 com modo CBC em vez do preenchimento de bytes NULL do mcrypt. Portanto, é mais provável que mcrypt torne seu código vulnerável a ataques oracle padding do que OpenSSL.
Finalmente, se você não está autenticando seus textos criptografados (Encrypt Then MAC), você está fazendo isso errado.
Leitura adicional:
Exemplos de código
Exemplo 1
AES Authenticated Encryption in GCM mode example for 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";
}
?>
Exemplo # 2
Exemplo de criptografia autenticada AES para 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";
}
?>
Exemplo # 3
Com base nos exemplos acima, alterei o código a seguir, que visa criptografar a id de sessão do usuário:
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());
}
}
para dentro:
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();
}
}
Para esclarecer, a alteração acima não é uma conversão verdadeira, pois as duas criptografias usam um tamanho de bloco diferente e dados criptografados diferentes. Além disso, o preenchimento padrão é diferente, MCRYPT_RIJNDAEL
suporta apenas preenchimento nulo não padrão. @zaph
Observações adicionais (dos comentários de @zaph):
- Rijndael 128 (
MCRYPT_RIJNDAEL_128
) é equivalente a AES , entretanto Rijndael 256 ( MCRYPT_RIJNDAEL_256
) não é AES-256, pois 256 especifica um tamanho de bloco de 256 bits, enquanto AES tem apenas um tamanho de bloco: 128 bits. Então, basicamente, Rijndael com um tamanho de bloco de 256 bits ( MCRYPT_RIJNDAEL_256
) foi nomeado por engano devido às escolhas dos desenvolvedores do mcrypt . @zaph
- Rijndael com um tamanho de bloco de 256 pode ser menos seguro do que com um tamanho de bloco de 128 bits porque o último teve muito mais análises e utilizações. Em segundo lugar, a interoperabilidade é prejudicada porque, embora o AES esteja geralmente disponível, o Rijndael com um tamanho de bloco de 256 bits não está.
A criptografia com tamanhos de bloco diferentes para Rijndael produz dados criptografados diferentes.
Por exemplo, MCRYPT_RIJNDAEL_256
(não equivalente a AES-256
) define uma variante diferente da cifra de bloco Rijndael com tamanho de 256 bits e um tamanho de chave baseado na chave passada, onde aes-256-cbc
é Rijndael com um tamanho de bloco de 128 bits com um tamanho de chave de 256 bits. Portanto, eles estão usando tamanhos de bloco diferentes que produzem dados criptografados totalmente diferentes, já que mcrypt usa o número para especificar o tamanho do bloco, onde o OpenSSL usa o número para especificar o tamanho da chave (AES só tem um tamanho de bloco de 128 bits). Então, basicamente, AES é Rijndael com um tamanho de bloco de 128 bits e tamanhos de chave de 128, 192 e 256 bits. Portanto, é melhor usar AES, que é chamado de Rijndael 128 no OpenSSL.
password_hash
e verificá-los compassword_verify
?