Criptografía hexadecimal con PHP.
Resumen.
En este interesante artículo vamos a hablar de seguridad, y aunque vamos a hacer referencia a las claves, contraseñas o password fundamentalmente, no solo la criptografía con PHP (y otros lenguajes) es usada para tales fines, también podemos obtener valores criptográficos para un archivo, por citar un ejemplo.Artículo.
Antes de entrar en la materia propiamente dicha es preciso aclarar ciertos conceptos que muchas veces, incluso en este mismo sitio Web, hemos usado de manera indistinta. En términos formales no es lo mismo codificar que criptografiar.
La diferencia entre uno y otro estriba en que por codificar se entiende una transformación del significado, mientras que por criptografiar se entiende una transformación de los caracteres que tienen un significado concreto.
Por ejemplo, como forma de codificación, en alguna película de espías hemos visto como uno le dice a otro: “Este año está haciendo mucho calor”; y el otro responde: “Sí, pero no tanto como el año pasado”. En este caso, lo de menos es el calor, lo importante es identificar si el contacto entre esas personas es legítimo, los dos conocen la pregunta y la respuesta, ese conocimiento implica la legitimidad del contacto.
La criptografía es diferente, por ejemplo, yo puedo representar el PIN de mi tarjeta de crédito como “aecb” que representa al PIN real “1532”.
Donde lo que hacemos es sustituir (función o regla criptográfica) los números “1234567890” por “abcdefghij” respectivamente. Es una forma criptográfica muy básica y poco segura, pero perfectamente útil para entender el concepto de criptografía.
Hecha esta diferenciación, cabe hacer otra dentro de la propia criptografía, y es que el método de transformación sea bidireccional o unidireccional. Es decir, el valor original se convierte en un valor criptografiado, y del valor criptografiado podemos volver al valor original. O por el contrario, el valor original se transforma en un valor criptografiado que no nos permite volver al valor original.
La pura lógica nos puede decir que la criptografía unidireccional no tiene sentido o es inútil, y que solo tiene sentido la criptografía bidireccional, pero caeríamos en un tremendo error, cada una tiene sus ventajas y cómo no, sus inconvenientes.
En este artículo creamos un método criptográfico bidireccional para guardar la clave de acceso de nuestros usuarios sin que esta sea reconocible para el personal técnico que manipula la tabla de datos de control de acceso a un sitio Web.
Este método bidireccional tiene una ventaja, y es que el usuario puede recuperar su clave de acceso. En el caso de los métodos unidireccionales, el usuario nunca puede recuperar su clave de acceso.
No poder recuperar la clave de acceso le da a las compañías la seguridad de que la clave solo la puede conocer el usuario, nadie, tan siquiera el personal técnico puede saber que clave se esconde tras un valor criptografiado. Esto tiene un valor legal para las compañías tecnológicas de tremenda importancia, dado que las exime de responsabilidad penal ante las posibles violaciones a la privacidad.
Como no se puede recuperar la clave, cuando un usuario la pierde, solo tiene una opción, introducir una nueva. Esto genera un problema para el usuario cuando esta identificado en varios dispositivos, y es que al cambiar la clave deja de estar identificado en los demás dispositivos, con lo que más de una vez (a mí me ha pasado), al tratar de identificarte en un nuevo dispositivo, si no recuerdas la última clave guardada, vuelves a tener que introducir otra nueva, y vuelta a empezar con la identificación en los demás dispositivos.
Con esto, queremos poner de manifiesto que la decisión de tener un sitio Web con claves o password recuperables o no recuperables supone un compromiso para el propietario de un sitio Web. Siendo muy importante esta decisión, cada cual debe evaluar la importancia de la comodidad para el usuario o la garantía legal de protección de la privacidad.
Contextualizado el asunto criptográfico y de codificación, vamos ya directos al tema sobre cómo materializar esto en PHP.
PHP tiene un buen número de opciones a la hora de criptografiar valores en código hexadecimal, una de las mas usadas es la función md5(), que toma la siguiente forma:
Para abc123 devuelve e99a18c428cb38d5f260853678922e03
Pero, como hemos dicho PHP no solo tiene la función md5(), que aplica el algoritmo criptográfico del mismo nombre “md5”, tiene otros muchos algoritmos, a los que podemos acceder mediante la función hash_algos(), que pueden ser mas o menos (algoritmos) según que versión de PHP tengas instalada. Para acceder a nuestros algoritmos criptográficos podemos usar la siguiente sintaxis que nos los devuelve en un array el conjunto del algoritmos criptográficos disponibles en nuestro servidor:
Mediante un bucle foreach podemos aplicar todos estos algoritmos a un mismo password y ver el resultado que obtenemos, el código sería el siguiente:
Respecto a la función hash() que aplica algoritmos, indicar que PHP tiene funciones especificas para aplicar un cierto algoritmo, como son la md5(), sha1, crc32, y sha256. En estas funciones se ha encontrado una discrepancia entre los valores aportados por la función y el valor aportado por hash() para ese algoritmo. Estos temas aparecen comentados en ingles en la página oficial.
Cabe comentar que se puede pensar que todas las criptografías en hexadecimal son unidireccionales, lo cual no es cierto, se puede codificar en hexadecimal de forma bidireccional, como puede verse en las funciones aquí expuestas. Que una codificación sea o no de doble sentido no esta vinculado al código de transformación (hexadecimal en este caso), está vinculado a la ecuación o regla de transformación.
Por último, y como comentamos en el resumen, no solo se puede codificar una cadena o string, también podemos codificar archivos. Sin entrar en muchas pretensiones vamos a presentar la función md5_file().
Dicho esto, cerramos este artículo, un poco complejo, pero espero que os haya resultado interesante.
La diferencia entre uno y otro estriba en que por codificar se entiende una transformación del significado, mientras que por criptografiar se entiende una transformación de los caracteres que tienen un significado concreto.
Por ejemplo, como forma de codificación, en alguna película de espías hemos visto como uno le dice a otro: “Este año está haciendo mucho calor”; y el otro responde: “Sí, pero no tanto como el año pasado”. En este caso, lo de menos es el calor, lo importante es identificar si el contacto entre esas personas es legítimo, los dos conocen la pregunta y la respuesta, ese conocimiento implica la legitimidad del contacto.
La criptografía es diferente, por ejemplo, yo puedo representar el PIN de mi tarjeta de crédito como “aecb” que representa al PIN real “1532”.
Donde lo que hacemos es sustituir (función o regla criptográfica) los números “1234567890” por “abcdefghij” respectivamente. Es una forma criptográfica muy básica y poco segura, pero perfectamente útil para entender el concepto de criptografía.
Hecha esta diferenciación, cabe hacer otra dentro de la propia criptografía, y es que el método de transformación sea bidireccional o unidireccional. Es decir, el valor original se convierte en un valor criptografiado, y del valor criptografiado podemos volver al valor original. O por el contrario, el valor original se transforma en un valor criptografiado que no nos permite volver al valor original.
La pura lógica nos puede decir que la criptografía unidireccional no tiene sentido o es inútil, y que solo tiene sentido la criptografía bidireccional, pero caeríamos en un tremendo error, cada una tiene sus ventajas y cómo no, sus inconvenientes.
En este artículo creamos un método criptográfico bidireccional para guardar la clave de acceso de nuestros usuarios sin que esta sea reconocible para el personal técnico que manipula la tabla de datos de control de acceso a un sitio Web.
Este método bidireccional tiene una ventaja, y es que el usuario puede recuperar su clave de acceso. En el caso de los métodos unidireccionales, el usuario nunca puede recuperar su clave de acceso.
No poder recuperar la clave de acceso le da a las compañías la seguridad de que la clave solo la puede conocer el usuario, nadie, tan siquiera el personal técnico puede saber que clave se esconde tras un valor criptografiado. Esto tiene un valor legal para las compañías tecnológicas de tremenda importancia, dado que las exime de responsabilidad penal ante las posibles violaciones a la privacidad.
Como no se puede recuperar la clave, cuando un usuario la pierde, solo tiene una opción, introducir una nueva. Esto genera un problema para el usuario cuando esta identificado en varios dispositivos, y es que al cambiar la clave deja de estar identificado en los demás dispositivos, con lo que más de una vez (a mí me ha pasado), al tratar de identificarte en un nuevo dispositivo, si no recuerdas la última clave guardada, vuelves a tener que introducir otra nueva, y vuelta a empezar con la identificación en los demás dispositivos.
Con esto, queremos poner de manifiesto que la decisión de tener un sitio Web con claves o password recuperables o no recuperables supone un compromiso para el propietario de un sitio Web. Siendo muy importante esta decisión, cada cual debe evaluar la importancia de la comodidad para el usuario o la garantía legal de protección de la privacidad.
Contextualizado el asunto criptográfico y de codificación, vamos ya directos al tema sobre cómo materializar esto en PHP.
PHP tiene un buen número de opciones a la hora de criptografiar valores en código hexadecimal, una de las mas usadas es la función md5(), que toma la siguiente forma:
Esta función siempre devolverá un conjunto de 32 caracteres hexadecimales (recordemos que son: 1234567890abcdef). En este caso:<?php // Encriptacion hexadecimal con md5() $clave = 'abc123'; $clave_criptog = md5($clave); echo "<p>$clave_criptog</p>"; ?>
Para abc123 devuelve e99a18c428cb38d5f260853678922e03
Pero, como hemos dicho PHP no solo tiene la función md5(), que aplica el algoritmo criptográfico del mismo nombre “md5”, tiene otros muchos algoritmos, a los que podemos acceder mediante la función hash_algos(), que pueden ser mas o menos (algoritmos) según que versión de PHP tengas instalada. Para acceder a nuestros algoritmos criptográficos podemos usar la siguiente sintaxis que nos los devuelve en un array el conjunto del algoritmos criptográficos disponibles en nuestro servidor:
Una vez seleccionado el algoritmo que deseamos usar, lo aplicaremos mediante la función hash() que recibe dos parámetros: el nombre del algoritmo y el valor a criptografiar:<?php // Algoritmos criptograficos disponibles $algoritmos_criptograficos = hash_algos(); echo '<pre>'; print_r($algoritmos_criptograficos); echo '</pre>'; ?>
El algoritmo “crc32b” devuelve una cadena hexadecimal de 8 caracteres, por lo que este algoritmo podría ser perfectamente útil, sin ocupar demasiado espacio, para almacenar valores como PIN de tarjetas de crédito. En este caso, la función devolverá “124ab51f”.<?php // Encriptado mediante el algoritmo “crc32b” $pin = '5734'; $encriptado = hash('crc32b', $pin); echo "<p>$encriptado</p>"; ?>
Mediante un bucle foreach podemos aplicar todos estos algoritmos a un mismo password y ver el resultado que obtenemos, el código sería el siguiente:
Que para que se haga una idea general de los resultados, nos devolvería lo siguiente (con versión PHP 7.3.31):<?php // Algoritmos criptograficos disponibles aplicados // a un mismo password o clave $password = 'abc123'; $algoritmos_criptograficos = hash_algos(); foreach($algoritmos_criptograficos as $key => $algoritmos){ $criptograficos[$key] = "(Key $key) ".hash($algoritmos, $password).' -- '. '<b>'.strlen(hash($algoritmos, $password)).'</b>'.' CARACTERES'; } $criptografia_caracteres = array_combine($algoritmos_criptograficos, $criptograficos); echo "<p>Resultado de encryptar <b>$password</b> con cada uno de los algoritmos.</p>"; echo '<pre>'; print_r($criptografia_caracteres); echo '</pre>'; ?>
Como hemos dicho, la respuesta, según la versión de PHP puede ser diferente, por lo tanto, ejecuta este código en tu servidor, y si es una versión posterior al probado aquí, es posible que el número de algoritmos sea superior (52 en nuestro caso). Si es más antigua la versión de PHP, es posible que el número de algoritmos sea inferior.Resultado de encriptar abc123 con cada uno de los algoritmos.
Array ( [md2] => (Key 0) e2cc4f546930ce0fcbce1246159cdb79 -- 32 CARACTERES [md4] => (Key 1) 0ceb1fd260c35bd50005341532748de6 -- 32 CARACTERES [md5] => (Key 2) e99a18c428cb38d5f260853678922e03 -- 32 CARACTERES [sha1] => (Key 3) 6367c48dd193d56ea7b0baad25b19455e529f5ee -- 40 CARACTERES [sha224] => (Key 4) 5c69bb695cc29b93d655e1a4bb5656cda624080d686f74477ea09349 -- 56 CARACTERES [sha256] => (Key 5) 6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090 -- 64 CARACTERES [sha384] => (Key 6) a31d79891919cad24f3264479d76884f581bee32e86778373db3a124de975dd86a40fc7f399b331133b281ab4b11a6ca -- 96 CARACTERES [sha512/224] => (Key 7) 0e1291aaab61cfc25495d7d56b944b41b0c84530b0ddc21e0c57d1fa -- 56 CARACTERES [sha512/256] => (Key 8) 8f085c893e15d8e56065f47bb5c98b12f57cef3866ab3569eefd326ed65080c1 -- 64 CARACTERES [sha512] => (Key 9) c70b5dd9ebfb6f51d09d4132b7170c9d20750a7852f00680f65658f0310e810056e6763c34c9a00b0e940076f54495c169fc2302cceb312039271c43469507dc -- 128 CARACTERES [sha3-224] => (Key 10) 026727ec105a060b02a0086a2181748f6b9ac3cea3fc347ca8675984 -- 56 CARACTERES [sha3-256] => (Key 11) f58fa3df820114f56e1544354379820cff464c9c41cb3ca0ad0b0843c9bb67ee -- 64 CARACTERES [sha3-384] => (Key 12) e07300227b15a724fdf6555569e38282022d106d778aa2268898dc21639b24e1e00fcc0a6d96ffc8b3a97c7fa7296305 -- 96 CARACTERES [sha3-512] => (Key 13) 3274f8455be84b8c7d79f9bd93e6c8520d13f6bd2855f3bb9c006ca9f3cce25d4b924d0370f8af4e27a350fd2baeef58bc37e0f4e4a403fe64c98017fa012757 -- 128 CARACTERES [ripemd128] => (Key 14) 029deb807ad1843954390e990e4f06ed -- 32 CARACTERES [ripemd160] => (Key 15) 949fa2fb25f40430c10dfbaf4cdcd403e1692ffb -- 40 CARACTERES [ripemd256] => (Key 16) ae573d5cf8829ea13ff71d797895d580bae77401c1d91d6bdd489f5f1e3620d6 -- 64 CARACTERES [ripemd320] => (Key 17) 853fb3c290346e14b009d6bfd1d2c28ca30cae71c8662a477b5bf8ec94805858d9fccd109754a5e7 -- 80 CARACTERES [whirlpool] => (Key 18) f9c3b1a3b54075cc8d53e8cb032560299d4b3a7b2aa38ff69bfc8170290cdf077988aece1f2c69685d5a9f6a1c8e68ac9b2dd2e7130df96af5199635bb580911 -- 128 CARACTERES [tiger128,3] => (Key 19) 46136f95bc750579b8ad08e232ff684d -- 32 CARACTERES [tiger160,3] => (Key 20) 46136f95bc750579b8ad08e232ff684dc8971d06 -- 40 CARACTERES [tiger192,3] => (Key 21) 46136f95bc750579b8ad08e232ff684dc8971d06289c514a -- 48 CARACTERES [tiger128,4] => (Key 22) f26889c19a459692a3b77736170e3820 -- 32 CARACTERES [tiger160,4] => (Key 23) f26889c19a459692a3b77736170e3820a2954e8b -- 40 CARACTERES [tiger192,4] => (Key 24) f26889c19a459692a3b77736170e3820a2954e8bbf4c6e99 -- 48 CARACTERES [snefru] => (Key 25) 780d123c68339a047ac9b4dd2ff8a91da99175fea72898b683e24661c85abfc6 -- 64 CARACTERES [snefru256] => (Key 26) 780d123c68339a047ac9b4dd2ff8a91da99175fea72898b683e24661c85abfc6 -- 64 CARACTERES [gost] => (Key 27) e7306add6edb7bc143f2cc40e665e22230b97d521fe6a4c18dc46d7fce69be2e -- 64 CARACTERES [gost-crypto] => (Key 28) 5808033a198fa0d8c5f4313749c04215480a0837e582aa3192fd49f3f951460c -- 64 CARACTERES [adler32] => (Key 29) 06ec01bd -- 8 CARACTERES [crc32] => (Key 30) dbf164c4 -- 8 CARACTERES [crc32b] => (Key 31) cf02bb5c -- 8 CARACTERES [fnv132] => (Key 32) d75a6225 -- 8 CARACTERES [fnv1a32] => (Key 33) 38b29a05 -- 8 CARACTERES [fnv164] => (Key 34) 249458653a685a85 -- 16 CARACTERES [fnv1a64] => (Key 35) 62cca2412f0aff65 -- 16 CARACTERES [joaat] => (Key 36) 599f3312 -- 8 CARACTERES [haval128,3] => (Key 37) ce969d5be89d55354fbd8c32c2f75227 -- 32 CARACTERES [haval160,3] => (Key 38) 9ba577c6c5247593add242a96c8d19cb38c071c9 -- 40 CARACTERES [haval192,3] => (Key 39) 8e8d4b03150e0d214f270184b1165bcf0e3cb966af70504a -- 48 CARACTERES [haval224,3] => (Key 40) 5f225849cabaca3fae610956e62eaf1202cefe4dd34a58d450386401 -- 56 CARACTERES [haval256,3] => (Key 41) 05aeda6c51b51aaf24a5ee757efd5e36391be24dbc255a03640067b5fa882404 -- 64 CARACTERES [haval128,4] => (Key 42) c462b6cf1274ad3f36ac0e9780773f35 -- 32 CARACTERES [haval160,4] => (Key 43) 2e2c5d96dc61f6a41fb102f62e1577a5b6d53912 -- 40 CARACTERES [haval192,4] => (Key 44) 096a9581e077b9d85688a5d8cae55d067a3151e2e0222176 -- 48 CARACTERES [haval224,4] => (Key 45) e6755e2606c19ed7921e637d3a98ef9d9e9db2f0eee8e14ed7654cef -- 56 CARACTERES [haval256,4] => (Key 46) 7f1c1fc99d93d52d7dcce283f2e69f4b20b16886b930c74cc60b48f28396d667 -- 64 CARACTERES [haval128,5] => (Key 47) 62badfd149edd203ba5decede96f1ded -- 32 CARACTERES [haval160,5] => (Key 48) 27c053e97ce6f043e9e801f38bc6670deb9c0022 -- 40 CARACTERES [haval192,5] => (Key 49) f1ce4f36374e785c5de82356c51d01fd2a00bfd618f03619 -- 48 CARACTERES [haval224,5] => (Key 50) d2edfac690dad8e6f4527871bb84a797e539275535d2bab55a77d3b6 -- 56 CARACTERES [haval256,5] => (Key 51) 383a277ceef51c8a254b51a4d51eb25d0be81ac381e3f7ec5ae1bba640f3bbc5 -- 64 CARACTERES )
Respecto a la función hash() que aplica algoritmos, indicar que PHP tiene funciones especificas para aplicar un cierto algoritmo, como son la md5(), sha1, crc32, y sha256. En estas funciones se ha encontrado una discrepancia entre los valores aportados por la función y el valor aportado por hash() para ese algoritmo. Estos temas aparecen comentados en ingles en la página oficial.
Cabe comentar que se puede pensar que todas las criptografías en hexadecimal son unidireccionales, lo cual no es cierto, se puede codificar en hexadecimal de forma bidireccional, como puede verse en las funciones aquí expuestas. Que una codificación sea o no de doble sentido no esta vinculado al código de transformación (hexadecimal en este caso), está vinculado a la ecuación o regla de transformación.
Por último, y como comentamos en el resumen, no solo se puede codificar una cadena o string, también podemos codificar archivos. Sin entrar en muchas pretensiones vamos a presentar la función md5_file().
Esta función nos puede resultar muy útil, por ejemplo, para identificar si una determinada imagen se ha subido ya a nuestro servidor. Eso sí, la imagen debe ser idéntica, con que le falte una simple fila de píxeles o cambie el brillo o saturación, ya generaría un valor hexadecimal diferente.<?php // Codifica archivo en md5 $file = 'https://www.artesaniaweb.es/fotos/mitos_de_internet_la_deep_web-i3u30/artesaniaweb_1545954658A.jpg'; $codifica_file = md5_file($file); echo "Archivo: $file <br /> Codificado en MD5: <b>$codifica_file</b>"; ?>
Dicho esto, cerramos este artículo, un poco complejo, pero espero que os haya resultado interesante.
Tags: Criptografía || hash || seguridad || codificación || encriptación