openssl_encrypt openssl_decrypt encrypt ejemplo decrypt cbc php encryption cryptography aes encryption-symmetric

openssl_decrypt - PHP AES cifra/descifra



openssl_encrypt (6)

Encontré un ejemplo para en / decodificar cadenas en PHP. Al principio se ve muy bien pero no funcionará :-(

Alguien sabe cual es el problema?

$Pass = "Passwort"; $Clear = "Klartext"; $crypted = fnEncrypt($Clear, $Pass); echo "Encrypted: ".$crypted."</br>"; $newClear = fnDecrypt($crypted, $Pass); echo "Decrypted: ".$newClear."</br>"; function fnEncrypt($sValue, $sSecretKey) { return trim(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $sSecretKey, $sDecrypted, MCRYPT_MODE_ECB, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND)))); } function fnDecrypt($sValue, $sSecretKey) { return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $sSecretKey, base64_decode($sEncrypted), MCRYPT_MODE_ECB, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND))); }

El resultado es:

Encriptado: boKRNTYYNp7AiOvY1CidqsAn9wX4ufz/D9XrpjAOPk8=

Descifrado: —‚(ÑÁ ^ yË~F''¸®Ó–í œð2Á_B‰Â—


Utilice una biblioteca de cifrado PHP segura existente

En general, es una mala idea escribir su propia criptografía a menos que tenga experiencia rompiendo las implementaciones de criptografía de otras personas.

Ninguno de los ejemplos aquí autentica el texto cifrado , lo que los hace vulnerables a los ataques de reescritura de bits.

Si puede instalar extensiones PECL, libsodium es aún mejor

<?php // PECL libsodium 0.2.1 and newer /** * Encrypt a message * * @param string $message - message to encrypt * @param string $key - encryption key * @return string */ function safeEncrypt($message, $key) { $nonce = /Sodium/randombytes_buf( /Sodium/CRYPTO_SECRETBOX_NONCEBYTES ); return base64_encode( $nonce. /Sodium/crypto_secretbox( $message, $nonce, $key ) ); } /** * Decrypt a message * * @param string $encrypted - message encrypted with safeEncrypt() * @param string $key - encryption key * @return string */ function safeDecrypt($encrypted, $key) { $decoded = base64_decode($encrypted); $nonce = mb_substr($decoded, 0, /Sodium/CRYPTO_SECRETBOX_NONCEBYTES, ''8bit''); $ciphertext = mb_substr($decoded, /Sodium/CRYPTO_SECRETBOX_NONCEBYTES, null, ''8bit''); return /Sodium/crypto_secretbox_open( $ciphertext, $nonce, $key ); }

Luego para probarlo:

<?php // This refers to the previous code block. require "safeCrypto.php"; // Do this once then store it somehow: $key = /Sodium/randombytes_buf(/Sodium/CRYPTO_SECRETBOX_KEYBYTES); $message = ''We are all living in a yellow submarine''; $ciphertext = safeEncrypt($message, $key); $plaintext = safeDecrypt($ciphertext, $key); var_dump($ciphertext); var_dump($plaintext);

Esto se puede usar en cualquier situación en la que transfiera datos al cliente (por ejemplo, cookies cifradas para sesiones sin almacenamiento en el servidor, parámetros de URL encriptados, etc.) con un grado razonablemente alto de certeza de que el usuario final no puede descifrar o manipular de manera confiable con eso.

Dado que libsodium es multiplataforma , esto también facilita la comunicación con PHP desde, por ejemplo, applets de Java o aplicaciones móviles nativas.

Nota: si específicamente necesita agregar cookies encriptadas con libsodium a su aplicación, mi empleador Paragon Initiative Enterprises está desarrollando una biblioteca llamada Halite que hace todo esto por usted.


Para información, MCRYPT_MODE_ECB no usa IV (vector de inicialización). El modo ECB divide su mensaje en bloques y cada bloque se cifra por separado. Realmente no lo recomiendo

El modo CBC usa IV para hacer que cada mensaje sea único. Se recomienda CBC y se debe usar en lugar de ECB.

Ejemplo:

<?php $password = "myPassword_!"; $messageClear = "Secret message"; // 32 byte binary blob $aes256Key = hash("SHA256", $password, true); // for good entropy (for MCRYPT_RAND) srand((double) microtime() * 1000000); // generate random iv $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC), MCRYPT_RAND); $crypted = fnEncrypt($messageClear, $aes256Key); $newClear = fnDecrypt($crypted, $aes256Key); echo "IV: <code>".$iv."</code><br/>". "Encrypred: <code>".$crypted."</code><br/>". "Decrypred: <code>".$newClear."</code><br/>"; function fnEncrypt($sValue, $sSecretKey) { global $iv; return rtrim(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $sSecretKey, $sValue, MCRYPT_MODE_CBC, $iv)), "/0/3"); } function fnDecrypt($sValue, $sSecretKey) { global $iv; return rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $sSecretKey, base64_decode($sValue), MCRYPT_MODE_CBC, $iv), "/0/3"); }

Tienes que almacenar el IV para decodificar cada mensaje (IV no es secreto). Cada mensaje es único porque cada mensaje tiene una IV única.


Pocas cosas importantes a tener en cuenta con el cifrado AES:

  1. Nunca use texto sin formato como clave de cifrado. Siempre hash la tecla de texto sin formato y luego utilizar para el cifrado.
  2. Utilice siempre Random IV (vector de inicialización) para cifrado y descifrado. La verdadera aleatorización es importante.
  3. Como se mencionó anteriormente, no use el modo ecb , use CBC lugar.

Si no desea usar una gran dependencia para algo solucionable en 15 líneas de código, use las funciones integradas de OpenSSL . La mayoría de las instalaciones de PHP vienen con OpenSSL, que proporciona cifrado AES rápido, compatible y seguro en PHP. Bueno, es seguro siempre que sigas las mejores prácticas.

El siguiente código:

  • usa AES256 en modo CBC
  • es compatible con otras implementaciones de AES, pero no con mcrypt , ya que mcrypt usa PKCS # 5 en lugar de PKCS # 7.
  • genera una clave a partir de la contraseña proporcionada utilizando SHA256
  • genera un hash hmac de los datos encriptados para la verificación de integridad
  • genera una IV aleatoria para cada mensaje
  • antepone el IV (16 bytes) y el hash (32 bytes) al texto cifrado
  • debería ser bastante seguro

IV es una información pública y debe ser aleatoria para cada mensaje. El hash garantiza que los datos no se hayan alterado.

function encrypt($plaintext, $password) { $method = "AES-256-CBC"; $key = hash(''sha256'', $password, true); $iv = openssl_random_pseudo_bytes(16); $ciphertext = openssl_encrypt($plaintext, $method, $key, OPENSSL_RAW_DATA, $iv); $hash = hash_hmac(''sha256'', $ciphertext, $key, true); return $iv . $hash . $ciphertext; } function decrypt($ivHashCiphertext, $password) { $method = "AES-256-CBC"; $iv = substr($ivHashCiphertext, 0, 16); $hash = substr($ivHashCiphertext, 16, 32); $ciphertext = substr($ivHashCiphertext, 48); $key = hash(''sha256'', $password, true); if (hash_hmac(''sha256'', $ciphertext, $key, true) !== $hash) return null; return openssl_decrypt($ciphertext, $method, $key, OPENSSL_RAW_DATA, $iv); }

Uso:

$encrypted = encrypt(''Plaintext string.'', ''password''); // this yields a binary string echo decrypt($encrypted, ''password''); // decrypt($encrypted, ''wrong password'') === null


Si está utilizando MCRYPT_RIJNDAEL_128, pruebe rtrim($output, "/0/3") . Si la longitud de la cadena es menor que 16, la función de descifrado devolverá una cadena con una longitud de 16 caracteres, agregando 03 al final.

Puede verificar esto fácilmente, por ejemplo, intentando:

$string = "TheString"; $decrypted_string = decrypt_function($stirng, $key); echo bin2hex($decrypted_string)."=".bin2hex("TheString");


$sDecrypted y $sEncrypted no estaban definidos en su código. Vea una solución que funciona (¡ pero no es segura! ):

¡DETENER!

¡Este ejemplo es inseguro! ¡No lo uses!

$Pass = "Passwort"; $Clear = "Klartext"; $crypted = fnEncrypt($Clear, $Pass); echo "Encrypred: ".$crypted."</br>"; $newClear = fnDecrypt($crypted, $Pass); echo "Decrypred: ".$newClear."</br>"; function fnEncrypt($sValue, $sSecretKey) { return rtrim( base64_encode( mcrypt_encrypt( MCRYPT_RIJNDAEL_256, $sSecretKey, $sValue, MCRYPT_MODE_ECB, mcrypt_create_iv( mcrypt_get_iv_size( MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB ), MCRYPT_RAND) ) ), "/0" ); } function fnDecrypt($sValue, $sSecretKey) { return rtrim( mcrypt_decrypt( MCRYPT_RIJNDAEL_256, $sSecretKey, base64_decode($sValue), MCRYPT_MODE_ECB, mcrypt_create_iv( mcrypt_get_iv_size( MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB ), MCRYPT_RAND ) ), "/0" ); }

Pero hay otros problemas en este código que lo hacen inseguro, en particular, el uso de ECB (que no es un modo de encriptación , solo un bloque de construcción sobre el cual se pueden definir los modos de encriptación). Vea la respuesta de Fab Sa para una solución rápida de los peores problemas y la respuesta de Scott sobre cómo hacerlo bien.