Solución:
Antes de hacer nada más, intente comprender la diferencia entre cifrado y autenticacióny por qué probablemente quieras cifrado autenticado en lugar de solo cifrado.
Para implementar el cifrado autenticado, desea cifrar y luego MAC. ¡El orden de cifrado y autenticación es muy importante! Una de las respuestas existentes a esta pregunta cometió este error; al igual que muchas bibliotecas de criptografía escritas en PHP.
Debe evitar implementar su propia criptografía y, en su lugar, utilizar una biblioteca segura escrita y revisada por expertos en criptografía.
Actualización: PHP 7.2 ahora proporciona libsodium! Para mayor seguridad, actualice sus sistemas para usar PHP 7.2 o superior y solo siga los consejos de libsodium en esta respuesta.
Utilice libsodium si tiene acceso a PECL (o sodium_compat si desea libsodium sin PECL); de lo contrario…
Utilice defuse / php-encryption; ¡no enrolle su propia criptografía!
Ambas bibliotecas vinculadas anteriormente facilitan y facilitan la implementación de cifrado autenticado en sus propias bibliotecas.
Si aún desea escribir e implementar su propia biblioteca de criptografía, en contra de la sabiduría convencional de todos los expertos en criptografía en Internet, estos son los pasos que debe seguir.
Cifrado:
- Cifre usando AES en modo CTR. También puede usar GCM (que elimina la necesidad de un MAC separado). Además, ChaCha20 y Salsa20 (proporcionados por libsodium) son cifrados de flujo y no necesitan modos especiales.
- A menos que elija GCM arriba, debe autenticar el texto cifrado con HMAC-SHA-256 (o, para los cifrados de flujo, Poly1305; la mayoría de las API de libsodium lo hacen por usted). ¡El MAC debe cubrir tanto el IV como el texto cifrado!
Descifrado:
- A menos que se utilice Poly1305 o GCM, vuelva a calcular el MAC del texto cifrado y compárelo con el MAC que se envió utilizando
hash_equals()
. Si falla, aborta. - Descifra el mensaje.
Otras consideraciones de diseño:
- No comprima nada nunca. El texto cifrado no es comprimible; Comprimir el texto sin formato antes del cifrado puede dar lugar a fugas de información (por ejemplo, CRIME e INCUMPLIMIENTO en TLS).
- Asegúrate de usar
mb_strlen()
ymb_substr()
, utilizando el'8bit'
modo de juego de caracteres para evitarmbstring.func_overload
cuestiones. - Los IV deben generarse utilizando un CSPRNG; Si estas usando
mcrypt_create_iv()
, NO UTILICEMCRYPT_RAND
!- También echa un vistazo a random_compat.
- A menos que esté utilizando una construcción AEAD, ¡SIEMPRE encripte y luego MAC!
bin2hex()
,base64_encode()
, etc. pueden filtrar información sobre su cifrado keys a través del tiempo de caché. Evítelos si es posible.
Incluso si sigue los consejos que se dan aquí, muchas cosas pueden salir mal con la criptografía. Siempre haga que un experto en criptografía revise su implementación. Si no tiene la suerte de ser amigo personal de un estudiante de criptografía en su universidad local, siempre puede probar el foro Cryptography Stack Exchange para obtener consejos.
Si necesita un análisis profesional de su implementación, siempre puede contratar a un equipo acreditado de consultores de seguridad para revisar su código de criptografía PHP (divulgación: mi empleador).
Importante: cuándo no utilizar el cifrado
No cifrar contraseñas. Tú quieres picadillo en su lugar, utilizando uno de estos algoritmos de hash de contraseña:
- Argón2
- scrypt
- bcrypt
- PBKDF2-SHA256 con 86.000 iteraciones
Nunca use una función hash de propósito general (MD5, SHA256) para el almacenamiento de contraseñas.
No cifre los parámetros de URL. Es la herramienta incorrecta para el trabajo.
Ejemplo de cifrado de cadenas PHP con Libsodium
Si está en PHP <7.2 o no tiene libsodium instalado, puede usar sodium_compat para lograr el mismo resultado (aunque más lento).
Luego, para probarlo:
Halita - Libsodium más fácil
Uno de los proyectos en los que he estado trabajando es una biblioteca de cifrado llamada Halite, cuyo objetivo es hacer que libsodium sea más fácil e intuitivo.
Libsodium maneja toda la criptografía subyacente.
Ejemplo con defuse / php-encryption
Nota: Crypto::encrypt()
devuelve una salida con codificación hexadecimal.
Gestión de claves de cifrado
Si tiene la tentación de utilizar una "contraseña", deténgase ahora mismo. Necesita un cifrado aleatorio de 128 bits key, no una contraseña memorable humana.
Puede almacenar un cifrado key para uso a largo plazo así:
$storeMe = bin2hex($key);
Y, a pedido, puede recuperarlo así:
$key = hex2bin($storeMe);
I fuertemente recomiendo almacenar un archivo generado aleatoriamente key para uso a largo plazo en lugar de cualquier tipo de contraseña, ya que key (o para derivar el key).
Si está utilizando la biblioteca de Defuse:
$string = $keyObject->saveToAsciiSafeString()
$loaded = Key::loadFromAsciiSafeString($string);
"Pero yo De Verdad desea utilizar una contraseña ".
Esa es una mala idea, pero está bien, aquí se explica cómo hacerlo de forma segura.
Primero, genere un aleatorio key y guárdelo en una constante.
/**
* Replace this with your own salt!
* Use bin2hex() then add x before every 2 hex characters, like so:
*/
define('MY_PBKDF2_SALT', "x2dxb7x68x1ax28x15xbex06x33xa0x7ex0ex8fx79xd5xdf");
Tenga en cuenta que está agregando trabajo adicional y podría usar esta constante como el key ¡y ahórrese muchos dolores de cabeza!
Luego use PBKDF2 (así) para obtener un cifrado adecuado key de su contraseña en lugar de cifrar con su contraseña directamente.
/**
* Get an AES key from a static password and a secret salt
*
* @param string $password Your weak password here
* @param int $keysize Number of bytes in encryption key
*/
function getKeyFromPassword($password, $keysize = 16)
return hash_pbkdf2(
'sha256',
$password,
MY_PBKDF2_SALT,
100000, // Number of iterations
$keysize,
true
);
No use simplemente una contraseña de 16 caracteres. Tu cifrado key se romperá cómicamente.
Llego tarde a la fiesta, pero al buscar la forma correcta de hacerlo, encontré esta página, fue uno de los mejores resultados de búsqueda de Google, por lo que me gustaría compartir mi opinión sobre el problema, que considero que es actualizado en el momento de escribir este artículo (principios de 2017). Desde PHP 7.1.0 el mcrypt_decrypt
y mcrypt_encrypt
va a quedar obsoleto, por lo que la creación de un código a prueba de futuro debería usar openssl_encrypt y openssl_decrypt
Puedes hacer algo como:
$string_to_encrypt="Test";
$password="password";
$encrypted_string=openssl_encrypt($string_to_encrypt,"AES-128-ECB",$password);
$decrypted_string=openssl_decrypt($encrypted_string,"AES-128-ECB",$password);
Importante: Utiliza el modo ECB, que no es seguro. Si desea una solución simple sin tomar un curso intensivo de ingeniería criptográfica, no la escriba usted mismo, solo use una biblioteca.
También puede utilizar cualquier otro método de astillado, según sus necesidades de seguridad. Para conocer los métodos de astillado disponibles, consulte la función openssl_get_cipher_methods.
Qué no hacer
ADVERTENCIA:
Esta respuesta usa ECB. ECB no es un modo de cifrado, es solo un componente básico. El uso de ECB como se demuestra en esta respuesta en realidad no cifra el string de forma segura. No utilice ECB en su código. Vea la respuesta de Scott para una buena solución.
Lo tengo yo mismo. De hecho, encontré una respuesta en Google y modifiqué algo. Sin embargo, el resultado es completamente inseguro.
[email protected]#$%^&*");
$string = "This is the original data string!";
echo $encrypted = encrypt($string, ENCRYPTION_KEY);
echo "
";
echo $decrypted = decrypt($encrypted, ENCRYPTION_KEY);
/**
* Returns an encrypted & utf8-encoded
*/
function encrypt($pure_string, $encryption_key)
$iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$encrypted_string = mcrypt_encrypt(MCRYPT_BLOWFISH, $encryption_key, utf8_encode($pure_string), MCRYPT_MODE_ECB, $iv);
return $encrypted_string;
/**
* Returns decrypted original string
*/
function decrypt($encrypted_string, $encryption_key)
$iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$decrypted_string = mcrypt_decrypt(MCRYPT_BLOWFISH, $encryption_key, $encrypted_string, MCRYPT_MODE_ECB, $iv);
return $decrypted_string;
?>
Tienes la opción de añadir valor a nuestro contenido asistiendo con tu experiencia en los comentarios.