Cifrar y descifrar información con PHP

En este artículo te voy a mostrar cómo encriptar y desencriptar datos usando PHP, para mantener los datos seguros. Veremos cómo:

  • Cifrar datos
  • Descifrar datos
  • Cifrar datos usando la contraseña de un usuario
  • Descifrar datos usando la contraseña de un usuario

Estos dos últimos ejemplos funcionan muy bien para cuando queremos asegurar la información incluso para los desarrolladores de la aplicación.

Recuerda que encriptar es distinto a hashear; porque cuando encriptamos un valor con PHP lo hacemos de esa manera para desencriptarlo más tarde. En cambio, al hashear una contraseña, su valor no es reversible.

La librería que vamos a usar para encriptar y desencriptar datos en PHP se llama php-encryption y su repositorio en GitHub lo puedes ver aquí.

Nota: voy a usar encriptar y cifrar como sinónimos para este post, al igual que desencriptar y descifrar.

Instalar php-encryption

En la consola ejecuta:

composer require defuse/php-encryption

Si no tienes composer mira aquí cómo instalarlo, y si ya tienes un proyecto iniciado, mira este post para adaptarlo.

Nota: si quieres comprobar que estás descargando el archivo real y que nadie lo interceptó en el camino puedes descargar el archivo phar y comprobar las firmas.

Después simplemente incluye el autoload (o el phar) usando:

require_once "vendor/autoload.php"

Generar clave de encriptación

Para poder cifrar y descifrar, necesitamos una clave de encriptación aleatoria, segura y lo suficientemente larga.

La librería trae consigo un ejecutable ubicado en vendor/bin/generate-defuse-key que genera esta clave aleatoria y segura.

Navega hasta esa ruta y ejecuta el binario, sin argumentos. Así:

generate-defuse-key

Eso te dará una clave totalmente distinta a la mía. Ahora guarda esa clave en un lugar seguro y accesible, es decir:

  1. Un lugar al que solo tú tengas acceso (no otros usuarios)
  2. Un lugar al que puedas acceder, por ejemplo una base de datos o un archivo de texto

Nota: recuerda que cualquiera que tenga acceso a esta clave podrá descifrar y cifrar; así que guárdala bien, imagina que son las llaves de la puerta que lleva a la habitación en donde está la información encriptada.

Cifrar / encriptar datos

Ahora que ya tenemos la clave, vamos a cifrar datos. Una vez cifrados podemos guardarlos en una base de datos o en cualquier otro lugar.

Por favor veamos este ejemplo de encriptación de datos con PHP:

Como ves, la clave está en un archivo de texto. De nuevo lo digo, este archivo debe estar seguro y puede ser guardado en otro lugar.

Estamos obteniendo su contenido con file_get_contents; después creamos una clave (porque debemos crear una clave a partir de la cadena ascii que guardamos) con loadFromASciiSafeString.

El cifrado se ve en la línea 21, ya que invocamos a Crypto::encrypt($mensaje, $clave). Eso devolverá una cadena cifrada que ya podemos guardar en cualquier medio o base de datos.

Descifrar datos

Ahora veamos el proceso inverso: descifrar datos que previamente ciframos.

Vamos a necesitar la misma clave que usamos para cifrar / encriptar. Veamos el código para descifrar datos con PHP, y abajo lo explico:

El proceso de cargar la clave es el mismo. Ahora invocamos al método decrypt($mensajeCifrado, $clave)

Este método va a lanzar una excepción de tipo WrongKeyOrModifiedCiphertextException en caso de que la clave sea errónea o los datos hayan sido modificados (pues si alguien modifica la cadena encriptada, se va a detectar).

Si esta excepción ocurre, puede que alguien haya intentado modificar los datos así que ten cuidado. También puede ser porque usaste una clave errónea; fíjate bien.

Encriptando y desencriptando

Ahora veamos los ejemplos ejecutándose:

Ejemplo de uso de php encryption

Cifrar datos con clave de usuario

Este escenario es el que más me gusta, porque así cada usuario protege sus datos y aunque un atacante robe los datos, tendrá que obtener la clave de cada uno de los usuarios.

1 – Registro de usuario

Por cierto, este método calcula el sha256 de la clave del usuario; y si la guardamos por ahí, encriptar será en vano. Es decir, simplemente por ninguna razón (porque las coincidencias existen) guardes el sha256 de las contraseñas; ya sea en logs, en bases de datos o en cualquier otro lugar.

Basta de charlas, veamos el código:

Estoy simplificando mucho las cosas. Tenemos la contraseña del usuario en texto plano, esa contraseña debe ser guardada con el nombre o correo del usuario, así como normalmente se hace.

Después estamos creando una clave del usuario a partir de su contraseña; esa clave también la debemos guardar por ahí. En este caso la estoy imprimiendo.

La clave debe quedar ligada al usuario.

2 – Cuando el usuario inicia sesión

Ahora, cuando el usuario hace login, comprobamos su contraseña y hacemos todo el proceso que hacemos en un login.

En caso de que la contraseña coincida, obtenemos su clave de la base de datos (la cual fue bloqueada con su contraseña) y la desbloqueamos con su contraseña.

El desbloqueo es un poco lento, así que es mejor guardar la clave desbloqueada en un almacenamiento temporal como la sesión.

Recuerda que la clave sin desbloquear debería ser obtenida de la base de datos; yo la pongo ahí por simplicidad.

3 – Cifrar datos con clave de usuario

La clave está en la sesión; así que para cifrar y descifrar datos la tomamos de ahí y llamamos al método encrypt como en los otros ejemplos.

Los datos encriptados ya podemos guardarlos, y nadie tendrá acceso a ellos, solo el usuario que conoce la contraseña.

Fíjate que la contraseña en texto plano ya no se usa aquí; solo se usó para desbloquear la clave del usuario.

4 – Descifrar datos con clave de usuario

Para descifrar es lo mismo, pero con el método decrypt. Es importante mencionar que si la clave o los datos son incorrectos, se producirá una excepción.

A los datos descifrados los puedes mostrar o usarlos.

Conclusiones y vistazo general

No te confundas; en los primeros ejemplos ciframos y desciframos con una clave general; y con que alguien tuviera esa clave, podría descifrar y cifrar a gusto.

En los ejemplos con el usuario, la clave se genera en el registro, se guarda y se desbloquea únicamente con la contraseña del usuario.

Recuerda que en el caso del usuario debes destruir la sesión con session_destroy() ya que si no, alguien podría acceder a la clave incluso después de que el usuario haya cerrado la sesión.

Por cierto, en los ejemplos simplifiqué muchas cosas pero fue para hacer esto más comprensivo.

Pronto traeré un ejemplo aplicando todo lo visto aquí; para que veas que realmente funciona.

Si quieres ver el repositorio en GitHub lo dejo aquí.